package wallet import ( "fmt" "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 { 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, }, }, } case *nockchain.Note_V1: fmt.Println("go here???") // Handle V1 notes if needed return nockchain.NockchainNote{ Note: &nockchain.NockchainNote_V1{ V1: &nockchain.NockchainNoteV1{}, }, } default: return nockchain.NockchainNote{} } } 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) if err != nil { return nil, err } seeds := []*nockchain.Seed{} for _, seed := range legacySpend.Seeds { seeds = append(seeds, &nockchain.Seed{ OutputSource: &nockchain.Source{ Hash: ParseHash(seed.OutputSource.Source), Coinbase: seed.OutputSource.IsCoinbase, }, 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), }) } convertedSpend = &nockchain.Spend{ SpendKind: &nockchain.Spend_Legacy{ Legacy: &nockchain.LegacySpend{ Signature: signature, Seeds: seeds, MinerFeeNicks: &nockchain.Nicks{ Value: legacySpend.Fee, }, }, }, } case *nockchain.NockchainNamedSpend_Witness: // TODO: handle v1 } // Conversion logic here return &nockchain.SpendEntry{ Name: ConvertName(spend.Name), Spend: convertedSpend, }, nil } func ConvertSignatures(signatures []*nockchain.NockchainSignature) (*nockchain.Signature, error) { entries := make([]*nockchain.SignatureEntry, len(signatures)) for i, sig := range signatures { pubkey, err := ParseSchnorrPubkey(sig.Pubkey) if err != nil { return nil, err } entries[i] = &nockchain.SignatureEntry{ SchnorrPubkey: pubkey, Signature: &nockchain.SchnorrSignature{ Chal: ParseEightBelt(sig.Chal), Sig: ParseEightBelt(sig.Sig), }, } } return &nockchain.Signature{ Entries: entries, }, 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 } }