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 { version := nockchain.Version(entry.Note.Version.Value) pubkeys := []string{} for _, pk := range entry.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{ entry.Note.Source.Hash.Belt_1.Value, entry.Note.Source.Hash.Belt_2.Value, entry.Note.Source.Hash.Belt_3.Value, entry.Note.Source.Hash.Belt_4.Value, entry.Note.Source.Hash.Belt_5.Value, } return nockchain.NockchainNote{ Version: version, BlockHeight: entry.Note.OriginPage.Value, Timelock: ParseTimelockIntent(entry.Note.Timelock), 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(entry.Note.Lock.KeysRequired), Pubkeys: pubkeys, }, Source: &nockchain.NockchainSource{ Source: crypto.Tip5HashToBase58(sourceHash), IsCoinbase: true, }, Asset: entry.Note.Assets.Value, } } func ConvertRawTx(rawTx *nockchain.RawTx) nockchain.RawTransaction { id := crypto.Base58ToTip5Hash(rawTx.TxId) var timelockRange *nockchain.TimeLockRangeAbsolute if rawTx.TimelockRange != nil { timelockRange = &nockchain.TimeLockRangeAbsolute{ Min: (*nockchain.BlockHeight)(rawTx.TimelockRange.Min), Max: (*nockchain.BlockHeight)(rawTx.TimelockRange.Max), } } return nockchain.RawTransaction{ Id: &nockchain.Hash{ Belt_1: &nockchain.Belt{Value: id[0]}, Belt_2: &nockchain.Belt{Value: id[1]}, Belt_3: &nockchain.Belt{Value: id[2]}, Belt_4: &nockchain.Belt{Value: id[3]}, Belt_5: &nockchain.Belt{Value: id[4]}, }, TimelockRange: timelockRange, TotalFees: &nockchain.Nicks{ Value: rawTx.TotalFees, }, } } func ConvertInput(input *nockchain.NockchainInput) (*nockchain.NamedInput, error) { pks := []*nockchain.SchnorrPubkey{} for _, i := range input.Note.Lock.Pubkeys { pk, err := ParseSchnorrPubkey(i) if err != nil { return nil, err } pks = append(pks, pk) } seeds := []*nockchain.Seed{} for _, seed := range input.Spend.Seeds { seedPks := []*nockchain.SchnorrPubkey{} for _, i := range input.Note.Lock.Pubkeys { pk, err := ParseSchnorrPubkey(i) if err != nil { return nil, err } pks = append(seedPks, pk) } var source *nockchain.OutputSource if seed.OutputSource != nil { source = &nockchain.OutputSource{ Source: &nockchain.Source{ Hash: ParseHash(seed.OutputSource.Source), Coinbase: input.Note.Source.IsCoinbase, }, } } seeds = append(seeds, &nockchain.Seed{ OutputSource: source, Recipient: &nockchain.Lock{ KeysRequired: uint32(seed.Recipient.KeysRequired), SchnorrPubkeys: seedPks, }, TimelockIntent: ConvertTimelockIntent(seed.TimelockIntent), Gift: &nockchain.Nicks{Value: seed.Gift}, ParentHash: ParseHash(seed.ParentHash), }) } sigEntries := []*nockchain.SignatureEntry{} for _, sig := range input.Spend.Signatures { pk, err := ParseSchnorrPubkey(sig.Pubkey) if err != nil { return nil, err } sigEntries = append(sigEntries, &nockchain.SignatureEntry{ SchnorrPubkey: pk, Signature: &nockchain.SchnorrSignature{ Chal: ParseEightBelt(sig.Chal), Sig: ParseEightBelt(sig.Sig), }, }) } return &nockchain.NamedInput{ Name: ConvertName(input.Name), Input: &nockchain.Input{ Note: &nockchain.Note{ OriginPage: &nockchain.BlockHeight{ Value: input.Note.BlockHeight, }, Timelock: ConvertTimelockIntent(input.Note.Timelock), Name: ConvertName(input.Name), Lock: &nockchain.Lock{ KeysRequired: uint32(input.Note.Lock.KeysRequired), SchnorrPubkeys: pks, }, Source: &nockchain.Source{ Hash: ParseHash(input.Note.Source.Source), Coinbase: input.Note.Source.IsCoinbase, }, Assets: &nockchain.Nicks{Value: input.Note.Asset}, Version: &nockchain.NoteVersion{Value: uint32(input.Note.Version)}, }, Spend: &nockchain.Spend{ Signature: &nockchain.Signature{ Entries: sigEntries, }, Seeds: seeds, MinerFeeNicks: &nockchain.Nicks{Value: input.Spend.Fee}, }, }, }, 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 } }