github.com/MetalBlockchain/metalgo@v1.11.9/wallet/chain/p/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 p
     5  
     6  import (
     7  	"errors"
     8  	"time"
     9  
    10  	"github.com/MetalBlockchain/metalgo/ids"
    11  	"github.com/MetalBlockchain/metalgo/vms/components/avax"
    12  	"github.com/MetalBlockchain/metalgo/vms/platformvm"
    13  	"github.com/MetalBlockchain/metalgo/vms/platformvm/txs"
    14  	"github.com/MetalBlockchain/metalgo/vms/secp256k1fx"
    15  	"github.com/MetalBlockchain/metalgo/wallet/chain/p/builder"
    16  	"github.com/MetalBlockchain/metalgo/wallet/subnet/primary/common"
    17  
    18  	vmsigner "github.com/MetalBlockchain/metalgo/vms/platformvm/signer"
    19  	walletsigner "github.com/MetalBlockchain/metalgo/wallet/chain/p/signer"
    20  )
    21  
    22  var (
    23  	ErrNotCommitted = errors.New("not committed")
    24  
    25  	_ Wallet = (*wallet)(nil)
    26  )
    27  
    28  type Wallet interface {
    29  	// Builder returns the builder that will be used to create the transactions.
    30  	Builder() builder.Builder
    31  
    32  	// Signer returns the signer that will be used to sign the transactions.
    33  	Signer() walletsigner.Signer
    34  
    35  	// IssueBaseTx creates, signs, and issues a new simple value transfer.
    36  	//
    37  	// - [outputs] specifies all the recipients and amounts that should be sent
    38  	//   from this transaction.
    39  	IssueBaseTx(
    40  		outputs []*avax.TransferableOutput,
    41  		options ...common.Option,
    42  	) (*txs.Tx, error)
    43  
    44  	// IssueAddValidatorTx creates, signs, and issues a new validator of the
    45  	// primary network.
    46  	//
    47  	// - [vdr] specifies all the details of the validation period such as the
    48  	//   startTime, endTime, stake weight, and nodeID.
    49  	// - [rewardsOwner] specifies the owner of all the rewards this validator
    50  	//   may accrue during its validation period.
    51  	// - [shares] specifies the fraction (out of 1,000,000) that this validator
    52  	//   will take from delegation rewards. If 1,000,000 is provided, 100% of
    53  	//   the delegation reward will be sent to the validator's [rewardsOwner].
    54  	IssueAddValidatorTx(
    55  		vdr *txs.Validator,
    56  		rewardsOwner *secp256k1fx.OutputOwners,
    57  		shares uint32,
    58  		options ...common.Option,
    59  	) (*txs.Tx, error)
    60  
    61  	// IssueAddSubnetValidatorTx creates, signs, and issues a new validator of a
    62  	// subnet.
    63  	//
    64  	// - [vdr] specifies all the details of the validation period such as the
    65  	//   startTime, endTime, sampling weight, nodeID, and subnetID.
    66  	IssueAddSubnetValidatorTx(
    67  		vdr *txs.SubnetValidator,
    68  		options ...common.Option,
    69  	) (*txs.Tx, error)
    70  
    71  	// IssueAddSubnetValidatorTx creates, signs, and issues a transaction that
    72  	// removes a validator of a subnet.
    73  	//
    74  	// - [nodeID] is the validator being removed from [subnetID].
    75  	IssueRemoveSubnetValidatorTx(
    76  		nodeID ids.NodeID,
    77  		subnetID ids.ID,
    78  		options ...common.Option,
    79  	) (*txs.Tx, error)
    80  
    81  	// IssueAddDelegatorTx creates, signs, and issues a new delegator to a
    82  	// validator on the primary network.
    83  	//
    84  	// - [vdr] specifies all the details of the delegation period such as the
    85  	//   startTime, endTime, stake weight, and validator's nodeID.
    86  	// - [rewardsOwner] specifies the owner of all the rewards this delegator
    87  	//   may accrue at the end of its delegation period.
    88  	IssueAddDelegatorTx(
    89  		vdr *txs.Validator,
    90  		rewardsOwner *secp256k1fx.OutputOwners,
    91  		options ...common.Option,
    92  	) (*txs.Tx, error)
    93  
    94  	// IssueCreateChainTx creates, signs, and issues a new chain in the named
    95  	// subnet.
    96  	//
    97  	// - [subnetID] specifies the subnet to launch the chain in.
    98  	// - [genesis] specifies the initial state of the new chain.
    99  	// - [vmID] specifies the vm that the new chain will run.
   100  	// - [fxIDs] specifies all the feature extensions that the vm should be
   101  	//   running with.
   102  	// - [chainName] specifies a human readable name for the chain.
   103  	IssueCreateChainTx(
   104  		subnetID ids.ID,
   105  		genesis []byte,
   106  		vmID ids.ID,
   107  		fxIDs []ids.ID,
   108  		chainName string,
   109  		options ...common.Option,
   110  	) (*txs.Tx, error)
   111  
   112  	// IssueCreateSubnetTx creates, signs, and issues a new subnet with the
   113  	// specified owner.
   114  	//
   115  	// - [owner] specifies who has the ability to create new chains and add new
   116  	//   validators to the subnet.
   117  	IssueCreateSubnetTx(
   118  		owner *secp256k1fx.OutputOwners,
   119  		options ...common.Option,
   120  	) (*txs.Tx, error)
   121  
   122  	// IssueTransferSubnetOwnershipTx creates, signs, and issues a transaction that
   123  	// changes the owner of the named subnet.
   124  	//
   125  	// - [subnetID] specifies the subnet to be modified
   126  	// - [owner] specifies who has the ability to create new chains and add new
   127  	//   validators to the subnet.
   128  	IssueTransferSubnetOwnershipTx(
   129  		subnetID ids.ID,
   130  		owner *secp256k1fx.OutputOwners,
   131  		options ...common.Option,
   132  	) (*txs.Tx, error)
   133  
   134  	// IssueImportTx creates, signs, and issues an import transaction that
   135  	// attempts to consume all the available UTXOs and import the funds to [to].
   136  	//
   137  	// - [chainID] specifies the chain to be importing funds from.
   138  	// - [to] specifies where to send the imported funds to.
   139  	IssueImportTx(
   140  		chainID ids.ID,
   141  		to *secp256k1fx.OutputOwners,
   142  		options ...common.Option,
   143  	) (*txs.Tx, error)
   144  
   145  	// IssueExportTx creates, signs, and issues an export transaction that
   146  	// attempts to send all the provided [outputs] to the requested [chainID].
   147  	//
   148  	// - [chainID] specifies the chain to be exporting the funds to.
   149  	// - [outputs] specifies the outputs to send to the [chainID].
   150  	IssueExportTx(
   151  		chainID ids.ID,
   152  		outputs []*avax.TransferableOutput,
   153  		options ...common.Option,
   154  	) (*txs.Tx, error)
   155  
   156  	// IssueTransformSubnetTx creates a transform subnet transaction that attempts
   157  	// to convert the provided [subnetID] from a permissioned subnet to a
   158  	// permissionless subnet. This transaction will convert
   159  	// [maxSupply] - [initialSupply] of [assetID] to staking rewards.
   160  	//
   161  	// - [subnetID] specifies the subnet to transform.
   162  	// - [assetID] specifies the asset to use to reward stakers on the subnet.
   163  	// - [initialSupply] is the amount of [assetID] that will be in circulation
   164  	//   after this transaction is accepted.
   165  	// - [maxSupply] is the maximum total amount of [assetID] that should ever
   166  	//   exist.
   167  	// - [minConsumptionRate] is the rate that a staker will receive rewards
   168  	//   if they stake with a duration of 0.
   169  	// - [maxConsumptionRate] is the maximum rate that staking rewards should be
   170  	//   consumed from the reward pool per year.
   171  	// - [minValidatorStake] is the minimum amount of funds required to become a
   172  	//   validator.
   173  	// - [maxValidatorStake] is the maximum amount of funds a single validator
   174  	//   can be allocated, including delegated funds.
   175  	// - [minStakeDuration] is the minimum number of seconds a staker can stake
   176  	//   for.
   177  	// - [maxStakeDuration] is the maximum number of seconds a staker can stake
   178  	//   for.
   179  	// - [minValidatorStake] is the minimum amount of funds required to become a
   180  	//   delegator.
   181  	// - [maxValidatorWeightFactor] is the factor which calculates the maximum
   182  	//   amount of delegation a validator can receive. A value of 1 effectively
   183  	//   disables delegation.
   184  	// - [uptimeRequirement] is the minimum percentage a validator must be
   185  	//   online and responsive to receive a reward.
   186  	IssueTransformSubnetTx(
   187  		subnetID ids.ID,
   188  		assetID ids.ID,
   189  		initialSupply uint64,
   190  		maxSupply uint64,
   191  		minConsumptionRate uint64,
   192  		maxConsumptionRate uint64,
   193  		minValidatorStake uint64,
   194  		maxValidatorStake uint64,
   195  		minStakeDuration time.Duration,
   196  		maxStakeDuration time.Duration,
   197  		minDelegationFee uint32,
   198  		minDelegatorStake uint64,
   199  		maxValidatorWeightFactor byte,
   200  		uptimeRequirement uint32,
   201  		options ...common.Option,
   202  	) (*txs.Tx, error)
   203  
   204  	// IssueAddPermissionlessValidatorTx creates, signs, and issues a new
   205  	// validator of the specified subnet.
   206  	//
   207  	// - [vdr] specifies all the details of the validation period such as the
   208  	//   subnetID, startTime, endTime, stake weight, and nodeID.
   209  	// - [signer] if the subnetID is the primary network, this is the BLS key
   210  	//   for this validator. Otherwise, this value should be the empty signer.
   211  	// - [assetID] specifies the asset to stake.
   212  	// - [validationRewardsOwner] specifies the owner of all the rewards this
   213  	//   validator earns for its validation period.
   214  	// - [delegationRewardsOwner] specifies the owner of all the rewards this
   215  	//   validator earns for delegations during its validation period.
   216  	// - [shares] specifies the fraction (out of 1,000,000) that this validator
   217  	//   will take from delegation rewards. If 1,000,000 is provided, 100% of
   218  	//   the delegation reward will be sent to the validator's [rewardsOwner].
   219  	IssueAddPermissionlessValidatorTx(
   220  		vdr *txs.SubnetValidator,
   221  		signer vmsigner.Signer,
   222  		assetID ids.ID,
   223  		validationRewardsOwner *secp256k1fx.OutputOwners,
   224  		delegationRewardsOwner *secp256k1fx.OutputOwners,
   225  		shares uint32,
   226  		options ...common.Option,
   227  	) (*txs.Tx, error)
   228  
   229  	// IssueAddPermissionlessDelegatorTx creates, signs, and issues a new
   230  	// delegator of the specified subnet on the specified nodeID.
   231  	//
   232  	// - [vdr] specifies all the details of the delegation period such as the
   233  	//   subnetID, startTime, endTime, stake weight, and nodeID.
   234  	// - [assetID] specifies the asset to stake.
   235  	// - [rewardsOwner] specifies the owner of all the rewards this delegator
   236  	//   earns during its delegation period.
   237  	IssueAddPermissionlessDelegatorTx(
   238  		vdr *txs.SubnetValidator,
   239  		assetID ids.ID,
   240  		rewardsOwner *secp256k1fx.OutputOwners,
   241  		options ...common.Option,
   242  	) (*txs.Tx, error)
   243  
   244  	// IssueUnsignedTx signs and issues the unsigned tx.
   245  	IssueUnsignedTx(
   246  		utx txs.UnsignedTx,
   247  		options ...common.Option,
   248  	) (*txs.Tx, error)
   249  
   250  	// IssueTx issues the signed tx.
   251  	IssueTx(
   252  		tx *txs.Tx,
   253  		options ...common.Option,
   254  	) error
   255  }
   256  
   257  func NewWallet(
   258  	builder builder.Builder,
   259  	signer walletsigner.Signer,
   260  	client platformvm.Client,
   261  	backend Backend,
   262  ) Wallet {
   263  	return &wallet{
   264  		Backend: backend,
   265  		builder: builder,
   266  		signer:  signer,
   267  		client:  client,
   268  	}
   269  }
   270  
   271  type wallet struct {
   272  	Backend
   273  	builder builder.Builder
   274  	signer  walletsigner.Signer
   275  	client  platformvm.Client
   276  }
   277  
   278  func (w *wallet) Builder() builder.Builder {
   279  	return w.builder
   280  }
   281  
   282  func (w *wallet) Signer() walletsigner.Signer {
   283  	return w.signer
   284  }
   285  
   286  func (w *wallet) IssueBaseTx(
   287  	outputs []*avax.TransferableOutput,
   288  	options ...common.Option,
   289  ) (*txs.Tx, error) {
   290  	utx, err := w.builder.NewBaseTx(outputs, options...)
   291  	if err != nil {
   292  		return nil, err
   293  	}
   294  	return w.IssueUnsignedTx(utx, options...)
   295  }
   296  
   297  func (w *wallet) IssueAddValidatorTx(
   298  	vdr *txs.Validator,
   299  	rewardsOwner *secp256k1fx.OutputOwners,
   300  	shares uint32,
   301  	options ...common.Option,
   302  ) (*txs.Tx, error) {
   303  	utx, err := w.builder.NewAddValidatorTx(vdr, rewardsOwner, shares, options...)
   304  	if err != nil {
   305  		return nil, err
   306  	}
   307  	return w.IssueUnsignedTx(utx, options...)
   308  }
   309  
   310  func (w *wallet) IssueAddSubnetValidatorTx(
   311  	vdr *txs.SubnetValidator,
   312  	options ...common.Option,
   313  ) (*txs.Tx, error) {
   314  	utx, err := w.builder.NewAddSubnetValidatorTx(vdr, options...)
   315  	if err != nil {
   316  		return nil, err
   317  	}
   318  	return w.IssueUnsignedTx(utx, options...)
   319  }
   320  
   321  func (w *wallet) IssueRemoveSubnetValidatorTx(
   322  	nodeID ids.NodeID,
   323  	subnetID ids.ID,
   324  	options ...common.Option,
   325  ) (*txs.Tx, error) {
   326  	utx, err := w.builder.NewRemoveSubnetValidatorTx(nodeID, subnetID, options...)
   327  	if err != nil {
   328  		return nil, err
   329  	}
   330  	return w.IssueUnsignedTx(utx, options...)
   331  }
   332  
   333  func (w *wallet) IssueAddDelegatorTx(
   334  	vdr *txs.Validator,
   335  	rewardsOwner *secp256k1fx.OutputOwners,
   336  	options ...common.Option,
   337  ) (*txs.Tx, error) {
   338  	utx, err := w.builder.NewAddDelegatorTx(vdr, rewardsOwner, options...)
   339  	if err != nil {
   340  		return nil, err
   341  	}
   342  	return w.IssueUnsignedTx(utx, options...)
   343  }
   344  
   345  func (w *wallet) IssueCreateChainTx(
   346  	subnetID ids.ID,
   347  	genesis []byte,
   348  	vmID ids.ID,
   349  	fxIDs []ids.ID,
   350  	chainName string,
   351  	options ...common.Option,
   352  ) (*txs.Tx, error) {
   353  	utx, err := w.builder.NewCreateChainTx(subnetID, genesis, vmID, fxIDs, chainName, options...)
   354  	if err != nil {
   355  		return nil, err
   356  	}
   357  	return w.IssueUnsignedTx(utx, options...)
   358  }
   359  
   360  func (w *wallet) IssueCreateSubnetTx(
   361  	owner *secp256k1fx.OutputOwners,
   362  	options ...common.Option,
   363  ) (*txs.Tx, error) {
   364  	utx, err := w.builder.NewCreateSubnetTx(owner, options...)
   365  	if err != nil {
   366  		return nil, err
   367  	}
   368  	return w.IssueUnsignedTx(utx, options...)
   369  }
   370  
   371  func (w *wallet) IssueTransferSubnetOwnershipTx(
   372  	subnetID ids.ID,
   373  	owner *secp256k1fx.OutputOwners,
   374  	options ...common.Option,
   375  ) (*txs.Tx, error) {
   376  	utx, err := w.builder.NewTransferSubnetOwnershipTx(subnetID, owner, options...)
   377  	if err != nil {
   378  		return nil, err
   379  	}
   380  	return w.IssueUnsignedTx(utx, options...)
   381  }
   382  
   383  func (w *wallet) IssueImportTx(
   384  	sourceChainID ids.ID,
   385  	to *secp256k1fx.OutputOwners,
   386  	options ...common.Option,
   387  ) (*txs.Tx, error) {
   388  	utx, err := w.builder.NewImportTx(sourceChainID, to, options...)
   389  	if err != nil {
   390  		return nil, err
   391  	}
   392  	return w.IssueUnsignedTx(utx, options...)
   393  }
   394  
   395  func (w *wallet) IssueExportTx(
   396  	chainID ids.ID,
   397  	outputs []*avax.TransferableOutput,
   398  	options ...common.Option,
   399  ) (*txs.Tx, error) {
   400  	utx, err := w.builder.NewExportTx(chainID, outputs, options...)
   401  	if err != nil {
   402  		return nil, err
   403  	}
   404  	return w.IssueUnsignedTx(utx, options...)
   405  }
   406  
   407  func (w *wallet) IssueTransformSubnetTx(
   408  	subnetID ids.ID,
   409  	assetID ids.ID,
   410  	initialSupply uint64,
   411  	maxSupply uint64,
   412  	minConsumptionRate uint64,
   413  	maxConsumptionRate uint64,
   414  	minValidatorStake uint64,
   415  	maxValidatorStake uint64,
   416  	minStakeDuration time.Duration,
   417  	maxStakeDuration time.Duration,
   418  	minDelegationFee uint32,
   419  	minDelegatorStake uint64,
   420  	maxValidatorWeightFactor byte,
   421  	uptimeRequirement uint32,
   422  	options ...common.Option,
   423  ) (*txs.Tx, error) {
   424  	utx, err := w.builder.NewTransformSubnetTx(
   425  		subnetID,
   426  		assetID,
   427  		initialSupply,
   428  		maxSupply,
   429  		minConsumptionRate,
   430  		maxConsumptionRate,
   431  		minValidatorStake,
   432  		maxValidatorStake,
   433  		minStakeDuration,
   434  		maxStakeDuration,
   435  		minDelegationFee,
   436  		minDelegatorStake,
   437  		maxValidatorWeightFactor,
   438  		uptimeRequirement,
   439  		options...,
   440  	)
   441  	if err != nil {
   442  		return nil, err
   443  	}
   444  	return w.IssueUnsignedTx(utx, options...)
   445  }
   446  
   447  func (w *wallet) IssueAddPermissionlessValidatorTx(
   448  	vdr *txs.SubnetValidator,
   449  	signer vmsigner.Signer,
   450  	assetID ids.ID,
   451  	validationRewardsOwner *secp256k1fx.OutputOwners,
   452  	delegationRewardsOwner *secp256k1fx.OutputOwners,
   453  	shares uint32,
   454  	options ...common.Option,
   455  ) (*txs.Tx, error) {
   456  	utx, err := w.builder.NewAddPermissionlessValidatorTx(
   457  		vdr,
   458  		signer,
   459  		assetID,
   460  		validationRewardsOwner,
   461  		delegationRewardsOwner,
   462  		shares,
   463  		options...,
   464  	)
   465  	if err != nil {
   466  		return nil, err
   467  	}
   468  	return w.IssueUnsignedTx(utx, options...)
   469  }
   470  
   471  func (w *wallet) IssueAddPermissionlessDelegatorTx(
   472  	vdr *txs.SubnetValidator,
   473  	assetID ids.ID,
   474  	rewardsOwner *secp256k1fx.OutputOwners,
   475  	options ...common.Option,
   476  ) (*txs.Tx, error) {
   477  	utx, err := w.builder.NewAddPermissionlessDelegatorTx(
   478  		vdr,
   479  		assetID,
   480  		rewardsOwner,
   481  		options...,
   482  	)
   483  	if err != nil {
   484  		return nil, err
   485  	}
   486  	return w.IssueUnsignedTx(utx, options...)
   487  }
   488  
   489  func (w *wallet) IssueUnsignedTx(
   490  	utx txs.UnsignedTx,
   491  	options ...common.Option,
   492  ) (*txs.Tx, error) {
   493  	ops := common.NewOptions(options)
   494  	ctx := ops.Context()
   495  	tx, err := walletsigner.SignUnsigned(ctx, w.signer, utx)
   496  	if err != nil {
   497  		return nil, err
   498  	}
   499  
   500  	return tx, w.IssueTx(tx, options...)
   501  }
   502  
   503  func (w *wallet) IssueTx(
   504  	tx *txs.Tx,
   505  	options ...common.Option,
   506  ) error {
   507  	ops := common.NewOptions(options)
   508  	ctx := ops.Context()
   509  	txID, err := w.client.IssueTx(ctx, tx.Bytes())
   510  	if err != nil {
   511  		return err
   512  	}
   513  
   514  	if f := ops.PostIssuanceFunc(); f != nil {
   515  		f(txID)
   516  	}
   517  
   518  	if ops.AssumeDecided() {
   519  		return w.Backend.AcceptTx(ctx, tx)
   520  	}
   521  
   522  	if err := platformvm.AwaitTxAccepted(w.client, ctx, txID, ops.PollFrequency()); err != nil {
   523  		return err
   524  	}
   525  
   526  	return w.Backend.AcceptTx(ctx, tx)
   527  }