305 lines
8.8 KiB
Go
Raw Normal View History

2025-10-07 11:10:08 +07:00
package wallet
import (
2025-11-04 10:38:31 +07:00
"fmt"
2025-10-07 11:10:08 +07:00
"github.com/btcsuite/btcd/btcutil/base58"
"github.com/phamminh0811/private-grpc/crypto"
"github.com/phamminh0811/private-grpc/nockchain"
)
func ParseBalanceEntry(entry *nockchain.BalanceEntry) nockchain.NockchainNote {
2025-11-04 10:38:31 +07:00
switch entry.Note.NoteVersion.(type) {
case *nockchain.Note_Legacy:
note := entry.Note.GetLegacy()
version := nockchain.Version(note.Version.Value)
pubkeys := []string{}
for _, pk := range note.Lock.SchnorrPubkeys {
pkPoint := crypto.CheetahPoint{
X: [6]crypto.Belt{
{Value: pk.Value.X.Belt_1.Value},
{Value: pk.Value.X.Belt_2.Value},
{Value: pk.Value.X.Belt_3.Value},
{Value: pk.Value.X.Belt_4.Value},
{Value: pk.Value.X.Belt_5.Value},
{Value: pk.Value.X.Belt_6.Value},
},
Y: [6]crypto.Belt{
{Value: pk.Value.Y.Belt_1.Value},
{Value: pk.Value.Y.Belt_2.Value},
{Value: pk.Value.Y.Belt_3.Value},
{Value: pk.Value.Y.Belt_4.Value},
{Value: pk.Value.Y.Belt_5.Value},
{Value: pk.Value.Y.Belt_6.Value},
},
Inf: pk.Value.Inf,
}
pkStr := base58.Encode(pkPoint.Bytes())
pubkeys = append(pubkeys, pkStr)
}
sourceHash := [5]uint64{
note.Source.Hash.Belt_1.Value,
note.Source.Hash.Belt_2.Value,
note.Source.Hash.Belt_3.Value,
note.Source.Hash.Belt_4.Value,
note.Source.Hash.Belt_5.Value,
}
return nockchain.NockchainNote{
Note: &nockchain.NockchainNote_V0{
V0: &nockchain.NockchainNoteV0{
Version: version,
OriginPage: note.OriginPage.Value,
Name: &nockchain.NockchainName{
First: crypto.Tip5HashToBase58([5]uint64{
entry.Name.First.Belt_1.Value,
entry.Name.First.Belt_2.Value,
entry.Name.First.Belt_3.Value,
entry.Name.First.Belt_4.Value,
entry.Name.First.Belt_5.Value,
}),
Last: crypto.Tip5HashToBase58([5]uint64{
entry.Name.Last.Belt_1.Value,
entry.Name.Last.Belt_2.Value,
entry.Name.Last.Belt_3.Value,
entry.Name.Last.Belt_4.Value,
entry.Name.Last.Belt_5.Value,
}),
},
Lock: &nockchain.NockchainLock{
KeysRequired: uint64(note.Lock.KeysRequired),
Pubkeys: pubkeys,
},
Source: &nockchain.NockchainSource{
Source: crypto.Tip5HashToBase58(sourceHash),
IsCoinbase: note.Source.Coinbase,
},
Asset: note.Assets.Value,
},
2025-10-07 11:10:08 +07:00
},
}
2025-11-04 10:38:31 +07:00
case *nockchain.Note_V1:
fmt.Println("go here???")
// Handle V1 notes if needed
return nockchain.NockchainNote{
Note: &nockchain.NockchainNote_V1{
V1: &nockchain.NockchainNoteV1{},
},
2025-10-07 11:10:08 +07:00
}
2025-11-04 10:38:31 +07:00
default:
return nockchain.NockchainNote{}
2025-10-07 11:10:08 +07:00
}
}
2025-11-04 10:38:31 +07:00
func ConvertNamedSpend(spend *nockchain.NockchainNamedSpend) (*nockchain.SpendEntry, error) {
convertedSpend := &nockchain.Spend{}
switch spend.SpendKind.(type) {
case *nockchain.NockchainNamedSpend_Legacy:
legacySpend := spend.GetLegacy()
signature, err := ConvertSignatures(legacySpend.Signatures)
2025-10-07 11:10:08 +07:00
if err != nil {
return nil, err
}
2025-11-04 10:38:31 +07:00
seeds := []*nockchain.Seed{}
for _, seed := range legacySpend.Seeds {
seeds = append(seeds, &nockchain.Seed{
OutputSource: &nockchain.Source{
2025-10-07 11:10:08 +07:00
Hash: ParseHash(seed.OutputSource.Source),
2025-11-04 10:38:31 +07:00
Coinbase: seed.OutputSource.IsCoinbase,
2025-10-07 11:10:08 +07:00
},
2025-11-04 10:38:31 +07:00
LockRoot: ParseHash(seed.LockRoot),
NoteData: &nockchain.NoteData{
Entries: []*nockchain.NoteDataEntry{
{
Key: "lock",
Blob: EncodeNoteData(seed.NoteData),
},
},
},
Gift: &nockchain.Nicks{
Value: seed.Gift,
},
ParentHash: ParseHash(seed.ParentHash),
})
2025-10-07 22:24:54 +07:00
}
2025-11-04 10:38:31 +07:00
convertedSpend = &nockchain.Spend{
SpendKind: &nockchain.Spend_Legacy{
Legacy: &nockchain.LegacySpend{
Signature: signature,
Seeds: seeds,
MinerFeeNicks: &nockchain.Nicks{
Value: legacySpend.Fee,
},
},
2025-10-07 11:10:08 +07:00
},
2025-11-04 10:38:31 +07:00
}
case *nockchain.NockchainNamedSpend_Witness:
// TODO: handle v1
2025-10-07 11:10:08 +07:00
}
2025-11-04 10:38:31 +07:00
// Conversion logic here
return &nockchain.SpendEntry{
Name: ConvertName(spend.Name),
Spend: convertedSpend,
}, nil
}
2025-10-07 11:10:08 +07:00
2025-11-04 10:38:31 +07:00
func ConvertSignatures(signatures []*nockchain.NockchainSignature) (*nockchain.Signature, error) {
entries := make([]*nockchain.SignatureEntry, len(signatures))
for i, sig := range signatures {
pubkey, err := ParseSchnorrPubkey(sig.Pubkey)
2025-10-07 11:10:08 +07:00
if err != nil {
return nil, err
}
2025-11-04 10:38:31 +07:00
entries[i] = &nockchain.SignatureEntry{
SchnorrPubkey: pubkey,
2025-10-07 11:10:08 +07:00
Signature: &nockchain.SchnorrSignature{
Chal: ParseEightBelt(sig.Chal),
Sig: ParseEightBelt(sig.Sig),
},
2025-11-04 10:38:31 +07:00
}
2025-10-07 11:10:08 +07:00
}
2025-11-04 10:38:31 +07:00
return &nockchain.Signature{
Entries: entries,
2025-10-07 11:10:08 +07:00
}, nil
}
func ConvertName(name *nockchain.NockchainName) *nockchain.Name {
return &nockchain.Name{
First: ParseHash(name.First),
Last: ParseHash(name.Last),
}
}
func ConvertTimelockIntent(timelock *nockchain.TimelockIntent) *nockchain.TimeLockIntent {
if timelock == nil {
return nil
}
if timelock.Absolute != nil && timelock.Relative != nil {
return &nockchain.TimeLockIntent{
Value: &nockchain.TimeLockIntent_AbsoluteAndRelative{
AbsoluteAndRelative: &nockchain.TimeLockRangeAbsoluteAndRelative{
Absolute: &nockchain.TimeLockRangeAbsolute{
Min: (*nockchain.BlockHeight)(timelock.Absolute.Min),
Max: (*nockchain.BlockHeight)(timelock.Absolute.Max),
},
Relative: &nockchain.TimeLockRangeRelative{
Min: (*nockchain.BlockHeightDelta)(timelock.Relative.Min),
Max: (*nockchain.BlockHeightDelta)(timelock.Relative.Max),
},
},
},
}
}
if timelock.Absolute != nil {
return &nockchain.TimeLockIntent{
Value: &nockchain.TimeLockIntent_Absolute{
Absolute: &nockchain.TimeLockRangeAbsolute{
Min: (*nockchain.BlockHeight)(timelock.Absolute.Min),
Max: (*nockchain.BlockHeight)(timelock.Absolute.Max),
},
},
}
}
if timelock.Relative != nil {
return &nockchain.TimeLockIntent{
Value: &nockchain.TimeLockIntent_Relative{
Relative: &nockchain.TimeLockRangeRelative{
Min: (*nockchain.BlockHeightDelta)(timelock.Relative.Min),
Max: (*nockchain.BlockHeightDelta)(timelock.Relative.Max),
},
},
}
}
return nil
}
func ParseHash(hash string) *nockchain.Hash {
hashTip5 := crypto.Base58ToTip5Hash(hash)
return &nockchain.Hash{
Belt_1: &nockchain.Belt{Value: hashTip5[0]},
Belt_2: &nockchain.Belt{Value: hashTip5[1]},
Belt_3: &nockchain.Belt{Value: hashTip5[2]},
Belt_4: &nockchain.Belt{Value: hashTip5[3]},
Belt_5: &nockchain.Belt{Value: hashTip5[4]},
}
}
func ParseEightBelt(data []uint64) *nockchain.EightBelt {
return &nockchain.EightBelt{
Belt_1: &nockchain.Belt{Value: data[0]},
Belt_2: &nockchain.Belt{Value: data[1]},
Belt_3: &nockchain.Belt{Value: data[2]},
Belt_4: &nockchain.Belt{Value: data[3]},
Belt_5: &nockchain.Belt{Value: data[4]},
Belt_6: &nockchain.Belt{Value: data[5]},
Belt_7: &nockchain.Belt{Value: data[6]},
Belt_8: &nockchain.Belt{Value: data[7]},
}
}
func ParseSchnorrPubkey(key string) (*nockchain.SchnorrPubkey, error) {
pk, err := crypto.CheetaPointFromBytes(base58.Decode(key))
if err != nil {
return nil, err
}
return &nockchain.SchnorrPubkey{
Value: &nockchain.CheetahPoint{
X: &nockchain.SixBelt{
Belt_1: &nockchain.Belt{Value: pk.X[0].Value},
Belt_2: &nockchain.Belt{Value: pk.X[1].Value},
Belt_3: &nockchain.Belt{Value: pk.X[2].Value},
Belt_4: &nockchain.Belt{Value: pk.X[3].Value},
Belt_5: &nockchain.Belt{Value: pk.X[4].Value},
Belt_6: &nockchain.Belt{Value: pk.X[5].Value},
},
Y: &nockchain.SixBelt{
Belt_1: &nockchain.Belt{Value: pk.Y[0].Value},
Belt_2: &nockchain.Belt{Value: pk.Y[1].Value},
Belt_3: &nockchain.Belt{Value: pk.Y[2].Value},
Belt_4: &nockchain.Belt{Value: pk.Y[3].Value},
Belt_5: &nockchain.Belt{Value: pk.Y[4].Value},
Belt_6: &nockchain.Belt{Value: pk.Y[5].Value},
},
Inf: pk.Inf,
},
}, nil
}
func ParseTimelockIntent(timelock *nockchain.TimeLockIntent) *nockchain.TimelockIntent {
if timelock == nil {
return nil
}
switch timelock.Value.(type) {
case *nockchain.TimeLockIntent_Absolute:
return &nockchain.TimelockIntent{
Absolute: &nockchain.TimelockRange{
Min: (*nockchain.Timelock)(timelock.GetAbsolute().Min),
Max: (*nockchain.Timelock)(timelock.GetAbsolute().Max),
},
Relative: nil,
}
case *nockchain.TimeLockIntent_Relative:
return &nockchain.TimelockIntent{
Absolute: nil,
Relative: &nockchain.TimelockRange{
Min: (*nockchain.Timelock)(timelock.GetRelative().Min),
Max: (*nockchain.Timelock)(timelock.GetRelative().Max),
},
}
case *nockchain.TimeLockIntent_AbsoluteAndRelative:
return &nockchain.TimelockIntent{
Absolute: &nockchain.TimelockRange{
Min: (*nockchain.Timelock)(timelock.GetAbsoluteAndRelative().Absolute.Min),
Max: (*nockchain.Timelock)(timelock.GetAbsoluteAndRelative().Absolute.Max),
},
Relative: &nockchain.TimelockRange{
Min: (*nockchain.Timelock)(timelock.GetAbsoluteAndRelative().Relative.Min),
Max: (*nockchain.Timelock)(timelock.GetAbsoluteAndRelative().Relative.Max),
},
}
default:
return nil
}
}