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  }