package wallet import ( "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 { 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, }), } 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: name, 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: note := entry.Note.GetV1() version := nockchain.Version(note.Version.Value) if len(note.NoteData.Entries) != 1 || note.NoteData.Entries[0].Key != "lock" { panic("invalid note data") } lock := DecodeNoteData(note.NoteData.Entries[0].Blob) return nockchain.NockchainNote{ Note: &nockchain.NockchainNote_V1{ V1: &nockchain.NockchainNoteV1{ Version: version, OriginPage: note.OriginPage.Value, Name: name, NoteData: lock, Assets: note.Assets.Value, }, }, } 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: witnessSpend := spend.GetWitness() seeds := []*nockchain.Seed{} for _, seed := range witnessSpend.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), }) } witness := witnessSpend.Witness[0] lockHashes := []*nockchain.Hash{} for i := 0; i < len(witness.Lmp.SpendCondition.Pubkeys); i++ { lockHashes = append(lockHashes, ParseHash(witness.Lmp.SpendCondition.Pubkeys[i])) } pkhSigs := []*nockchain.PkhSignatureEntry{} for _, pkh := range witness.Pkh { pk, err := crypto.CheetaPointFromBytes(base58.Decode(pkh.Pubkey)) if err != nil { return nil, err } schnorrPk, err := ParseSchnorrPubkey(pkh.Pubkey) if err != nil { return nil, err } pkHash := HashPubkey(pk) pkhSigs = append(pkhSigs, &nockchain.PkhSignatureEntry{ Hash: ParseHash(crypto.Tip5HashToBase58(pkHash)), Pubkey: schnorrPk, Signature: &nockchain.SchnorrSignature{ Chal: ParseEightBelt(pkh.Chal), Sig: ParseEightBelt(pkh.Sig), }, }) } convertedSpend = &nockchain.Spend{ SpendKind: &nockchain.Spend_Witness{ Witness: &nockchain.WitnessSpend{ Witness: &nockchain.Witness{ LockMerkleProof: &nockchain.LockMerkleProof{ SpendCondition: &nockchain.SpendCondition{ Primitives: []*nockchain.LockPrimitive{ { Primitive: &nockchain.LockPrimitive_Pkh{ Pkh: &nockchain.PkhLock{ M: witness.Lmp.SpendCondition.KeysRequired, Hashes: lockHashes, }, }, }, }, }, Axis: witness.Lmp.Axis, Proof: &nockchain.MerkleProof{ Root: ParseHash(witness.Lmp.MerkleRoot), Path: []*nockchain.Hash{}, }, }, PkhSignature: &nockchain.PkhSignature{ Entries: pkhSigs, }, }, Seeds: seeds, Fee: &nockchain.Nicks{ Value: witnessSpend.Fee, }, }, }, } } // 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 } }