diff --git a/indexer/examples/x-chain-blocks/main.go b/indexer/examples/x-chain-blocks/main.go index 226460720fc5..c118a7ad378b 100644 --- a/indexer/examples/x-chain-blocks/main.go +++ b/indexer/examples/x-chain-blocks/main.go @@ -10,7 +10,7 @@ import ( "github.com/ava-labs/avalanchego/indexer" "github.com/ava-labs/avalanchego/vms/proposervm/block" - "github.com/ava-labs/avalanchego/wallet/chain/x" + "github.com/ava-labs/avalanchego/wallet/chain/x/builder" "github.com/ava-labs/avalanchego/wallet/subnet/primary" ) @@ -37,7 +37,7 @@ func main() { } avmBlockBytes := proposerVMBlock.Block() - avmBlock, err := x.Parser.ParseBlock(avmBlockBytes) + avmBlock, err := builder.Parser.ParseBlock(avmBlockBytes) if err != nil { log.Fatalf("failed to parse avm block: %s\n", err) } diff --git a/tests/antithesis/main.go b/tests/antithesis/main.go index d33a8808e0f4..5d7d614f75c5 100644 --- a/tests/antithesis/main.go +++ b/tests/antithesis/main.go @@ -27,12 +27,12 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/status" "github.com/ava-labs/avalanchego/vms/propertyfx" "github.com/ava-labs/avalanchego/vms/secp256k1fx" - "github.com/ava-labs/avalanchego/wallet/chain/x" "github.com/ava-labs/avalanchego/wallet/subnet/primary" "github.com/ava-labs/avalanchego/wallet/subnet/primary/common" xtxs "github.com/ava-labs/avalanchego/vms/avm/txs" ptxs "github.com/ava-labs/avalanchego/vms/platformvm/txs" + xbuilder "github.com/ava-labs/avalanchego/wallet/chain/x/builder" ) const NumKeys = 5 @@ -69,8 +69,10 @@ func main() { workloads[0] = genesisWorkload var ( - genesisXWallet = wallet.X() - avaxAssetID = genesisXWallet.AVAXAssetID() + genesisXWallet = wallet.X() + genesisXBuilder = genesisXWallet.Builder() + genesisXContext = genesisXBuilder.Context() + avaxAssetID = genesisXContext.AVAXAssetID ) for i := 1; i < NumKeys; i++ { key, err := secp256k1.NewPrivateKey() @@ -192,7 +194,8 @@ func (w *workload) run(ctx context.Context) { log.Fatalf("failed to fetch P-chain balances: %s", err) } var ( - avaxAssetID = xWallet.AVAXAssetID() + xContext = xBuilder.Context() + avaxAssetID = xContext.AVAXAssetID xAVAX = xBalances[avaxAssetID] pAVAX = pBalances[avaxAssetID] ) @@ -245,9 +248,10 @@ func (w *workload) issueXChainBaseTx(ctx context.Context) { } var ( - avaxAssetID = xWallet.AVAXAssetID() + xContext = xBuilder.Context() + avaxAssetID = xContext.AVAXAssetID avaxBalance = balances[avaxAssetID] - baseTxFee = xWallet.BaseTxFee() + baseTxFee = xContext.BaseTxFee neededBalance = baseTxFee + units.Schmeckle ) if avaxBalance < neededBalance { @@ -294,9 +298,10 @@ func (w *workload) issueXChainCreateAssetTx(ctx context.Context) { } var ( - avaxAssetID = xWallet.AVAXAssetID() + xContext = xBuilder.Context() + avaxAssetID = xContext.AVAXAssetID avaxBalance = balances[avaxAssetID] - neededBalance = xWallet.CreateAssetTxFee() + neededBalance = xContext.CreateAssetTxFee ) if avaxBalance < neededBalance { log.Printf("skipping X-chain tx issuance due to insufficient balance: %d < %d", avaxBalance, neededBalance) @@ -342,10 +347,11 @@ func (w *workload) issueXChainOperationTx(ctx context.Context) { } var ( - avaxAssetID = xWallet.AVAXAssetID() + xContext = xBuilder.Context() + avaxAssetID = xContext.AVAXAssetID avaxBalance = balances[avaxAssetID] - createAssetTxFee = xWallet.CreateAssetTxFee() - baseTxFee = xWallet.BaseTxFee() + createAssetTxFee = xContext.CreateAssetTxFee + baseTxFee = xContext.BaseTxFee neededBalance = createAssetTxFee + baseTxFee ) if avaxBalance < neededBalance { @@ -405,9 +411,10 @@ func (w *workload) issueXToPTransfer(ctx context.Context) { } var ( - avaxAssetID = xWallet.AVAXAssetID() + xContext = xBuilder.Context() + avaxAssetID = xContext.AVAXAssetID avaxBalance = balances[avaxAssetID] - xBaseTxFee = xWallet.BaseTxFee() + xBaseTxFee = xContext.BaseTxFee pBuilder = pWallet.Builder() pContext = pBuilder.Context() pBaseTxFee = pContext.BaseTxFee @@ -441,7 +448,7 @@ func (w *workload) issueXToPTransfer(ctx context.Context) { log.Printf("created X-chain export transaction %s in %s", exportTx.ID(), time.Since(exportStartTime)) var ( - xChainID = xWallet.BlockchainID() + xChainID = xContext.BlockchainID importStartTime = time.Now() ) importTx, err := pWallet.IssueImportTx( @@ -464,6 +471,7 @@ func (w *workload) issuePToXTransfer(ctx context.Context) { var ( xWallet = w.wallet.X() pWallet = w.wallet.P() + xBuilder = xWallet.Builder() pBuilder = pWallet.Builder() ) balances, err := pBuilder.GetBalance() @@ -473,11 +481,12 @@ func (w *workload) issuePToXTransfer(ctx context.Context) { } var ( + xContext = xBuilder.Context() pContext = pBuilder.Context() avaxAssetID = pContext.AVAXAssetID avaxBalance = balances[avaxAssetID] pBaseTxFee = pContext.BaseTxFee - xBaseTxFee = xWallet.BaseTxFee() + xBaseTxFee = xContext.BaseTxFee txFees = pBaseTxFee + xBaseTxFee neededBalance = txFees + units.Schmeckle ) @@ -487,7 +496,7 @@ func (w *workload) issuePToXTransfer(ctx context.Context) { } var ( - xChainID = xWallet.BlockchainID() + xChainID = xContext.BlockchainID owner = w.makeOwner() exportStartTime = time.Now() ) @@ -573,7 +582,7 @@ func (w *workload) confirmPChainTx(ctx context.Context, tx *ptxs.Tx) { func (w *workload) verifyXChainTxConsumedUTXOs(ctx context.Context, tx *xtxs.Tx) { txID := tx.ID() - chainID := w.wallet.X().BlockchainID() + chainID := w.wallet.X().Builder().Context().BlockchainID for _, uri := range w.uris { client := avm.NewClient(uri, "X") @@ -582,7 +591,7 @@ func (w *workload) verifyXChainTxConsumedUTXOs(ctx context.Context, tx *xtxs.Tx) ctx, utxos, client, - x.Parser.Codec(), + xbuilder.Parser.Codec(), chainID, chainID, w.addrs.List(), diff --git a/tests/e2e/banff/suites.go b/tests/e2e/banff/suites.go index 7ac486b373fe..b6da324c98ea 100644 --- a/tests/e2e/banff/suites.go +++ b/tests/e2e/banff/suites.go @@ -30,9 +30,11 @@ var _ = ginkgo.Describe("[Banff]", func() { // Get the P-chain and the X-chain wallets pWallet := wallet.P() xWallet := wallet.X() + xBuilder := xWallet.Builder() + xContext := xBuilder.Context() // Pull out useful constants to use when issuing transactions. - xChainID := xWallet.BlockchainID() + xChainID := xContext.BlockchainID owner := &secp256k1fx.OutputOwners{ Threshold: 1, Addrs: []ids.ShortID{ diff --git a/tests/e2e/c/interchain_workflow.go b/tests/e2e/c/interchain_workflow.go index cf8437b751b8..f5afc4abe059 100644 --- a/tests/e2e/c/interchain_workflow.go +++ b/tests/e2e/c/interchain_workflow.go @@ -84,7 +84,9 @@ var _ = e2e.DescribeCChain("[Interchain Workflow]", func() { pWallet := baseWallet.P() ginkgo.By("defining common configuration") - avaxAssetID := xWallet.AVAXAssetID() + xBuilder := xWallet.Builder() + xContext := xBuilder.Context() + avaxAssetID := xContext.AVAXAssetID // Use the same owner for import funds to X-Chain and P-Chain recipientOwner := secp256k1fx.OutputOwners{ Threshold: 1, @@ -107,7 +109,7 @@ var _ = e2e.DescribeCChain("[Interchain Workflow]", func() { ginkgo.By("exporting AVAX from the C-Chain to the X-Chain", func() { _, err := cWallet.IssueExportTx( - xWallet.BlockchainID(), + xContext.BlockchainID, exportOutputs, e2e.WithDefaultContext(), e2e.WithSuggestedGasPrice(ethClient), diff --git a/tests/e2e/p/interchain_workflow.go b/tests/e2e/p/interchain_workflow.go index f45a1f8c6669..d27d080d9c00 100644 --- a/tests/e2e/p/interchain_workflow.go +++ b/tests/e2e/p/interchain_workflow.go @@ -56,12 +56,14 @@ var _ = e2e.DescribePChain("[Interchain Workflow]", ginkgo.Label(e2e.UsesCChainL cWallet := baseWallet.C() pWallet := baseWallet.P() + xBuilder := xWallet.Builder() + xContext := xBuilder.Context() pBuilder := pWallet.Builder() pContext := pBuilder.Context() ginkgo.By("defining common configuration") recipientEthAddress := evm.GetEthAddress(recipientKey) - avaxAssetID := xWallet.AVAXAssetID() + avaxAssetID := xContext.AVAXAssetID // Use the same owner for sending to X-Chain and importing funds to P-Chain recipientOwner := secp256k1fx.OutputOwners{ Threshold: 1, @@ -158,7 +160,7 @@ var _ = e2e.DescribePChain("[Interchain Workflow]", ginkgo.Label(e2e.UsesCChainL ginkgo.By("exporting AVAX from the P-Chain to the X-Chain", func() { _, err := pWallet.IssueExportTx( - xWallet.BlockchainID(), + xContext.BlockchainID, exportOutputs, e2e.WithDefaultContext(), ) diff --git a/tests/e2e/p/permissionless_subnets.go b/tests/e2e/p/permissionless_subnets.go index eb0a6e129ae8..dc92bdd60d5c 100644 --- a/tests/e2e/p/permissionless_subnets.go +++ b/tests/e2e/p/permissionless_subnets.go @@ -36,7 +36,9 @@ var _ = e2e.DescribePChain("[Permissionless Subnets]", func() { pWallet := baseWallet.P() xWallet := baseWallet.X() - xChainID := xWallet.BlockchainID() + xBuilder := xWallet.Builder() + xContext := xBuilder.Context() + xChainID := xContext.BlockchainID var validatorID ids.NodeID ginkgo.By("retrieving the node ID of a primary network validator", func() { diff --git a/tests/e2e/p/workflow.go b/tests/e2e/p/workflow.go index 7b9e213acaa5..3708c6b82c0a 100644 --- a/tests/e2e/p/workflow.go +++ b/tests/e2e/p/workflow.go @@ -45,6 +45,8 @@ var _ = e2e.DescribePChain("[Workflow]", func() { pContext := pBuilder.Context() avaxAssetID := pContext.AVAXAssetID xWallet := baseWallet.X() + xBuilder := xWallet.Builder() + xContext := xBuilder.Context() pChainClient := platformvm.NewClient(nodeURI.URI) tests.Outf("{{blue}} fetching minimal stake amounts {{/}}\n") @@ -143,7 +145,7 @@ var _ = e2e.DescribePChain("[Workflow]", func() { ginkgo.By("export avax from P to X chain", func() { _, err := pWallet.IssueExportTx( - xWallet.BlockchainID(), + xContext.BlockchainID, []*avax.TransferableOutput{ { Asset: avax.Asset{ diff --git a/tests/e2e/x/interchain_workflow.go b/tests/e2e/x/interchain_workflow.go index ce13cf8ab7ad..838c6d11773d 100644 --- a/tests/e2e/x/interchain_workflow.go +++ b/tests/e2e/x/interchain_workflow.go @@ -42,7 +42,9 @@ var _ = e2e.DescribeXChain("[Interchain Workflow]", ginkgo.Label(e2e.UsesCChainL ginkgo.By("defining common configuration") recipientEthAddress := evm.GetEthAddress(recipientKey) - avaxAssetID := xWallet.AVAXAssetID() + xBuilder := xWallet.Builder() + xContext := xBuilder.Context() + avaxAssetID := xContext.AVAXAssetID // Use the same owner for sending to X-Chain and importing funds to P-Chain recipientOwner := secp256k1fx.OutputOwners{ Threshold: 1, @@ -106,7 +108,7 @@ var _ = e2e.DescribeXChain("[Interchain Workflow]", ginkgo.Label(e2e.UsesCChainL ginkgo.By("importing AVAX from the X-Chain to the C-Chain", func() { _, err := cWallet.IssueImportTx( - xWallet.BlockchainID(), + xContext.BlockchainID, recipientEthAddress, e2e.WithDefaultContext(), e2e.WithSuggestedGasPrice(ethClient), @@ -132,7 +134,7 @@ var _ = e2e.DescribeXChain("[Interchain Workflow]", ginkgo.Label(e2e.UsesCChainL ginkgo.By("importing AVAX from the X-Chain to the P-Chain", func() { _, err := pWallet.IssueImportTx( - xWallet.BlockchainID(), + xContext.BlockchainID, &recipientOwner, e2e.WithDefaultContext(), ) diff --git a/tests/e2e/x/transfer/virtuous.go b/tests/e2e/x/transfer/virtuous.go index 4736ba93f17a..886f7bbe834e 100644 --- a/tests/e2e/x/transfer/virtuous.go +++ b/tests/e2e/x/transfer/virtuous.go @@ -84,7 +84,10 @@ var _ = e2e.DescribeXChainSerial("[Virtuous Transfer Tx AVAX]", func() { keychain := secp256k1fx.NewKeychain(testKeys...) baseWallet := e2e.NewWallet(keychain, e2e.Env.GetRandomNodeURI()) - avaxAssetID := baseWallet.X().AVAXAssetID() + xWallet := baseWallet.X() + xBuilder := xWallet.Builder() + xContext := xBuilder.Context() + avaxAssetID := xContext.AVAXAssetID wallets := make([]primary.Wallet, len(testKeys)) shortAddrs := make([]ids.ShortID, len(testKeys)) @@ -146,7 +149,7 @@ var _ = e2e.DescribeXChainSerial("[Virtuous Transfer Tx AVAX]", func() { amountToTransfer := senderOrigBal / 10 - senderNewBal := senderOrigBal - amountToTransfer - baseWallet.X().BaseTxFee() + senderNewBal := senderOrigBal - amountToTransfer - xContext.BaseTxFee receiverNewBal := receiverOrigBal + amountToTransfer ginkgo.By("X-Chain transfer with wrong amount must fail", func() { diff --git a/wallet/chain/x/backend.go b/wallet/chain/x/backend.go index a87e799fa911..e73cb1620e31 100644 --- a/wallet/chain/x/backend.go +++ b/wallet/chain/x/backend.go @@ -4,10 +4,12 @@ package x import ( + "context" + "github.com/ava-labs/avalanchego/vms/avm/txs" + "github.com/ava-labs/avalanchego/wallet/chain/x/builder" + "github.com/ava-labs/avalanchego/wallet/chain/x/signer" "github.com/ava-labs/avalanchego/wallet/subnet/primary/common" - - stdcontext "context" ) var _ Backend = (*backend)(nil) @@ -15,25 +17,26 @@ var _ Backend = (*backend)(nil) // Backend defines the full interface required to support an X-chain wallet. type Backend interface { common.ChainUTXOs - BuilderBackend - SignerBackend + builder.Backend + signer.Backend - AcceptTx(ctx stdcontext.Context, tx *txs.Tx) error + AcceptTx(ctx context.Context, tx *txs.Tx) error } type backend struct { - Context common.ChainUTXOs + + context *builder.Context } -func NewBackend(ctx Context, utxos common.ChainUTXOs) Backend { +func NewBackend(context *builder.Context, utxos common.ChainUTXOs) Backend { return &backend{ - Context: ctx, ChainUTXOs: utxos, + context: context, } } -func (b *backend) AcceptTx(ctx stdcontext.Context, tx *txs.Tx) error { +func (b *backend) AcceptTx(ctx context.Context, tx *txs.Tx) error { err := tx.Unsigned.Visit(&backendVisitor{ b: b, ctx: ctx, @@ -43,7 +46,7 @@ func (b *backend) AcceptTx(ctx stdcontext.Context, tx *txs.Tx) error { return err } - chainID := b.Context.BlockchainID() + chainID := b.context.BlockchainID inputUTXOs := tx.Unsigned.InputUTXOs() for _, utxoID := range inputUTXOs { if utxoID.Symbol { diff --git a/wallet/chain/x/backend_visitor.go b/wallet/chain/x/backend_visitor.go index 0bf9ac040a97..4809bf2e06de 100644 --- a/wallet/chain/x/backend_visitor.go +++ b/wallet/chain/x/backend_visitor.go @@ -4,11 +4,11 @@ package x import ( + "context" + "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/vms/avm/txs" "github.com/ava-labs/avalanchego/vms/components/avax" - - stdcontext "context" ) var _ txs.Visitor = (*backendVisitor)(nil) @@ -16,7 +16,7 @@ var _ txs.Visitor = (*backendVisitor)(nil) // backendVisitor handles accepting of transactions for the backend type backendVisitor struct { b *backend - ctx stdcontext.Context + ctx context.Context txID ids.ID } diff --git a/wallet/chain/x/builder.go b/wallet/chain/x/builder/builder.go similarity index 91% rename from wallet/chain/x/builder.go rename to wallet/chain/x/builder/builder.go index 330ed69a2504..20411e6e4ce7 100644 --- a/wallet/chain/x/builder.go +++ b/wallet/chain/x/builder/builder.go @@ -1,9 +1,10 @@ // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. -package x +package builder import ( + "context" "errors" "fmt" @@ -18,8 +19,6 @@ import ( "github.com/ava-labs/avalanchego/vms/propertyfx" "github.com/ava-labs/avalanchego/vms/secp256k1fx" "github.com/ava-labs/avalanchego/wallet/subnet/primary/common" - - stdcontext "context" ) var ( @@ -27,9 +26,9 @@ var ( errInsufficientFunds = errors.New("insufficient funds") fxIndexToID = map[uint32]ids.ID{ - 0: secp256k1fx.ID, - 1: nftfx.ID, - 2: propertyfx.ID, + SECP256K1FxIndex: secp256k1fx.ID, + NFTFxIndex: nftfx.ID, + PropertyFxIndex: propertyfx.ID, } _ Builder = (*builder)(nil) @@ -38,6 +37,10 @@ var ( // Builder provides a convenient interface for building unsigned X-chain // transactions. type Builder interface { + // Context returns the configuration of the chain that this builder uses to + // create transactions. + Context() *Context + // GetFTBalance calculates the amount of each fungible asset that this // builder has control over. GetFTBalance( @@ -154,37 +157,43 @@ type Builder interface { ) (*txs.ExportTx, error) } -// BuilderBackend specifies the required information needed to build unsigned -// X-chain transactions. -type BuilderBackend interface { - Context - - UTXOs(ctx stdcontext.Context, sourceChainID ids.ID) ([]*avax.UTXO, error) +type Backend interface { + UTXOs(ctx context.Context, sourceChainID ids.ID) ([]*avax.UTXO, error) } type builder struct { addrs set.Set[ids.ShortID] - backend BuilderBackend + context *Context + backend Backend } -// NewBuilder returns a new transaction builder. +// New returns a new transaction builder. // // - [addrs] is the set of addresses that the builder assumes can be used when // signing the transactions in the future. -// - [backend] provides the required access to the chain's context and state -// to build out the transactions. -func NewBuilder(addrs set.Set[ids.ShortID], backend BuilderBackend) Builder { +// - [context] provides the chain's configuration. +// - [backend] provides the chain's state. +func New( + addrs set.Set[ids.ShortID], + context *Context, + backend Backend, +) Builder { return &builder{ addrs: addrs, + context: context, backend: backend, } } +func (b *builder) Context() *Context { + return b.context +} + func (b *builder) GetFTBalance( options ...common.Option, ) (map[ids.ID]uint64, error) { ops := common.NewOptions(options) - return b.getBalance(b.backend.BlockchainID(), ops) + return b.getBalance(b.context.BlockchainID, ops) } func (b *builder) GetImportableBalance( @@ -200,7 +209,7 @@ func (b *builder) NewBaseTx( options ...common.Option, ) (*txs.BaseTx, error) { toBurn := map[ids.ID]uint64{ - b.backend.AVAXAssetID(): b.backend.BaseTxFee(), + b.context.AVAXAssetID: b.context.BaseTxFee, } for _, out := range outputs { assetID := out.AssetID() @@ -220,8 +229,8 @@ func (b *builder) NewBaseTx( avax.SortTransferableOutputs(outputs, Parser.Codec()) // sort the outputs tx := &txs.BaseTx{BaseTx: avax.BaseTx{ - NetworkID: b.backend.NetworkID(), - BlockchainID: b.backend.BlockchainID(), + NetworkID: b.context.NetworkID, + BlockchainID: b.context.BlockchainID, Ins: inputs, Outs: outputs, Memo: ops.Memo(), @@ -237,7 +246,7 @@ func (b *builder) NewCreateAssetTx( options ...common.Option, ) (*txs.CreateAssetTx, error) { toBurn := map[ids.ID]uint64{ - b.backend.AVAXAssetID(): b.backend.CreateAssetTxFee(), + b.context.AVAXAssetID: b.context.CreateAssetTxFee, } ops := common.NewOptions(options) inputs, outputs, err := b.spend(toBurn, ops) @@ -260,8 +269,8 @@ func (b *builder) NewCreateAssetTx( utils.Sort(states) // sort the initial states tx := &txs.CreateAssetTx{ BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ - NetworkID: b.backend.NetworkID(), - BlockchainID: b.backend.BlockchainID(), + NetworkID: b.context.NetworkID, + BlockchainID: b.context.BlockchainID, Ins: inputs, Outs: outputs, Memo: ops.Memo(), @@ -279,7 +288,7 @@ func (b *builder) NewOperationTx( options ...common.Option, ) (*txs.OperationTx, error) { toBurn := map[ids.ID]uint64{ - b.backend.AVAXAssetID(): b.backend.BaseTxFee(), + b.context.AVAXAssetID: b.context.BaseTxFee, } ops := common.NewOptions(options) inputs, outputs, err := b.spend(toBurn, ops) @@ -290,8 +299,8 @@ func (b *builder) NewOperationTx( txs.SortOperations(operations, Parser.Codec()) tx := &txs.OperationTx{ BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ - NetworkID: b.backend.NetworkID(), - BlockchainID: b.backend.BlockchainID(), + NetworkID: b.context.NetworkID, + BlockchainID: b.context.BlockchainID, Ins: inputs, Outs: outputs, Memo: ops.Memo(), @@ -366,8 +375,8 @@ func (b *builder) NewImportTx( var ( addrs = ops.Addresses(b.addrs) minIssuanceTime = ops.MinIssuanceTime() - avaxAssetID = b.backend.AVAXAssetID() - txFee = b.backend.BaseTxFee() + avaxAssetID = b.context.AVAXAssetID + txFee = b.context.BaseTxFee importedInputs = make([]*avax.TransferableInput, 0, len(utxos)) importedAmounts = make(map[ids.ID]uint64) @@ -449,8 +458,8 @@ func (b *builder) NewImportTx( avax.SortTransferableOutputs(outputs, Parser.Codec()) tx := &txs.ImportTx{ BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ - NetworkID: b.backend.NetworkID(), - BlockchainID: b.backend.BlockchainID(), + NetworkID: b.context.NetworkID, + BlockchainID: b.context.BlockchainID, Ins: inputs, Outs: outputs, Memo: ops.Memo(), @@ -467,7 +476,7 @@ func (b *builder) NewExportTx( options ...common.Option, ) (*txs.ExportTx, error) { toBurn := map[ids.ID]uint64{ - b.backend.AVAXAssetID(): b.backend.BaseTxFee(), + b.context.AVAXAssetID: b.context.BaseTxFee, } for _, out := range outputs { assetID := out.AssetID() @@ -487,8 +496,8 @@ func (b *builder) NewExportTx( avax.SortTransferableOutputs(outputs, Parser.Codec()) tx := &txs.ExportTx{ BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ - NetworkID: b.backend.NetworkID(), - BlockchainID: b.backend.BlockchainID(), + NetworkID: b.context.NetworkID, + BlockchainID: b.context.BlockchainID, Ins: inputs, Outs: changeOutputs, Memo: ops.Memo(), @@ -547,7 +556,7 @@ func (b *builder) spend( outputs []*avax.TransferableOutput, err error, ) { - utxos, err := b.backend.UTXOs(options.Context(), b.backend.BlockchainID()) + utxos, err := b.backend.UTXOs(options.Context(), b.context.BlockchainID) if err != nil { return nil, nil, err } @@ -642,7 +651,7 @@ func (b *builder) mintFTs( operations []*txs.Operation, err error, ) { - utxos, err := b.backend.UTXOs(options.Context(), b.backend.BlockchainID()) + utxos, err := b.backend.UTXOs(options.Context(), b.context.BlockchainID) if err != nil { return nil, err } @@ -705,7 +714,7 @@ func (b *builder) mintNFTs( operations []*txs.Operation, err error, ) { - utxos, err := b.backend.UTXOs(options.Context(), b.backend.BlockchainID()) + utxos, err := b.backend.UTXOs(options.Context(), b.context.BlockchainID) if err != nil { return nil, err } @@ -762,7 +771,7 @@ func (b *builder) mintProperty( operations []*txs.Operation, err error, ) { - utxos, err := b.backend.UTXOs(options.Context(), b.backend.BlockchainID()) + utxos, err := b.backend.UTXOs(options.Context(), b.context.BlockchainID) if err != nil { return nil, err } @@ -819,7 +828,7 @@ func (b *builder) burnProperty( operations []*txs.Operation, err error, ) { - utxos, err := b.backend.UTXOs(options.Context(), b.backend.BlockchainID()) + utxos, err := b.backend.UTXOs(options.Context(), b.context.BlockchainID) if err != nil { return nil, err } @@ -868,7 +877,11 @@ func (b *builder) burnProperty( } func (b *builder) initCtx(tx txs.UnsignedTx) error { - ctx, err := newSnowContext(b.backend) + ctx, err := NewSnowContext( + b.context.NetworkID, + b.context.BlockchainID, + b.context.AVAXAssetID, + ) if err != nil { return err } diff --git a/wallet/chain/x/builder_with_options.go b/wallet/chain/x/builder/builder_with_options.go similarity index 81% rename from wallet/chain/x/builder_with_options.go rename to wallet/chain/x/builder/builder_with_options.go index c2b65b05a630..a788ccee33c6 100644 --- a/wallet/chain/x/builder_with_options.go +++ b/wallet/chain/x/builder/builder_with_options.go @@ -1,7 +1,7 @@ // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. -package x +package builder import ( "github.com/ava-labs/avalanchego/ids" @@ -15,28 +15,32 @@ import ( var _ Builder = (*builderWithOptions)(nil) type builderWithOptions struct { - Builder + builder Builder options []common.Option } -// NewBuilderWithOptions returns a new transaction builder that will use the -// given options by default. +// NewWithOptions returns a new transaction builder that will use the given +// options by default. // // - [builder] is the builder that will be called to perform the underlying // operations. // - [options] will be provided to the builder in addition to the options // provided in the method calls. -func NewBuilderWithOptions(builder Builder, options ...common.Option) Builder { +func NewWithOptions(builder Builder, options ...common.Option) Builder { return &builderWithOptions{ - Builder: builder, + builder: builder, options: options, } } +func (b *builderWithOptions) Context() *Context { + return b.builder.Context() +} + func (b *builderWithOptions) GetFTBalance( options ...common.Option, ) (map[ids.ID]uint64, error) { - return b.Builder.GetFTBalance( + return b.builder.GetFTBalance( common.UnionOptions(b.options, options)..., ) } @@ -45,7 +49,7 @@ func (b *builderWithOptions) GetImportableBalance( chainID ids.ID, options ...common.Option, ) (map[ids.ID]uint64, error) { - return b.Builder.GetImportableBalance( + return b.builder.GetImportableBalance( chainID, common.UnionOptions(b.options, options)..., ) @@ -55,7 +59,7 @@ func (b *builderWithOptions) NewBaseTx( outputs []*avax.TransferableOutput, options ...common.Option, ) (*txs.BaseTx, error) { - return b.Builder.NewBaseTx( + return b.builder.NewBaseTx( outputs, common.UnionOptions(b.options, options)..., ) @@ -68,7 +72,7 @@ func (b *builderWithOptions) NewCreateAssetTx( initialState map[uint32][]verify.State, options ...common.Option, ) (*txs.CreateAssetTx, error) { - return b.Builder.NewCreateAssetTx( + return b.builder.NewCreateAssetTx( name, symbol, denomination, @@ -81,7 +85,7 @@ func (b *builderWithOptions) NewOperationTx( operations []*txs.Operation, options ...common.Option, ) (*txs.OperationTx, error) { - return b.Builder.NewOperationTx( + return b.builder.NewOperationTx( operations, common.UnionOptions(b.options, options)..., ) @@ -91,7 +95,7 @@ func (b *builderWithOptions) NewOperationTxMintFT( outputs map[ids.ID]*secp256k1fx.TransferOutput, options ...common.Option, ) (*txs.OperationTx, error) { - return b.Builder.NewOperationTxMintFT( + return b.builder.NewOperationTxMintFT( outputs, common.UnionOptions(b.options, options)..., ) @@ -103,7 +107,7 @@ func (b *builderWithOptions) NewOperationTxMintNFT( owners []*secp256k1fx.OutputOwners, options ...common.Option, ) (*txs.OperationTx, error) { - return b.Builder.NewOperationTxMintNFT( + return b.builder.NewOperationTxMintNFT( assetID, payload, owners, @@ -116,7 +120,7 @@ func (b *builderWithOptions) NewOperationTxMintProperty( owner *secp256k1fx.OutputOwners, options ...common.Option, ) (*txs.OperationTx, error) { - return b.Builder.NewOperationTxMintProperty( + return b.builder.NewOperationTxMintProperty( assetID, owner, common.UnionOptions(b.options, options)..., @@ -127,7 +131,7 @@ func (b *builderWithOptions) NewOperationTxBurnProperty( assetID ids.ID, options ...common.Option, ) (*txs.OperationTx, error) { - return b.Builder.NewOperationTxBurnProperty( + return b.builder.NewOperationTxBurnProperty( assetID, common.UnionOptions(b.options, options)..., ) @@ -138,7 +142,7 @@ func (b *builderWithOptions) NewImportTx( to *secp256k1fx.OutputOwners, options ...common.Option, ) (*txs.ImportTx, error) { - return b.Builder.NewImportTx( + return b.builder.NewImportTx( chainID, to, common.UnionOptions(b.options, options)..., @@ -150,7 +154,7 @@ func (b *builderWithOptions) NewExportTx( outputs []*avax.TransferableOutput, options ...common.Option, ) (*txs.ExportTx, error) { - return b.Builder.NewExportTx( + return b.builder.NewExportTx( chainID, outputs, common.UnionOptions(b.options, options)..., diff --git a/wallet/chain/x/constants.go b/wallet/chain/x/builder/constants.go similarity index 97% rename from wallet/chain/x/constants.go rename to wallet/chain/x/builder/constants.go index 690fa168b5fd..2fc1b1132b93 100644 --- a/wallet/chain/x/constants.go +++ b/wallet/chain/x/builder/constants.go @@ -1,7 +1,7 @@ // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. -package x +package builder import ( "github.com/ava-labs/avalanchego/vms/avm/block" diff --git a/wallet/chain/x/builder/context.go b/wallet/chain/x/builder/context.go new file mode 100644 index 000000000000..6a072cf6230b --- /dev/null +++ b/wallet/chain/x/builder/context.go @@ -0,0 +1,38 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package builder + +import ( + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/snow" + "github.com/ava-labs/avalanchego/utils/constants" + "github.com/ava-labs/avalanchego/utils/logging" +) + +const Alias = "X" + +type Context struct { + NetworkID uint32 + BlockchainID ids.ID + AVAXAssetID ids.ID + BaseTxFee uint64 + CreateAssetTxFee uint64 +} + +func NewSnowContext( + networkID uint32, + blockchainID ids.ID, + avaxAssetID ids.ID, +) (*snow.Context, error) { + lookup := ids.NewAliaser() + return &snow.Context{ + NetworkID: networkID, + SubnetID: constants.PrimaryNetworkID, + ChainID: blockchainID, + XChainID: blockchainID, + AVAXAssetID: avaxAssetID, + Log: logging.NoLog{}, + BCLookup: lookup, + }, lookup.Alias(blockchainID, Alias) +} diff --git a/wallet/chain/x/builder_test.go b/wallet/chain/x/builder_test.go index 0e349ad28565..801046c185ca 100644 --- a/wallet/chain/x/builder_test.go +++ b/wallet/chain/x/builder_test.go @@ -18,6 +18,7 @@ import ( "github.com/ava-labs/avalanchego/vms/nftfx" "github.com/ava-labs/avalanchego/vms/propertyfx" "github.com/ava-labs/avalanchego/vms/secp256k1fx" + "github.com/ava-labs/avalanchego/wallet/chain/x/builder" "github.com/ava-labs/avalanchego/wallet/subnet/primary/common" ) @@ -31,13 +32,13 @@ var ( nftAssetID = ids.Empty.Prefix(2022) propertyAssetID = ids.Empty.Prefix(2023) - testCtx = NewContext( - constants.UnitTestID, - xChainID, - avaxAssetID, - units.MicroAvax, // BaseTxFee - 99*units.MilliAvax, // CreateAssetTxFee - ) + testContext = &builder.Context{ + NetworkID: constants.UnitTestID, + BlockchainID: xChainID, + AVAXAssetID: avaxAssetID, + BaseTxFee: units.MicroAvax, + CreateAssetTxFee: 99 * units.MilliAvax, + } ) // These tests create and sign a tx, then verify that utxos included @@ -56,11 +57,11 @@ func TestBaseTx(t *testing.T) { xChainID: utxos, }, ) - backend = NewBackend(testCtx, genericBackend) + backend = NewBackend(testContext, genericBackend) // builder utxoAddr = utxosKey.Address() - builder = NewBuilder(set.Of(utxoAddr), backend) + builder = builder.New(set.Of(utxoAddr), testContext, backend) // data to build the transaction outputsToMove = []*avax.TransferableOutput{{ @@ -86,7 +87,7 @@ func TestBaseTx(t *testing.T) { require.Len(ins, 2) require.Len(outs, 2) - expectedConsumed := testCtx.BaseTxFee() + expectedConsumed := testContext.BaseTxFee consumed := ins[0].In.Amount() + ins[1].In.Amount() - outs[0].Out.Amount() - outs[1].Out.Amount() require.Equal(expectedConsumed, consumed) require.Equal(outputsToMove[0], outs[1]) @@ -105,11 +106,11 @@ func TestCreateAssetTx(t *testing.T) { xChainID: utxos, }, ) - backend = NewBackend(testCtx, genericBackend) + backend = NewBackend(testContext, genericBackend) // builder utxoAddr = utxosKey.Address() - builder = NewBuilder(set.Of(utxoAddr), backend) + builder = builder.New(set.Of(utxoAddr), testContext, backend) // data to build the transaction assetName = "Team Rocket" @@ -176,7 +177,7 @@ func TestCreateAssetTx(t *testing.T) { require.Len(ins, 2) require.Len(outs, 1) - expectedConsumed := testCtx.CreateAssetTxFee() + expectedConsumed := testContext.CreateAssetTxFee consumed := ins[0].In.Amount() + ins[1].In.Amount() - outs[0].Out.Amount() require.Equal(expectedConsumed, consumed) } @@ -194,11 +195,11 @@ func TestMintNFTOperation(t *testing.T) { xChainID: utxos, }, ) - backend = NewBackend(testCtx, genericBackend) + backend = NewBackend(testContext, genericBackend) // builder utxoAddr = utxosKey.Address() - builder = NewBuilder(set.Of(utxoAddr), backend) + builder = builder.New(set.Of(utxoAddr), testContext, backend) // data to build the transaction payload = []byte{'h', 'e', 'l', 'l', 'o'} @@ -221,7 +222,7 @@ func TestMintNFTOperation(t *testing.T) { require.Len(ins, 1) require.Len(outs, 1) - expectedConsumed := testCtx.BaseTxFee() + expectedConsumed := testContext.BaseTxFee consumed := ins[0].In.Amount() - outs[0].Out.Amount() require.Equal(expectedConsumed, consumed) } @@ -239,11 +240,11 @@ func TestMintFTOperation(t *testing.T) { xChainID: utxos, }, ) - backend = NewBackend(testCtx, genericBackend) + backend = NewBackend(testContext, genericBackend) // builder utxoAddr = utxosKey.Address() - builder = NewBuilder(set.Of(utxoAddr), backend) + builder = builder.New(set.Of(utxoAddr), testContext, backend) // data to build the transaction outputs = map[ids.ID]*secp256k1fx.TransferOutput{ @@ -268,7 +269,7 @@ func TestMintFTOperation(t *testing.T) { require.Len(ins, 1) require.Len(outs, 1) - expectedConsumed := testCtx.BaseTxFee() + expectedConsumed := testContext.BaseTxFee consumed := ins[0].In.Amount() - outs[0].Out.Amount() require.Equal(expectedConsumed, consumed) } @@ -286,11 +287,11 @@ func TestMintPropertyOperation(t *testing.T) { xChainID: utxos, }, ) - backend = NewBackend(testCtx, genericBackend) + backend = NewBackend(testContext, genericBackend) // builder utxoAddr = utxosKey.Address() - builder = NewBuilder(set.Of(utxoAddr), backend) + builder = builder.New(set.Of(utxoAddr), testContext, backend) // data to build the transaction propertyOwner = &secp256k1fx.OutputOwners{ @@ -311,7 +312,7 @@ func TestMintPropertyOperation(t *testing.T) { require.Len(ins, 1) require.Len(outs, 1) - expectedConsumed := testCtx.BaseTxFee() + expectedConsumed := testContext.BaseTxFee consumed := ins[0].In.Amount() - outs[0].Out.Amount() require.Equal(expectedConsumed, consumed) } @@ -329,11 +330,11 @@ func TestBurnPropertyOperation(t *testing.T) { xChainID: utxos, }, ) - backend = NewBackend(testCtx, genericBackend) + backend = NewBackend(testContext, genericBackend) // builder utxoAddr = utxosKey.Address() - builder = NewBuilder(set.Of(utxoAddr), backend) + builder = builder.New(set.Of(utxoAddr), testContext, backend) ) utx, err := builder.NewOperationTxBurnProperty( @@ -347,7 +348,7 @@ func TestBurnPropertyOperation(t *testing.T) { require.Len(ins, 1) require.Len(outs, 1) - expectedConsumed := testCtx.BaseTxFee() + expectedConsumed := testContext.BaseTxFee consumed := ins[0].In.Amount() - outs[0].Out.Amount() require.Equal(expectedConsumed, consumed) } @@ -369,11 +370,11 @@ func TestImportTx(t *testing.T) { }, ) - backend = NewBackend(testCtx, genericBackend) + backend = NewBackend(testContext, genericBackend) // builder utxoAddr = utxosKey.Address() - builder = NewBuilder(set.Of(utxoAddr), backend) + builder = builder.New(set.Of(utxoAddr), testContext, backend) // data to build the transaction importKey = testKeys[0] @@ -399,7 +400,7 @@ func TestImportTx(t *testing.T) { require.Len(importedIns, 1) require.Len(outs, 1) - expectedConsumed := testCtx.BaseTxFee() + expectedConsumed := testContext.BaseTxFee consumed := importedIns[0].In.Amount() - outs[0].Out.Amount() require.Equal(expectedConsumed, consumed) } @@ -417,11 +418,11 @@ func TestExportTx(t *testing.T) { xChainID: utxos, }, ) - backend = NewBackend(testCtx, genericBackend) + backend = NewBackend(testContext, genericBackend) // builder utxoAddr = utxosKey.Address() - builder = NewBuilder(set.Of(utxoAddr), backend) + builder = builder.New(set.Of(utxoAddr), testContext, backend) // data to build the transaction subnetID = ids.GenerateTestID() @@ -449,7 +450,7 @@ func TestExportTx(t *testing.T) { require.Len(ins, 2) require.Len(outs, 1) - expectedConsumed := testCtx.BaseTxFee() + exportedOutputs[0].Out.Amount() + expectedConsumed := testContext.BaseTxFee + exportedOutputs[0].Out.Amount() consumed := ins[0].In.Amount() + ins[1].In.Amount() - outs[0].Out.Amount() require.Equal(expectedConsumed, consumed) require.Equal(utx.ExportedOuts, exportedOutputs) diff --git a/wallet/chain/x/context.go b/wallet/chain/x/context.go index 7218bc8c1436..7bd4e280a2cf 100644 --- a/wallet/chain/x/context.go +++ b/wallet/chain/x/context.go @@ -4,53 +4,30 @@ package x import ( + "context" + "github.com/ava-labs/avalanchego/api/info" - "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/avalanchego/snow" - "github.com/ava-labs/avalanchego/utils/constants" - "github.com/ava-labs/avalanchego/utils/logging" "github.com/ava-labs/avalanchego/vms/avm" - - stdcontext "context" + "github.com/ava-labs/avalanchego/wallet/chain/x/builder" ) -const Alias = "X" - -var _ Context = (*context)(nil) - -type Context interface { - NetworkID() uint32 - BlockchainID() ids.ID - AVAXAssetID() ids.ID - BaseTxFee() uint64 - CreateAssetTxFee() uint64 -} - -type context struct { - networkID uint32 - blockchainID ids.ID - avaxAssetID ids.ID - baseTxFee uint64 - createAssetTxFee uint64 -} - -func NewContextFromURI(ctx stdcontext.Context, uri string) (Context, error) { +func NewContextFromURI(ctx context.Context, uri string) (*builder.Context, error) { infoClient := info.NewClient(uri) - xChainClient := avm.NewClient(uri, Alias) + xChainClient := avm.NewClient(uri, builder.Alias) return NewContextFromClients(ctx, infoClient, xChainClient) } func NewContextFromClients( - ctx stdcontext.Context, + ctx context.Context, infoClient info.Client, xChainClient avm.Client, -) (Context, error) { +) (*builder.Context, error) { networkID, err := infoClient.GetNetworkID(ctx) if err != nil { return nil, err } - chainID, err := infoClient.GetBlockchainID(ctx, Alias) + chainID, err := infoClient.GetBlockchainID(ctx, builder.Alias) if err != nil { return nil, err } @@ -65,61 +42,11 @@ func NewContextFromClients( return nil, err } - return NewContext( - networkID, - chainID, - asset.AssetID, - uint64(txFees.TxFee), - uint64(txFees.CreateAssetTxFee), - ), nil -} - -func NewContext( - networkID uint32, - blockchainID ids.ID, - avaxAssetID ids.ID, - baseTxFee uint64, - createAssetTxFee uint64, -) Context { - return &context{ - networkID: networkID, - blockchainID: blockchainID, - avaxAssetID: avaxAssetID, - baseTxFee: baseTxFee, - createAssetTxFee: createAssetTxFee, - } -} - -func (c *context) NetworkID() uint32 { - return c.networkID -} - -func (c *context) BlockchainID() ids.ID { - return c.blockchainID -} - -func (c *context) AVAXAssetID() ids.ID { - return c.avaxAssetID -} - -func (c *context) BaseTxFee() uint64 { - return c.baseTxFee -} - -func (c *context) CreateAssetTxFee() uint64 { - return c.createAssetTxFee -} - -func newSnowContext(c Context) (*snow.Context, error) { - chainID := c.BlockchainID() - lookup := ids.NewAliaser() - return &snow.Context{ - NetworkID: c.NetworkID(), - SubnetID: constants.PrimaryNetworkID, - ChainID: chainID, - XChainID: chainID, - AVAXAssetID: c.AVAXAssetID(), - Log: logging.NoLog{}, - BCLookup: lookup, - }, lookup.Alias(chainID, Alias) + return &builder.Context{ + NetworkID: networkID, + BlockchainID: chainID, + AVAXAssetID: asset.AssetID, + BaseTxFee: uint64(txFees.TxFee), + CreateAssetTxFee: uint64(txFees.CreateAssetTxFee), + }, nil } diff --git a/wallet/chain/x/signer.go b/wallet/chain/x/signer/signer.go similarity index 71% rename from wallet/chain/x/signer.go rename to wallet/chain/x/signer/signer.go index 9bc8734e46cd..1d3b943e6b87 100644 --- a/wallet/chain/x/signer.go +++ b/wallet/chain/x/signer/signer.go @@ -1,15 +1,15 @@ // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. -package x +package signer import ( + "context" + "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/crypto/keychain" "github.com/ava-labs/avalanchego/vms/avm/txs" "github.com/ava-labs/avalanchego/vms/components/avax" - - stdcontext "context" ) var _ Signer = (*signer)(nil) @@ -23,27 +23,27 @@ type Signer interface { // // If the signer doesn't have the ability to provide a required signature, // the signature slot will be skipped without reporting an error. - Sign(ctx stdcontext.Context, tx *txs.Tx) error + Sign(ctx context.Context, tx *txs.Tx) error } -type SignerBackend interface { - GetUTXO(ctx stdcontext.Context, chainID, utxoID ids.ID) (*avax.UTXO, error) +type Backend interface { + GetUTXO(ctx context.Context, chainID, utxoID ids.ID) (*avax.UTXO, error) } type signer struct { kc keychain.Keychain - backend SignerBackend + backend Backend } -func NewSigner(kc keychain.Keychain, backend SignerBackend) Signer { +func New(kc keychain.Keychain, backend Backend) Signer { return &signer{ kc: kc, backend: backend, } } -func (s *signer) Sign(ctx stdcontext.Context, tx *txs.Tx) error { - return tx.Unsigned.Visit(&signerVisitor{ +func (s *signer) Sign(ctx context.Context, tx *txs.Tx) error { + return tx.Unsigned.Visit(&visitor{ kc: s.kc, backend: s.backend, ctx: ctx, @@ -52,7 +52,7 @@ func (s *signer) Sign(ctx stdcontext.Context, tx *txs.Tx) error { } func SignUnsigned( - ctx stdcontext.Context, + ctx context.Context, signer Signer, utx txs.UnsignedTx, ) (*txs.Tx, error) { diff --git a/wallet/chain/x/signer_visitor.go b/wallet/chain/x/signer/visitor.go similarity index 82% rename from wallet/chain/x/signer_visitor.go rename to wallet/chain/x/signer/visitor.go index be442f5511f3..23a9940c6147 100644 --- a/wallet/chain/x/signer_visitor.go +++ b/wallet/chain/x/signer/visitor.go @@ -1,9 +1,10 @@ // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. -package x +package signer import ( + "context" "errors" "fmt" @@ -18,32 +19,31 @@ import ( "github.com/ava-labs/avalanchego/vms/nftfx" "github.com/ava-labs/avalanchego/vms/propertyfx" "github.com/ava-labs/avalanchego/vms/secp256k1fx" - - stdcontext "context" + "github.com/ava-labs/avalanchego/wallet/chain/x/builder" ) var ( - _ txs.Visitor = (*signerVisitor)(nil) + _ txs.Visitor = (*visitor)(nil) - errUnknownInputType = errors.New("unknown input type") - errUnknownOpType = errors.New("unknown operation type") - errInvalidNumUTXOsInOp = errors.New("invalid number of UTXOs in operation") - errUnknownCredentialType = errors.New("unknown credential type") - errUnknownOutputType = errors.New("unknown output type") - errInvalidUTXOSigIndex = errors.New("invalid UTXO signature index") + ErrUnknownInputType = errors.New("unknown input type") + ErrUnknownOpType = errors.New("unknown operation type") + ErrInvalidNumUTXOsInOp = errors.New("invalid number of UTXOs in operation") + ErrUnknownCredentialType = errors.New("unknown credential type") + ErrUnknownOutputType = errors.New("unknown output type") + ErrInvalidUTXOSigIndex = errors.New("invalid UTXO signature index") emptySig [secp256k1.SignatureLen]byte ) -// signerVisitor handles signing transactions for the signer -type signerVisitor struct { +// visitor handles signing transactions for the signer +type visitor struct { kc keychain.Keychain - backend SignerBackend - ctx stdcontext.Context + backend Backend + ctx context.Context tx *txs.Tx } -func (s *signerVisitor) BaseTx(tx *txs.BaseTx) error { +func (s *visitor) BaseTx(tx *txs.BaseTx) error { txCreds, txSigners, err := s.getSigners(s.ctx, tx.BlockchainID, tx.Ins) if err != nil { return err @@ -51,7 +51,7 @@ func (s *signerVisitor) BaseTx(tx *txs.BaseTx) error { return sign(s.tx, txCreds, txSigners) } -func (s *signerVisitor) CreateAssetTx(tx *txs.CreateAssetTx) error { +func (s *visitor) CreateAssetTx(tx *txs.CreateAssetTx) error { txCreds, txSigners, err := s.getSigners(s.ctx, tx.BlockchainID, tx.Ins) if err != nil { return err @@ -59,7 +59,7 @@ func (s *signerVisitor) CreateAssetTx(tx *txs.CreateAssetTx) error { return sign(s.tx, txCreds, txSigners) } -func (s *signerVisitor) OperationTx(tx *txs.OperationTx) error { +func (s *visitor) OperationTx(tx *txs.OperationTx) error { txCreds, txSigners, err := s.getSigners(s.ctx, tx.BlockchainID, tx.Ins) if err != nil { return err @@ -73,7 +73,7 @@ func (s *signerVisitor) OperationTx(tx *txs.OperationTx) error { return sign(s.tx, txCreds, txSigners) } -func (s *signerVisitor) ImportTx(tx *txs.ImportTx) error { +func (s *visitor) ImportTx(tx *txs.ImportTx) error { txCreds, txSigners, err := s.getSigners(s.ctx, tx.BlockchainID, tx.Ins) if err != nil { return err @@ -87,7 +87,7 @@ func (s *signerVisitor) ImportTx(tx *txs.ImportTx) error { return sign(s.tx, txCreds, txSigners) } -func (s *signerVisitor) ExportTx(tx *txs.ExportTx) error { +func (s *visitor) ExportTx(tx *txs.ExportTx) error { txCreds, txSigners, err := s.getSigners(s.ctx, tx.BlockchainID, tx.Ins) if err != nil { return err @@ -95,14 +95,14 @@ func (s *signerVisitor) ExportTx(tx *txs.ExportTx) error { return sign(s.tx, txCreds, txSigners) } -func (s *signerVisitor) getSigners(ctx stdcontext.Context, sourceChainID ids.ID, ins []*avax.TransferableInput) ([]verify.Verifiable, [][]keychain.Signer, error) { +func (s *visitor) getSigners(ctx context.Context, sourceChainID ids.ID, ins []*avax.TransferableInput) ([]verify.Verifiable, [][]keychain.Signer, error) { txCreds := make([]verify.Verifiable, len(ins)) txSigners := make([][]keychain.Signer, len(ins)) for credIndex, transferInput := range ins { txCreds[credIndex] = &secp256k1fx.Credential{} input, ok := transferInput.In.(*secp256k1fx.TransferInput) if !ok { - return nil, nil, errUnknownInputType + return nil, nil, ErrUnknownInputType } inputSigners := make([]keychain.Signer, len(input.SigIndices)) @@ -121,12 +121,12 @@ func (s *signerVisitor) getSigners(ctx stdcontext.Context, sourceChainID ids.ID, out, ok := utxo.Out.(*secp256k1fx.TransferOutput) if !ok { - return nil, nil, errUnknownOutputType + return nil, nil, ErrUnknownOutputType } for sigIndex, addrIndex := range input.SigIndices { if addrIndex >= uint32(len(out.Addrs)) { - return nil, nil, errInvalidUTXOSigIndex + return nil, nil, ErrInvalidUTXOSigIndex } addr := out.Addrs[addrIndex] @@ -142,7 +142,7 @@ func (s *signerVisitor) getSigners(ctx stdcontext.Context, sourceChainID ids.ID, return txCreds, txSigners, nil } -func (s *signerVisitor) getOpsSigners(ctx stdcontext.Context, sourceChainID ids.ID, ops []*txs.Operation) ([]verify.Verifiable, [][]keychain.Signer, error) { +func (s *visitor) getOpsSigners(ctx context.Context, sourceChainID ids.ID, ops []*txs.Operation) ([]verify.Verifiable, [][]keychain.Signer, error) { txCreds := make([]verify.Verifiable, len(ops)) txSigners := make([][]keychain.Signer, len(ops)) for credIndex, op := range ops { @@ -164,14 +164,14 @@ func (s *signerVisitor) getOpsSigners(ctx stdcontext.Context, sourceChainID ids. txCreds[credIndex] = &propertyfx.Credential{} input = &op.Input default: - return nil, nil, errUnknownOpType + return nil, nil, ErrUnknownOpType } inputSigners := make([]keychain.Signer, len(input.SigIndices)) txSigners[credIndex] = inputSigners if len(op.UTXOIDs) != 1 { - return nil, nil, errInvalidNumUTXOsInOp + return nil, nil, ErrInvalidNumUTXOsInOp } utxoID := op.UTXOIDs[0].InputID() utxo, err := s.backend.GetUTXO(ctx, sourceChainID, utxoID) @@ -197,12 +197,12 @@ func (s *signerVisitor) getOpsSigners(ctx stdcontext.Context, sourceChainID ids. case *propertyfx.OwnedOutput: addrs = out.Addrs default: - return nil, nil, errUnknownOutputType + return nil, nil, ErrUnknownOutputType } for sigIndex, addrIndex := range input.SigIndices { if addrIndex >= uint32(len(addrs)) { - return nil, nil, errInvalidUTXOSigIndex + return nil, nil, ErrInvalidUTXOSigIndex } addr := addrs[addrIndex] @@ -219,7 +219,7 @@ func (s *signerVisitor) getOpsSigners(ctx stdcontext.Context, sourceChainID ids. } func sign(tx *txs.Tx, creds []verify.Verifiable, txSigners [][]keychain.Signer) error { - codec := Parser.Codec() + codec := builder.Parser.Codec() unsignedBytes, err := codec.Marshal(txs.CodecVersion, &tx.Unsigned) if err != nil { return fmt.Errorf("couldn't marshal unsigned tx: %w", err) @@ -254,7 +254,7 @@ func sign(tx *txs.Tx, creds []verify.Verifiable, txSigners [][]keychain.Signer) fxCred.FxID = propertyfx.ID cred = &credImpl.Credential default: - return errUnknownCredentialType + return ErrUnknownCredentialType } if expectedLen := len(inputSigners); expectedLen != len(cred.Sigs) { diff --git a/wallet/chain/x/wallet.go b/wallet/chain/x/wallet.go index 13491a241349..bb6484b5526a 100644 --- a/wallet/chain/x/wallet.go +++ b/wallet/chain/x/wallet.go @@ -13,23 +13,23 @@ import ( "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/components/verify" "github.com/ava-labs/avalanchego/vms/secp256k1fx" + "github.com/ava-labs/avalanchego/wallet/chain/x/builder" + "github.com/ava-labs/avalanchego/wallet/chain/x/signer" "github.com/ava-labs/avalanchego/wallet/subnet/primary/common" ) var ( - errNotAccepted = errors.New("not accepted") + ErrNotAccepted = errors.New("not accepted") _ Wallet = (*wallet)(nil) ) type Wallet interface { - Context - // Builder returns the builder that will be used to create the transactions. - Builder() Builder + Builder() builder.Builder // Signer returns the signer that will be used to sign the transactions. - Signer() Signer + Signer() signer.Signer // IssueBaseTx creates, signs, and issues a new simple value transfer. // @@ -145,13 +145,13 @@ type Wallet interface { } func NewWallet( - builder Builder, - signer Signer, + builder builder.Builder, + signer signer.Signer, client avm.Client, backend Backend, ) Wallet { return &wallet{ - Backend: backend, + backend: backend, builder: builder, signer: signer, client: client, @@ -159,17 +159,17 @@ func NewWallet( } type wallet struct { - Backend - builder Builder - signer Signer + backend Backend + builder builder.Builder + signer signer.Signer client avm.Client } -func (w *wallet) Builder() Builder { +func (w *wallet) Builder() builder.Builder { return w.builder } -func (w *wallet) Signer() Signer { +func (w *wallet) Signer() signer.Signer { return w.signer } @@ -286,7 +286,7 @@ func (w *wallet) IssueUnsignedTx( ) (*txs.Tx, error) { ops := common.NewOptions(options) ctx := ops.Context() - tx, err := SignUnsigned(ctx, w.signer, utx) + tx, err := signer.SignUnsigned(ctx, w.signer, utx) if err != nil { return nil, err } @@ -310,7 +310,7 @@ func (w *wallet) IssueTx( } if ops.AssumeDecided() { - return w.Backend.AcceptTx(ctx, tx) + return w.backend.AcceptTx(ctx, tx) } txStatus, err := w.client.ConfirmTx(ctx, txID, ops.PollFrequency()) @@ -318,12 +318,12 @@ func (w *wallet) IssueTx( return err } - if err := w.Backend.AcceptTx(ctx, tx); err != nil { + if err := w.backend.AcceptTx(ctx, tx); err != nil { return err } if txStatus != choices.Accepted { - return errNotAccepted + return ErrNotAccepted } return nil } diff --git a/wallet/chain/x/wallet_with_options.go b/wallet/chain/x/wallet_with_options.go index d62d02efdd40..33de453b7d61 100644 --- a/wallet/chain/x/wallet_with_options.go +++ b/wallet/chain/x/wallet_with_options.go @@ -9,6 +9,8 @@ import ( "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/components/verify" "github.com/ava-labs/avalanchego/vms/secp256k1fx" + "github.com/ava-labs/avalanchego/wallet/chain/x/builder" + "github.com/ava-labs/avalanchego/wallet/chain/x/signer" "github.com/ava-labs/avalanchego/wallet/subnet/primary/common" ) @@ -19,28 +21,32 @@ func NewWalletWithOptions( options ...common.Option, ) Wallet { return &walletWithOptions{ - Wallet: wallet, + wallet: wallet, options: options, } } type walletWithOptions struct { - Wallet + wallet Wallet options []common.Option } -func (w *walletWithOptions) Builder() Builder { - return NewBuilderWithOptions( - w.Wallet.Builder(), +func (w *walletWithOptions) Builder() builder.Builder { + return builder.NewWithOptions( + w.wallet.Builder(), w.options..., ) } +func (w *walletWithOptions) Signer() signer.Signer { + return w.wallet.Signer() +} + func (w *walletWithOptions) IssueBaseTx( outputs []*avax.TransferableOutput, options ...common.Option, ) (*txs.Tx, error) { - return w.Wallet.IssueBaseTx( + return w.wallet.IssueBaseTx( outputs, common.UnionOptions(w.options, options)..., ) @@ -53,7 +59,7 @@ func (w *walletWithOptions) IssueCreateAssetTx( initialState map[uint32][]verify.State, options ...common.Option, ) (*txs.Tx, error) { - return w.Wallet.IssueCreateAssetTx( + return w.wallet.IssueCreateAssetTx( name, symbol, denomination, @@ -66,7 +72,7 @@ func (w *walletWithOptions) IssueOperationTx( operations []*txs.Operation, options ...common.Option, ) (*txs.Tx, error) { - return w.Wallet.IssueOperationTx( + return w.wallet.IssueOperationTx( operations, common.UnionOptions(w.options, options)..., ) @@ -76,7 +82,7 @@ func (w *walletWithOptions) IssueOperationTxMintFT( outputs map[ids.ID]*secp256k1fx.TransferOutput, options ...common.Option, ) (*txs.Tx, error) { - return w.Wallet.IssueOperationTxMintFT( + return w.wallet.IssueOperationTxMintFT( outputs, common.UnionOptions(w.options, options)..., ) @@ -88,7 +94,7 @@ func (w *walletWithOptions) IssueOperationTxMintNFT( owners []*secp256k1fx.OutputOwners, options ...common.Option, ) (*txs.Tx, error) { - return w.Wallet.IssueOperationTxMintNFT( + return w.wallet.IssueOperationTxMintNFT( assetID, payload, owners, @@ -101,7 +107,7 @@ func (w *walletWithOptions) IssueOperationTxMintProperty( owner *secp256k1fx.OutputOwners, options ...common.Option, ) (*txs.Tx, error) { - return w.Wallet.IssueOperationTxMintProperty( + return w.wallet.IssueOperationTxMintProperty( assetID, owner, common.UnionOptions(w.options, options)..., @@ -112,7 +118,7 @@ func (w *walletWithOptions) IssueOperationTxBurnProperty( assetID ids.ID, options ...common.Option, ) (*txs.Tx, error) { - return w.Wallet.IssueOperationTxBurnProperty( + return w.wallet.IssueOperationTxBurnProperty( assetID, common.UnionOptions(w.options, options)..., ) @@ -123,7 +129,7 @@ func (w *walletWithOptions) IssueImportTx( to *secp256k1fx.OutputOwners, options ...common.Option, ) (*txs.Tx, error) { - return w.Wallet.IssueImportTx( + return w.wallet.IssueImportTx( chainID, to, common.UnionOptions(w.options, options)..., @@ -135,7 +141,7 @@ func (w *walletWithOptions) IssueExportTx( outputs []*avax.TransferableOutput, options ...common.Option, ) (*txs.Tx, error) { - return w.Wallet.IssueExportTx( + return w.wallet.IssueExportTx( chainID, outputs, common.UnionOptions(w.options, options)..., @@ -146,7 +152,7 @@ func (w *walletWithOptions) IssueUnsignedTx( utx txs.UnsignedTx, options ...common.Option, ) (*txs.Tx, error) { - return w.Wallet.IssueUnsignedTx( + return w.wallet.IssueUnsignedTx( utx, common.UnionOptions(w.options, options)..., ) @@ -156,7 +162,7 @@ func (w *walletWithOptions) IssueTx( tx *txs.Tx, options ...common.Option, ) error { - return w.Wallet.IssueTx( + return w.wallet.IssueTx( tx, common.UnionOptions(w.options, options)..., ) diff --git a/wallet/subnet/primary/api.go b/wallet/subnet/primary/api.go index 7486cde263e9..a7c271b385bf 100644 --- a/wallet/subnet/primary/api.go +++ b/wallet/subnet/primary/api.go @@ -21,9 +21,10 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm" "github.com/ava-labs/avalanchego/vms/platformvm/txs" "github.com/ava-labs/avalanchego/wallet/chain/c" - "github.com/ava-labs/avalanchego/wallet/chain/p/builder" "github.com/ava-labs/avalanchego/wallet/chain/x" + pbuilder "github.com/ava-labs/avalanchego/wallet/chain/p/builder" + xbuilder "github.com/ava-labs/avalanchego/wallet/chain/x/builder" walletcommon "github.com/ava-labs/avalanchego/wallet/subnet/primary/common" ethcommon "github.com/ethereum/go-ethereum/common" ) @@ -57,9 +58,9 @@ type UTXOClient interface { type AVAXState struct { PClient platformvm.Client - PCTX *builder.Context + PCTX *pbuilder.Context XClient avm.Client - XCTX x.Context + XCTX *xbuilder.Context CClient evm.Client CCTX c.Context UTXOs walletcommon.UTXOs @@ -78,7 +79,7 @@ func FetchState( xClient := avm.NewClient(uri, "X") cClient := evm.NewCChainClient(uri) - pCTX, err := builder.NewContextFromClients(ctx, infoClient, xClient) + pCTX, err := pbuilder.NewContextFromClients(ctx, infoClient, xClient) if err != nil { return nil, err } @@ -106,9 +107,9 @@ func FetchState( codec: txs.Codec, }, { - id: xCTX.BlockchainID(), + id: xCTX.BlockchainID, client: xClient, - codec: x.Parser.Codec(), + codec: xbuilder.Parser.Codec(), }, { id: cCTX.BlockchainID(), diff --git a/wallet/subnet/primary/example_test.go b/wallet/subnet/primary/example_test.go index 2b8d8b8eeec8..6c2390e00be4 100644 --- a/wallet/subnet/primary/example_test.go +++ b/wallet/subnet/primary/example_test.go @@ -41,9 +41,11 @@ func ExampleWallet() { // Get the P-chain and the X-chain wallets pWallet := wallet.P() xWallet := wallet.X() + xBuilder := xWallet.Builder() + xContext := xBuilder.Context() // Pull out useful constants to use when issuing transactions. - xChainID := xWallet.BlockchainID() + xChainID := xContext.BlockchainID owner := &secp256k1fx.OutputOwners{ Threshold: 1, Addrs: []ids.ShortID{ diff --git a/wallet/subnet/primary/examples/get-x-chain-balance/main.go b/wallet/subnet/primary/examples/get-x-chain-balance/main.go index 9895546879ee..1d45e1de609d 100644 --- a/wallet/subnet/primary/examples/get-x-chain-balance/main.go +++ b/wallet/subnet/primary/examples/get-x-chain-balance/main.go @@ -11,6 +11,7 @@ import ( "github.com/ava-labs/avalanchego/utils/formatting/address" "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/wallet/chain/x" + "github.com/ava-labs/avalanchego/wallet/chain/x/builder" "github.com/ava-labs/avalanchego/wallet/subnet/primary" "github.com/ava-labs/avalanchego/wallet/subnet/primary/common" ) @@ -35,18 +36,18 @@ func main() { } log.Printf("fetched state of %s in %s\n", addrStr, time.Since(fetchStartTime)) - xChainID := state.XCTX.BlockchainID() + xChainID := state.XCTX.BlockchainID xUTXOs := common.NewChainUTXOs(xChainID, state.UTXOs) xBackend := x.NewBackend(state.XCTX, xUTXOs) - xBuilder := x.NewBuilder(addresses, xBackend) + xBuilder := builder.New(addresses, state.XCTX, xBackend) currentBalances, err := xBuilder.GetFTBalance() if err != nil { log.Fatalf("failed to get the balance: %s\n", err) } - avaxID := state.XCTX.AVAXAssetID() + avaxID := state.XCTX.AVAXAssetID avaxBalance := currentBalances[avaxID] log.Printf("current AVAX balance of %s is %d nAVAX\n", addrStr, avaxBalance) } diff --git a/wallet/subnet/primary/wallet.go b/wallet/subnet/primary/wallet.go index 6a9e9d3124b0..382a042a6bee 100644 --- a/wallet/subnet/primary/wallet.go +++ b/wallet/subnet/primary/wallet.go @@ -18,6 +18,8 @@ import ( pbuilder "github.com/ava-labs/avalanchego/wallet/chain/p/builder" psigner "github.com/ava-labs/avalanchego/wallet/chain/p/signer" + xbuilder "github.com/ava-labs/avalanchego/wallet/chain/x/builder" + xsigner "github.com/ava-labs/avalanchego/wallet/chain/x/signer" ) var _ Wallet = (*wallet)(nil) @@ -124,11 +126,11 @@ func MakeWallet(ctx context.Context, config *WalletConfig) (Wallet, error) { pBuilder := pbuilder.New(avaxAddrs, avaxState.PCTX, pBackend) pSigner := psigner.New(config.AVAXKeychain, pBackend) - xChainID := avaxState.XCTX.BlockchainID() + xChainID := avaxState.XCTX.BlockchainID xUTXOs := common.NewChainUTXOs(xChainID, avaxState.UTXOs) xBackend := x.NewBackend(avaxState.XCTX, xUTXOs) - xBuilder := x.NewBuilder(avaxAddrs, xBackend) - xSigner := x.NewSigner(config.AVAXKeychain, xBackend) + xBuilder := xbuilder.New(avaxAddrs, avaxState.XCTX, xBackend) + xSigner := xsigner.New(config.AVAXKeychain, xBackend) cChainID := avaxState.CCTX.BlockchainID() cUTXOs := common.NewChainUTXOs(cChainID, avaxState.UTXOs)