github.com/MetalBlockchain/metalgo@v1.11.9/wallet/subnet/primary/wallet.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package primary 5 6 import ( 7 "context" 8 9 "github.com/MetalBlockchain/metalgo/ids" 10 "github.com/MetalBlockchain/metalgo/utils/constants" 11 "github.com/MetalBlockchain/metalgo/utils/crypto/keychain" 12 "github.com/MetalBlockchain/metalgo/utils/set" 13 "github.com/MetalBlockchain/metalgo/vms/platformvm/txs" 14 "github.com/MetalBlockchain/metalgo/wallet/chain/c" 15 "github.com/MetalBlockchain/metalgo/wallet/chain/p" 16 "github.com/MetalBlockchain/metalgo/wallet/chain/x" 17 "github.com/MetalBlockchain/metalgo/wallet/subnet/primary/common" 18 19 pbuilder "github.com/MetalBlockchain/metalgo/wallet/chain/p/builder" 20 psigner "github.com/MetalBlockchain/metalgo/wallet/chain/p/signer" 21 xbuilder "github.com/MetalBlockchain/metalgo/wallet/chain/x/builder" 22 xsigner "github.com/MetalBlockchain/metalgo/wallet/chain/x/signer" 23 ) 24 25 var _ Wallet = (*wallet)(nil) 26 27 // Wallet provides chain wallets for the primary network. 28 type Wallet interface { 29 P() p.Wallet 30 X() x.Wallet 31 C() c.Wallet 32 } 33 34 type wallet struct { 35 p p.Wallet 36 x x.Wallet 37 c c.Wallet 38 } 39 40 func (w *wallet) P() p.Wallet { 41 return w.p 42 } 43 44 func (w *wallet) X() x.Wallet { 45 return w.x 46 } 47 48 func (w *wallet) C() c.Wallet { 49 return w.c 50 } 51 52 // Creates a new default wallet 53 func NewWallet(p p.Wallet, x x.Wallet, c c.Wallet) Wallet { 54 return &wallet{ 55 p: p, 56 x: x, 57 c: c, 58 } 59 } 60 61 // Creates a Wallet with the given set of options 62 func NewWalletWithOptions(w Wallet, options ...common.Option) Wallet { 63 return NewWallet( 64 p.NewWalletWithOptions(w.P(), options...), 65 x.NewWalletWithOptions(w.X(), options...), 66 c.NewWalletWithOptions(w.C(), options...), 67 ) 68 } 69 70 type WalletConfig struct { 71 // Base URI to use for all node requests. 72 URI string // required 73 // Keys to use for signing all transactions. 74 AVAXKeychain keychain.Keychain // required 75 EthKeychain c.EthKeychain // required 76 // Set of P-chain transactions that the wallet should know about to be able 77 // to generate transactions. 78 PChainTxs map[ids.ID]*txs.Tx // optional 79 // Set of P-chain transactions that the wallet should fetch to be able to 80 // generate transactions. 81 PChainTxsToFetch set.Set[ids.ID] // optional 82 } 83 84 // MakeWallet returns a wallet that supports issuing transactions to the chains 85 // living in the primary network. 86 // 87 // On creation, the wallet attaches to the provided uri and fetches all UTXOs 88 // that reference any of the provided keys. If the UTXOs are modified through an 89 // external issuance process, such as another instance of the wallet, the UTXOs 90 // may become out of sync. The wallet will also fetch all requested P-chain 91 // transactions. 92 // 93 // The wallet manages all state locally, and performs all tx signing locally. 94 func MakeWallet(ctx context.Context, config *WalletConfig) (Wallet, error) { 95 avaxAddrs := config.AVAXKeychain.Addresses() 96 avaxState, err := FetchState(ctx, config.URI, avaxAddrs) 97 if err != nil { 98 return nil, err 99 } 100 101 ethAddrs := config.EthKeychain.EthAddresses() 102 ethState, err := FetchEthState(ctx, config.URI, ethAddrs) 103 if err != nil { 104 return nil, err 105 } 106 107 pChainTxs := config.PChainTxs 108 if pChainTxs == nil { 109 pChainTxs = make(map[ids.ID]*txs.Tx) 110 } 111 112 for txID := range config.PChainTxsToFetch { 113 txBytes, err := avaxState.PClient.GetTx(ctx, txID) 114 if err != nil { 115 return nil, err 116 } 117 tx, err := txs.Parse(txs.Codec, txBytes) 118 if err != nil { 119 return nil, err 120 } 121 pChainTxs[txID] = tx 122 } 123 124 pUTXOs := common.NewChainUTXOs(constants.PlatformChainID, avaxState.UTXOs) 125 pBackend := p.NewBackend(avaxState.PCTX, pUTXOs, pChainTxs) 126 pBuilder := pbuilder.New(avaxAddrs, avaxState.PCTX, pBackend) 127 pSigner := psigner.New(config.AVAXKeychain, pBackend) 128 129 xChainID := avaxState.XCTX.BlockchainID 130 xUTXOs := common.NewChainUTXOs(xChainID, avaxState.UTXOs) 131 xBackend := x.NewBackend(avaxState.XCTX, xUTXOs) 132 xBuilder := xbuilder.New(avaxAddrs, avaxState.XCTX, xBackend) 133 xSigner := xsigner.New(config.AVAXKeychain, xBackend) 134 135 cChainID := avaxState.CCTX.BlockchainID 136 cUTXOs := common.NewChainUTXOs(cChainID, avaxState.UTXOs) 137 cBackend := c.NewBackend(cUTXOs, ethState.Accounts) 138 cBuilder := c.NewBuilder(avaxAddrs, ethAddrs, avaxState.CCTX, cBackend) 139 cSigner := c.NewSigner(config.AVAXKeychain, config.EthKeychain, cBackend) 140 141 return NewWallet( 142 p.NewWallet(pBuilder, pSigner, avaxState.PClient, pBackend), 143 x.NewWallet(xBuilder, xSigner, avaxState.XClient, xBackend), 144 c.NewWallet(cBuilder, cSigner, avaxState.CClient, ethState.Client, cBackend), 145 ), nil 146 }