code.vegaprotocol.io/vega@v0.79.0/cmd/vega/commands/bridge/erc20.go (about)

     1  // Copyright (C) 2023 Gobalsky Labs Limited
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15  
    16  package bridge
    17  
    18  import (
    19  	"errors"
    20  	"fmt"
    21  	"sort"
    22  	"time"
    23  
    24  	"code.vegaprotocol.io/vega/core/bridges"
    25  	"code.vegaprotocol.io/vega/core/config"
    26  	"code.vegaprotocol.io/vega/core/nodewallets"
    27  	"code.vegaprotocol.io/vega/libs/num"
    28  	"code.vegaprotocol.io/vega/paths"
    29  
    30  	"github.com/jessevdk/go-flags"
    31  )
    32  
    33  type ERC20Cmd struct {
    34  	config.VegaHomeFlag
    35  	config.PassphraseFlag
    36  	PrivateKey string `description:"A ethereum private key to be use to sign the messages"                                         long:"private-key" required:"false"`
    37  	ChainID    string `description:"The chain-id of the EVM bridge. Not required if generating signatures for the Ethereum bridge" long:"chain-id"    required:"false"`
    38  
    39  	AddSigner              ERC20AddSignerCmd              `command:"add_signer"                description:"Create signature to add a new signer to the erc20 bridge"`
    40  	RemoveSigner           ERC20RemoveSignerCmd           `command:"remove_signer"             description:"Create signature to remove a signer from the erc20 bridge"`
    41  	SetThreshold           ERC20SetThresholdCmd           `command:"set_threshold"             description:"Create signature to change the threshold of required signature to apply changes to the bridge"`
    42  	BurnNonce              ERC20BurnNonceCmd              `command:"burn_nonce"                description:"Create signature to burn and existing nonce in order to prevent it to be used on the bridge"`
    43  	ListAsset              ERC20ListAssetCmd              `command:"list_asset"                description:"Add a new erc20 asset to the erc20 bridge"`
    44  	VerifyListAsset        ERC20VerifyListAssetCmd        `command:"verify_list_asset"         description:"Verify signatures to add a new erc20 asset to the erc20 bridge"`
    45  	RemoveAsset            ERC20RemoveAssetCmd            `command:"remove_asset"              description:"Remove an erc20 asset from the erc20 bridge"`
    46  	WithdrawAsset          ERC20WithdrawAssetCmd          `command:"withdraw_asset"            description:"Withdraw ERC20 from the bridge"`
    47  	VerifyWithdrawAsset    ERC20VerifyWithdrawAssetCmd    `command:"verify_withdraw_asset"     description:"Verify withdraw ERC20 from the bridge"`
    48  	SetBridgeAddress       ERC20SetBridgeAddressCmd       `command:"set_bridge_address"        description:"Update the bridge address use by the asset pool"`
    49  	SetMultisigControl     ERC20SetMultisigControlCmd     `command:"set_multisig_control"      description:"Update the bridge address use by the asset pool"`
    50  	VerifyGlobalResume     ERC20VerifyGlobalResumeCmd     `command:"verify_global_resume"      description:"Verify the signature to resume usage of the bridge"`
    51  	GlobalResume           ERC20GlobalResumeCmd           `command:"global_resume"             description:"Build the signature to resume usage of the bridge"`
    52  	GlobalStop             ERC20GlobalStopCmd             `command:"global_stop"               description:"Build the signature to stop the bridge"`
    53  	SetWithdrawDelay       ERC20SetWithdrawDelayCmd       `command:"set_withdraw_delay"        description:"Update the withdraw delay for all asset"`
    54  	VerifySetWithdrawDelay ERC20VerifySetWithdrawDelayCmd `command:"verify_set_withdraw_delay" description:"Verify signatures to update the withdraw delay for all asset"`
    55  	SetAssetLimits         ERC20SetAssetLimitsCmd         `command:"set_asset_limits"          description:"Update the limits for an asset"`
    56  	VerifySetAssetLimits   ERC20VerifySetAssetLimitsCmd   `command:"verify_set_asset_limits"   description:"Verify signatures to update the limits for an asset"`
    57  }
    58  
    59  var erc20Cmd *ERC20Cmd
    60  
    61  func (e *ERC20Cmd) GetSigner() (bridges.Signer, error) {
    62  	if len(e.PrivateKey) <= 0 {
    63  		pass, err := erc20Cmd.PassphraseFile.Get("node wallet", false)
    64  		if err != nil {
    65  			return nil, err
    66  		}
    67  
    68  		vegaPaths := paths.New(e.VegaHome)
    69  
    70  		if _, _, err := config.EnsureNodeConfig(vegaPaths); err != nil {
    71  			return nil, err
    72  		}
    73  
    74  		s, err := nodewallets.GetEthereumWallet(vegaPaths, pass)
    75  		if err != nil {
    76  			return nil, fmt.Errorf("couldn't get Ethereum node wallet: %w", err)
    77  		}
    78  
    79  		return s, nil
    80  	}
    81  
    82  	s, err := NewPrivKeySigner(e.PrivateKey)
    83  	if err != nil {
    84  		return nil, fmt.Errorf("couldn't load private key: %w", err)
    85  	}
    86  
    87  	return s, nil
    88  }
    89  
    90  func ERC20() *ERC20Cmd {
    91  	erc20Cmd = &ERC20Cmd{
    92  		AddSigner:              ERC20AddSignerCmd{},
    93  		RemoveSigner:           ERC20RemoveSignerCmd{},
    94  		SetThreshold:           ERC20SetThresholdCmd{},
    95  		ListAsset:              ERC20ListAssetCmd{},
    96  		VerifyListAsset:        ERC20VerifyListAssetCmd{},
    97  		RemoveAsset:            ERC20RemoveAssetCmd{},
    98  		WithdrawAsset:          ERC20WithdrawAssetCmd{},
    99  		VerifyWithdrawAsset:    ERC20VerifyWithdrawAssetCmd{},
   100  		SetAssetLimits:         ERC20SetAssetLimitsCmd{},
   101  		VerifySetAssetLimits:   ERC20VerifySetAssetLimitsCmd{},
   102  		SetBridgeAddress:       ERC20SetBridgeAddressCmd{},
   103  		SetMultisigControl:     ERC20SetMultisigControlCmd{},
   104  		VerifyGlobalResume:     ERC20VerifyGlobalResumeCmd{},
   105  		GlobalResume:           ERC20GlobalResumeCmd{},
   106  		GlobalStop:             ERC20GlobalStopCmd{},
   107  		SetWithdrawDelay:       ERC20SetWithdrawDelayCmd{},
   108  		VerifySetWithdrawDelay: ERC20VerifySetWithdrawDelayCmd{},
   109  		BurnNonce:              ERC20BurnNonceCmd{},
   110  	}
   111  	return erc20Cmd
   112  }
   113  
   114  type ERC20WithdrawAssetCmd struct {
   115  	TokenAddress    string `description:"The Ethereum address of the new token"                                long:"token-address"    required:"true"`
   116  	Amount          string `description:"The amount to be withdrawn"                                           long:"amount"           required:"true"`
   117  	ReceiverAddress string `description:"The ethereum address of the wallet which is to receive the funds"     long:"receiver-address" required:"true"`
   118  	BridgeAddress   string `description:"The address of the vega bridge this transaction will be submitted to" long:"bridge-address"   required:"true"`
   119  	Nonce           string `description:"A nonce for this signature"                                           long:"nonce"            required:"true"`
   120  	Creation        int64  `description:"creation time of the withdrawal (timestamp)"                          long:"creation"         required:"true"`
   121  }
   122  
   123  func (opts *ERC20WithdrawAssetCmd) Execute(_ []string) error {
   124  	if _, err := flags.NewParser(opts, flags.Default|flags.IgnoreUnknown).Parse(); err != nil {
   125  		return err
   126  	}
   127  
   128  	w, err := erc20Cmd.GetSigner()
   129  	if err != nil {
   130  		return err
   131  	}
   132  
   133  	nonce, overflowed := num.UintFromString(opts.Nonce, 10)
   134  	if overflowed {
   135  		return errors.New("invalid nonce, needs to be base 10")
   136  	}
   137  
   138  	amount, overflowed := num.UintFromString(opts.Amount, 10)
   139  	if overflowed {
   140  		return errors.New("invalid amount, needs to be base 10")
   141  	}
   142  
   143  	creation := time.Unix(opts.Creation, 0)
   144  
   145  	erc20Logic := bridges.NewERC20Logic(w, opts.BridgeAddress, erc20Cmd.ChainID, erc20Cmd.ChainID == "")
   146  	bundle, err := erc20Logic.WithdrawAsset(
   147  		opts.TokenAddress, amount, opts.ReceiverAddress, creation, nonce,
   148  	)
   149  	if err != nil {
   150  		return fmt.Errorf("unable to generate signature: %w", err)
   151  	}
   152  
   153  	fmt.Printf("0x%v\n", bundle.Signature.Hex())
   154  	return nil
   155  }
   156  
   157  type ERC20VerifyWithdrawAssetCmd struct {
   158  	TokenAddress    string `description:"The Ethereum address of the new token"                                long:"token-address"    required:"true"`
   159  	Amount          string `description:"The amount to be withdrawn"                                           long:"amount"           required:"true"`
   160  	ReceiverAddress string `description:"The ethereum address of the wallet which is to receive the funds"     long:"receiver-address" required:"true"`
   161  	BridgeAddress   string `description:"The address of the vega bridge this transaction will be submitted to" long:"bridge-address"   required:"true"`
   162  	Nonce           string `description:"A nonce for this signature"                                           long:"nonce"            required:"true"`
   163  	Creation        int64  `description:"creation time of the withdrawal (timestamp)"                          long:"creation"         required:"true"`
   164  	Signatures      string `description:"signatures of the withdrawal"                                         long:"signatures"       required:"true"`
   165  }
   166  
   167  func (opts *ERC20VerifyWithdrawAssetCmd) Execute(_ []string) error {
   168  	if _, err := flags.NewParser(opts, flags.Default|flags.IgnoreUnknown).Parse(); err != nil {
   169  		return err
   170  	}
   171  
   172  	nonce, overflowed := num.UintFromString(opts.Nonce, 10)
   173  	if overflowed {
   174  		return errors.New("invalid nonce, needs to be base 10")
   175  	}
   176  
   177  	amount, overflowed := num.UintFromString(opts.Amount, 10)
   178  	if overflowed {
   179  		return errors.New("invalid amount, needs to be base 10")
   180  	}
   181  
   182  	creation := time.Unix(opts.Creation, 0)
   183  
   184  	if len(opts.Signatures) <= 0 {
   185  		return errors.New("missing signatures")
   186  	}
   187  
   188  	if (len(opts.Signatures)-2)%130 != 0 {
   189  		return errors.New("invalid signatures format")
   190  	}
   191  
   192  	erc20Logic := bridges.NewERC20Logic(nil, opts.BridgeAddress, erc20Cmd.ChainID, erc20Cmd.ChainID == "")
   193  	addresses, err := erc20Logic.VerifyWithdrawAsset(
   194  		opts.TokenAddress, amount, opts.ReceiverAddress, creation, nonce, opts.Signatures,
   195  	)
   196  	if err != nil {
   197  		return fmt.Errorf("unable to generate signature: %w", err)
   198  	}
   199  
   200  	sort.Strings(addresses)
   201  	for _, v := range addresses {
   202  		fmt.Printf("%v\n", v)
   203  	}
   204  	return nil
   205  }
   206  
   207  type ERC20ListAssetCmd struct {
   208  	TokenAddress      string `description:"The Ethereum address of the new token"                                long:"token-address"      required:"true"`
   209  	VegaAssetID       string `description:"The vega ID for this new token"                                       long:"vega-asset-id"      required:"true"`
   210  	BridgeAddress     string `description:"The address of the vega bridge this transaction will be submitted to" long:"bridge-address"     required:"true"`
   211  	Nonce             string `description:"A nonce for this signature"                                           long:"nonce"              required:"true"`
   212  	LifetimeLimit     string `description:"The lifetime deposit limit for the asset"                             long:"lifetime-limit"     required:"true"`
   213  	WithdrawThreshold string `description:"The withdrawal threshold for this asset"                              long:"withdraw-threshold" required:"true"`
   214  }
   215  
   216  func (opts *ERC20ListAssetCmd) Execute(_ []string) error {
   217  	if _, err := flags.NewParser(opts, flags.Default|flags.IgnoreUnknown).Parse(); err != nil {
   218  		return err
   219  	}
   220  
   221  	w, err := erc20Cmd.GetSigner()
   222  	if err != nil {
   223  		return err
   224  	}
   225  
   226  	nonce, overflowed := num.UintFromString(opts.Nonce, 10)
   227  	if overflowed {
   228  		return errors.New("invalid nonce, needs to be base 10")
   229  	}
   230  	lifetimeLimit, overflowed := num.UintFromString(opts.LifetimeLimit, 10)
   231  	if overflowed {
   232  		return errors.New("invalid lifetime-limit, needs to be base 10")
   233  	}
   234  	withdrawThreshod, overflowed := num.UintFromString(opts.WithdrawThreshold, 10)
   235  	if overflowed {
   236  		return errors.New("invalid withdraw-threshold, needs to be base 10")
   237  	}
   238  
   239  	erc20Logic := bridges.NewERC20Logic(w, opts.BridgeAddress, erc20Cmd.ChainID, erc20Cmd.ChainID == "")
   240  	bundle, err := erc20Logic.ListAsset(
   241  		opts.TokenAddress, opts.VegaAssetID, lifetimeLimit, withdrawThreshod, nonce,
   242  	)
   243  	if err != nil {
   244  		return fmt.Errorf("unable to generate signature: %w", err)
   245  	}
   246  
   247  	fmt.Printf("0x%v\n", bundle.Signature.Hex())
   248  	return nil
   249  }
   250  
   251  type ERC20VerifyListAssetCmd struct {
   252  	TokenAddress      string `description:"The Ethereum address of the new token"                                long:"token-address"      required:"true"`
   253  	VegaAssetID       string `description:"The vega ID for this new token"                                       long:"vega-asset-id"      required:"true"`
   254  	BridgeAddress     string `description:"The address of the vega bridge this transaction will be submitted to" long:"bridge-address"     required:"true"`
   255  	Nonce             string `description:"A nonce for this signature"                                           long:"nonce"              required:"true"`
   256  	LifetimeLimit     string `description:"The lifetime deposit limit for the asset"                             long:"lifetime-limit"     required:"true"`
   257  	WithdrawThreshold string `description:"The withdrawal threshold for this asset"                              long:"withdraw-threshold" required:"true"`
   258  	Signatures        string `description:"The signature bundle to verify"                                       long:"signatures"         required:"true"`
   259  }
   260  
   261  func (opts *ERC20VerifyListAssetCmd) Execute(_ []string) error {
   262  	if _, err := flags.NewParser(opts, flags.Default|flags.IgnoreUnknown).Parse(); err != nil {
   263  		return err
   264  	}
   265  
   266  	nonce, overflowed := num.UintFromString(opts.Nonce, 10)
   267  	if overflowed {
   268  		return errors.New("invalid nonce, needs to be base 10")
   269  	}
   270  	lifetimeLimit, overflowed := num.UintFromString(opts.LifetimeLimit, 10)
   271  	if overflowed {
   272  		return errors.New("invalid lifetime-limit, needs to be base 10")
   273  	}
   274  	withdrawThreshod, overflowed := num.UintFromString(opts.WithdrawThreshold, 10)
   275  	if overflowed {
   276  		return errors.New("invalid withdraw-threshold, needs to be base 10")
   277  	}
   278  
   279  	if len(opts.Signatures) <= 0 {
   280  		return errors.New("missing signatures")
   281  	}
   282  
   283  	if (len(opts.Signatures)-2)%130 != 0 {
   284  		return errors.New("invalid signatures format")
   285  	}
   286  
   287  	erc20Logic := bridges.NewERC20Logic(nil, opts.BridgeAddress, erc20Cmd.ChainID, erc20Cmd.ChainID == "")
   288  	addresses, err := erc20Logic.VerifyListAsset(
   289  		opts.TokenAddress, opts.VegaAssetID, lifetimeLimit, withdrawThreshod, nonce, opts.Signatures,
   290  	)
   291  	if err != nil {
   292  		return fmt.Errorf("unable to generate signature: %w", err)
   293  	}
   294  
   295  	sort.Strings(addresses)
   296  	for _, v := range addresses {
   297  		fmt.Printf("%v\n", v)
   298  	}
   299  	return nil
   300  }
   301  
   302  type ERC20RemoveAssetCmd struct {
   303  	TokenAddress  string `description:"The Ethereum address of the new token"                                long:"token-address"  required:"true"`
   304  	BridgeAddress string `description:"The address of the vega bridge this transaction will be submitted to" long:"bridge-address" required:"true"`
   305  	Nonce         string `description:"A nonce for this signature"                                           long:"nonce"          required:"true"`
   306  }
   307  
   308  func (opts *ERC20RemoveAssetCmd) Execute(_ []string) error {
   309  	if _, err := flags.NewParser(opts, flags.Default|flags.IgnoreUnknown).Parse(); err != nil {
   310  		return err
   311  	}
   312  
   313  	w, err := erc20Cmd.GetSigner()
   314  	if err != nil {
   315  		return err
   316  	}
   317  
   318  	nonce, overflowed := num.UintFromString(opts.Nonce, 10)
   319  	if overflowed {
   320  		return errors.New("invalid nonce, needs to be base 10")
   321  	}
   322  
   323  	erc20Logic := bridges.NewERC20Logic(w, opts.BridgeAddress, erc20Cmd.ChainID, erc20Cmd.ChainID == "")
   324  	bundle, err := erc20Logic.RemoveAsset(
   325  		opts.TokenAddress, nonce,
   326  	)
   327  	if err != nil {
   328  		return fmt.Errorf("unable to generate signature: %w", err)
   329  	}
   330  
   331  	fmt.Printf("0x%v\n", bundle.Signature.Hex())
   332  	return nil
   333  }
   334  
   335  type ERC20AddSignerCmd struct {
   336  	NewSigner string `description:"Ethereum address of the new signer"                   long:"new-signer" required:"true"`
   337  	Submitter string `description:"Ethereum address of the submitter of the transaction" long:"submitter"  required:"true"`
   338  	Nonce     string `description:"A nonce for this signature"                           long:"nonce"      required:"true"`
   339  }
   340  
   341  func (opts *ERC20AddSignerCmd) Execute(_ []string) error {
   342  	if _, err := flags.NewParser(opts, flags.Default|flags.IgnoreUnknown).Parse(); err != nil {
   343  		return err
   344  	}
   345  
   346  	w, err := erc20Cmd.GetSigner()
   347  	if err != nil {
   348  		return err
   349  	}
   350  
   351  	nonce, overflowed := num.UintFromString(opts.Nonce, 10)
   352  	if overflowed {
   353  		return errors.New("invalid nonce, needs to be base 10")
   354  	}
   355  
   356  	multiSigControl := bridges.NewERC20MultiSigControl(w, erc20Cmd.ChainID, erc20Cmd.ChainID == "")
   357  	bundle, err := multiSigControl.AddSigner(
   358  		opts.NewSigner, opts.Submitter, nonce,
   359  	)
   360  	if err != nil {
   361  		return fmt.Errorf("unable to generate signature: %w", err)
   362  	}
   363  
   364  	fmt.Printf("0x%v\n", bundle.Signature.Hex())
   365  	return nil
   366  }
   367  
   368  type ERC20RemoveSignerCmd struct {
   369  	OldSigner string `description:"Ethereum address of signer to remove"                 long:"old-signer" required:"true"`
   370  	Submitter string `description:"Ethereum address of the submitter of the transaction" long:"submitter"  required:"true"`
   371  	Nonce     string `description:"A nonce for this signature"                           long:"nonce"      required:"true"`
   372  }
   373  
   374  func (opts *ERC20RemoveSignerCmd) Execute(_ []string) error {
   375  	if _, err := flags.NewParser(opts, flags.Default|flags.IgnoreUnknown).Parse(); err != nil {
   376  		return err
   377  	}
   378  
   379  	w, err := erc20Cmd.GetSigner()
   380  	if err != nil {
   381  		return err
   382  	}
   383  
   384  	nonce, overflowed := num.UintFromString(opts.Nonce, 10)
   385  	if overflowed {
   386  		return errors.New("invalid nonce, needs to be base 10")
   387  	}
   388  
   389  	multiSigControl := bridges.NewERC20MultiSigControl(w, erc20Cmd.ChainID, erc20Cmd.ChainID == "")
   390  	bundle, err := multiSigControl.RemoveSigner(
   391  		opts.OldSigner, opts.Submitter, nonce,
   392  	)
   393  	if err != nil {
   394  		return fmt.Errorf("unable to generate signature: %w", err)
   395  	}
   396  
   397  	fmt.Printf("0x%v\n", bundle.Signature.Hex())
   398  	return nil
   399  }
   400  
   401  type ERC20SetThresholdCmd struct {
   402  	NewThreshold uint16 `description:"The new threshold to be used on the bridge"           long:"new-threshold" required:"true"`
   403  	Submitter    string `description:"Ethereum address of the submitter of the transaction" long:"submitter"     required:"true"`
   404  	Nonce        string `description:"A nonce for this signature"                           long:"nonce"         required:"true"`
   405  }
   406  
   407  func (opts *ERC20SetThresholdCmd) Execute(_ []string) error {
   408  	if _, err := flags.NewParser(opts, flags.Default|flags.IgnoreUnknown).Parse(); err != nil {
   409  		return err
   410  	}
   411  
   412  	w, err := erc20Cmd.GetSigner()
   413  	if err != nil {
   414  		return err
   415  	}
   416  
   417  	if opts.NewThreshold == 0 || opts.NewThreshold > 1000 {
   418  		return fmt.Errorf("invalid new threshold, required to be > 0 and <= 1000, got %d", opts.NewThreshold)
   419  	}
   420  
   421  	nonce, overflowed := num.UintFromString(opts.Nonce, 10)
   422  	if overflowed {
   423  		return errors.New("invalid nonce, needs to be base 10 and not overflow")
   424  	}
   425  
   426  	multiSigControl := bridges.NewERC20MultiSigControl(w, erc20Cmd.ChainID, erc20Cmd.ChainID == "")
   427  	bundle, err := multiSigControl.SetThreshold(
   428  		opts.NewThreshold, opts.Submitter, nonce,
   429  	)
   430  	if err != nil {
   431  		return fmt.Errorf("unable to generate signature: %w", err)
   432  	}
   433  
   434  	fmt.Printf("0x%v\n", bundle.Signature.Hex())
   435  	return nil
   436  }
   437  
   438  type ERC20BurnNonceCmd struct {
   439  	Submitter string `description:"Ethereum address of the submitter of the transaction" long:"submitter" required:"true"`
   440  	Nonce     string `description:"A nonce for this signature"                           long:"nonce"     required:"true"`
   441  }
   442  
   443  func (opts *ERC20BurnNonceCmd) Execute(_ []string) error {
   444  	if _, err := flags.NewParser(opts, flags.Default|flags.IgnoreUnknown).Parse(); err != nil {
   445  		return err
   446  	}
   447  
   448  	w, err := erc20Cmd.GetSigner()
   449  	if err != nil {
   450  		return err
   451  	}
   452  
   453  	nonce, overflowed := num.UintFromString(opts.Nonce, 10)
   454  	if overflowed {
   455  		return errors.New("invalid nonce, needs to be base 10 and not overflow")
   456  	}
   457  
   458  	multiSigControl := bridges.NewERC20MultiSigControl(w, erc20Cmd.ChainID, erc20Cmd.ChainID == "")
   459  	bundle, err := multiSigControl.BurnNonce(opts.Submitter, nonce)
   460  	if err != nil {
   461  		return fmt.Errorf("unable to generate signature: %w", err)
   462  	}
   463  
   464  	fmt.Printf("0x%v\n", bundle.Signature.Hex())
   465  	return nil
   466  }
   467  
   468  type ERC20SetBridgeAddressCmd struct {
   469  	NewAddress       string `description:"The Ethereum address of the bridge"                                       long:"new-address"        required:"true"`
   470  	AssetPoolAddress string `description:"The address of the vega asset pool this transaction will be submitted to" long:"asset-pool-address" required:"true"`
   471  	Nonce            string `description:"A nonce for this signature"                                               long:"nonce"              required:"true"`
   472  }
   473  
   474  func (opts *ERC20SetBridgeAddressCmd) Execute(_ []string) error {
   475  	if _, err := flags.NewParser(opts, flags.Default|flags.IgnoreUnknown).Parse(); err != nil {
   476  		return err
   477  	}
   478  
   479  	w, err := erc20Cmd.GetSigner()
   480  	if err != nil {
   481  		return err
   482  	}
   483  
   484  	nonce, overflowed := num.UintFromString(opts.Nonce, 10)
   485  	if overflowed {
   486  		return errors.New("invalid nonce, needs to be base 10")
   487  	}
   488  
   489  	erc20Logic := bridges.NewERC20AssetPool(w, opts.AssetPoolAddress, erc20Cmd.ChainID, erc20Cmd.ChainID == "")
   490  	bundle, err := erc20Logic.SetBridgeAddress(
   491  		opts.NewAddress, nonce,
   492  	)
   493  	if err != nil {
   494  		return fmt.Errorf("unable to generate signature: %w", err)
   495  	}
   496  
   497  	fmt.Printf("0x%v\n", bundle.Signature.Hex())
   498  	return nil
   499  }
   500  
   501  type ERC20SetMultisigControlCmd struct {
   502  	NewAddress       string `description:"The Ethereum address of the bridge"                                       long:"new-address"        required:"true"`
   503  	AssetPoolAddress string `description:"The address of the vega asset pool this transaction will be submitted to" long:"asset-pool-address" required:"true"`
   504  	Nonce            string `description:"A nonce for this signature"                                               long:"nonce"              required:"true"`
   505  }
   506  
   507  func (opts *ERC20SetMultisigControlCmd) Execute(_ []string) error {
   508  	if _, err := flags.NewParser(opts, flags.Default|flags.IgnoreUnknown).Parse(); err != nil {
   509  		return err
   510  	}
   511  
   512  	w, err := erc20Cmd.GetSigner()
   513  	if err != nil {
   514  		return err
   515  	}
   516  
   517  	nonce, overflowed := num.UintFromString(opts.Nonce, 10)
   518  	if overflowed {
   519  		return errors.New("invalid nonce, needs to be base 10")
   520  	}
   521  
   522  	erc20Logic := bridges.NewERC20AssetPool(w, opts.AssetPoolAddress, erc20Cmd.ChainID, erc20Cmd.ChainID == "")
   523  	bundle, err := erc20Logic.SetMultiSigControl(
   524  		opts.NewAddress, nonce,
   525  	)
   526  	if err != nil {
   527  		return fmt.Errorf("unable to generate signature: %w", err)
   528  	}
   529  
   530  	fmt.Printf("0x%v\n", bundle.Signature.Hex())
   531  	return nil
   532  }
   533  
   534  type ERC20GlobalStopCmd struct {
   535  	Nonce         string `description:"A nonce for this signature"                                           long:"nonce"          required:"true"`
   536  	BridgeAddress string `description:"The address of the vega bridge this transaction will be submitted to" long:"bridge-address" required:"true"`
   537  }
   538  
   539  func (opts *ERC20GlobalStopCmd) Execute(_ []string) error {
   540  	if _, err := flags.NewParser(opts, flags.Default|flags.IgnoreUnknown).Parse(); err != nil {
   541  		return err
   542  	}
   543  
   544  	w, err := erc20Cmd.GetSigner()
   545  	if err != nil {
   546  		return err
   547  	}
   548  
   549  	nonce, overflowed := num.UintFromString(opts.Nonce, 10)
   550  	if overflowed {
   551  		return errors.New("invalid nonce, needs to be base 10 and not overflow")
   552  	}
   553  
   554  	erc20 := bridges.NewERC20Logic(w, opts.BridgeAddress, erc20Cmd.ChainID, erc20Cmd.ChainID == "")
   555  	bundle, err := erc20.GlobalStop(
   556  		nonce,
   557  	)
   558  	if err != nil {
   559  		return fmt.Errorf("unable to generate signature: %w", err)
   560  	}
   561  
   562  	fmt.Printf("0x%v\n", bundle.Signature.Hex())
   563  	return nil
   564  }
   565  
   566  type ERC20GlobalResumeCmd struct {
   567  	Nonce         string `description:"A nonce for this signature"                                           long:"nonce"          required:"true"`
   568  	BridgeAddress string `description:"The address of the vega bridge this transaction will be submitted to" long:"bridge-address" required:"true"`
   569  }
   570  
   571  func (opts *ERC20GlobalResumeCmd) Execute(_ []string) error {
   572  	if _, err := flags.NewParser(opts, flags.Default|flags.IgnoreUnknown).Parse(); err != nil {
   573  		return err
   574  	}
   575  
   576  	w, err := erc20Cmd.GetSigner()
   577  	if err != nil {
   578  		return err
   579  	}
   580  
   581  	nonce, overflowed := num.UintFromString(opts.Nonce, 10)
   582  	if overflowed {
   583  		return errors.New("invalid nonce, needs to be base 10 and not overflow")
   584  	}
   585  
   586  	erc20 := bridges.NewERC20Logic(w, opts.BridgeAddress, erc20Cmd.ChainID, erc20Cmd.ChainID == "")
   587  	bundle, err := erc20.GlobalResume(
   588  		nonce,
   589  	)
   590  	if err != nil {
   591  		return fmt.Errorf("unable to generate signature: %w", err)
   592  	}
   593  
   594  	fmt.Printf("0x%v\n", bundle.Signature.Hex())
   595  	return nil
   596  }
   597  
   598  type ERC20VerifyGlobalResumeCmd struct {
   599  	Nonce         string `description:"A nonce for this signature"                                           long:"nonce"          required:"true"`
   600  	BridgeAddress string `description:"The address of the vega bridge this transaction will be submitted to" long:"bridge-address" required:"true"`
   601  	Signatures    string `description:"The list of signatures from the validators"                           long:"signatures"     required:"true"`
   602  }
   603  
   604  func (opts *ERC20VerifyGlobalResumeCmd) Execute(_ []string) error {
   605  	if _, err := flags.NewParser(opts, flags.Default|flags.IgnoreUnknown).Parse(); err != nil {
   606  		return err
   607  	}
   608  
   609  	nonce, overflowed := num.UintFromString(opts.Nonce, 10)
   610  	if overflowed {
   611  		return errors.New("invalid nonce, needs to be base 10 and not overflow")
   612  	}
   613  
   614  	if len(opts.Signatures) <= 0 {
   615  		return errors.New("missing signatures")
   616  	}
   617  
   618  	if (len(opts.Signatures)-2)%130 != 0 {
   619  		return errors.New("invalid signatures format")
   620  	}
   621  
   622  	erc20 := bridges.NewERC20Logic(nil, opts.BridgeAddress, erc20Cmd.ChainID, erc20Cmd.ChainID == "")
   623  	signers, err := erc20.VerifyGlobalResume(
   624  		nonce, opts.Signatures,
   625  	)
   626  	if err != nil {
   627  		return fmt.Errorf("unable to generate signature: %w", err)
   628  	}
   629  
   630  	sort.Strings(signers)
   631  	for _, v := range signers {
   632  		fmt.Printf("%v\n", v)
   633  	}
   634  	return nil
   635  }
   636  
   637  type ERC20SetAssetLimitsCmd struct {
   638  	WithdrawThreshold      string `description:"The threshold"                                                        long:"withdraw-threshold"       required:"true"`
   639  	DepositLifetimeMaximum string `description:"The maxium deposit allowed per address"                               long:"deposit-lifetime-maximum" required:"true"`
   640  	Nonce                  string `description:"A nonce for this signature"                                           long:"nonce"                    required:"true"`
   641  	BridgeAddress          string `description:"The address of the vega bridge this transaction will be submitted to" long:"bridge-address"           required:"true"`
   642  	TokenAddress           string `description:"The address of the token to be used"                                  long:"token-address"            required:"true"`
   643  }
   644  
   645  func (opts *ERC20SetAssetLimitsCmd) Execute(_ []string) error {
   646  	if _, err := flags.NewParser(opts, flags.Default|flags.IgnoreUnknown).Parse(); err != nil {
   647  		return err
   648  	}
   649  
   650  	w, err := erc20Cmd.GetSigner()
   651  	if err != nil {
   652  		return err
   653  	}
   654  
   655  	nonce, overflowed := num.UintFromString(opts.Nonce, 10)
   656  	if overflowed {
   657  		return errors.New("invalid nonce, needs to be base 10 and not overflow")
   658  	}
   659  
   660  	threshold, overflowed := num.UintFromString(opts.WithdrawThreshold, 10)
   661  	if overflowed {
   662  		return errors.New("invalid withdraw-threshold, needs to be base 10 and not overflow")
   663  	}
   664  
   665  	depositLifetime, overflowed := num.UintFromString(opts.DepositLifetimeMaximum, 10)
   666  	if overflowed {
   667  		return errors.New("invalid deposit-lifetime-maximum needs to be base 10 and not overflow")
   668  	}
   669  
   670  	erc20 := bridges.NewERC20Logic(w, opts.BridgeAddress, erc20Cmd.ChainID, erc20Cmd.ChainID == "")
   671  	bundle, err := erc20.SetAssetLimits(
   672  		opts.TokenAddress, depositLifetime, threshold, nonce,
   673  	)
   674  	if err != nil {
   675  		return fmt.Errorf("unable to generate signature: %w", err)
   676  	}
   677  
   678  	fmt.Printf("0x%v\n", bundle.Signature.Hex())
   679  	return nil
   680  }
   681  
   682  type ERC20VerifySetAssetLimitsCmd struct {
   683  	WithdrawThreshold      string `description:"The threshold"                                                        long:"withdraw-threshold"       required:"true"`
   684  	DepositLifetimeMaximum string `description:"The maxium deposit allowed per address"                               long:"deposit-lifetime-maximum" required:"true"`
   685  	Nonce                  string `description:"A nonce for this signature"                                           long:"nonce"                    required:"true"`
   686  	BridgeAddress          string `description:"The address of the vega bridge this transaction will be submitted to" long:"bridge-address"           required:"true"`
   687  	TokenAddress           string `description:"The address of the token to be used"                                  long:"token-address"            required:"true"`
   688  	Signatures             string `description:"The list of signatures from the validators"                           long:"signatures"               required:"true"`
   689  }
   690  
   691  func (opts *ERC20VerifySetAssetLimitsCmd) Execute(_ []string) error {
   692  	if _, err := flags.NewParser(opts, flags.Default|flags.IgnoreUnknown).Parse(); err != nil {
   693  		return err
   694  	}
   695  
   696  	nonce, overflowed := num.UintFromString(opts.Nonce, 10)
   697  	if overflowed {
   698  		return errors.New("invalid nonce, needs to be base 10 and not overflow")
   699  	}
   700  
   701  	threshold, overflowed := num.UintFromString(opts.WithdrawThreshold, 10)
   702  	if overflowed {
   703  		return errors.New("invalid withdraw-threshold, needs to be base 10 and not overflow")
   704  	}
   705  
   706  	depositLifetime, overflowed := num.UintFromString(opts.DepositLifetimeMaximum, 10)
   707  	if overflowed {
   708  		return errors.New("invalid deposit-lifetime-maximum needs to be base 10 and not overflow")
   709  	}
   710  
   711  	if len(opts.Signatures) <= 0 {
   712  		return errors.New("missing signatures")
   713  	}
   714  
   715  	if (len(opts.Signatures)-2)%130 != 0 {
   716  		return errors.New("invalid signatures format")
   717  	}
   718  
   719  	erc20 := bridges.NewERC20Logic(nil, opts.BridgeAddress, erc20Cmd.ChainID, erc20Cmd.ChainID == "")
   720  	signers, err := erc20.VerifySetAssetLimits(
   721  		opts.TokenAddress, depositLifetime, threshold, nonce, opts.Signatures,
   722  	)
   723  	if err != nil {
   724  		return fmt.Errorf("unable to generate signature: %w", err)
   725  	}
   726  
   727  	sort.Strings(signers)
   728  	for _, v := range signers {
   729  		fmt.Printf("%v\n", v)
   730  	}
   731  	return nil
   732  }
   733  
   734  type ERC20SetWithdrawDelayCmd struct {
   735  	Delay         time.Duration `description:"The delay to be applied to all withdrawals"                           long:"delay"          required:"true"`
   736  	Nonce         string        `description:"A nonce for this signature"                                           long:"nonce"          required:"true"`
   737  	BridgeAddress string        `description:"The address of the vega bridge this transaction will be submitted to" long:"bridge-address" required:"true"`
   738  }
   739  
   740  func (opts *ERC20SetWithdrawDelayCmd) Execute(_ []string) error {
   741  	if _, err := flags.NewParser(opts, flags.Default|flags.IgnoreUnknown).Parse(); err != nil {
   742  		return err
   743  	}
   744  
   745  	w, err := erc20Cmd.GetSigner()
   746  	if err != nil {
   747  		return err
   748  	}
   749  
   750  	nonce, overflowed := num.UintFromString(opts.Nonce, 10)
   751  	if overflowed {
   752  		return errors.New("invalid nonce, needs to be base 10 and not overflow")
   753  	}
   754  
   755  	erc20 := bridges.NewERC20Logic(w, opts.BridgeAddress, erc20Cmd.ChainID, erc20Cmd.ChainID == "")
   756  	bundle, err := erc20.SetWithdrawDelay(
   757  		opts.Delay, nonce,
   758  	)
   759  	if err != nil {
   760  		return fmt.Errorf("unable to generate signature: %w", err)
   761  	}
   762  
   763  	fmt.Printf("0x%v\n", bundle.Signature.Hex())
   764  	return nil
   765  }
   766  
   767  type ERC20VerifySetWithdrawDelayCmd struct {
   768  	Delay         time.Duration `description:"The delay to be applied to all withdrawals"                           long:"delay"          required:"true"`
   769  	Nonce         string        `description:"A nonce for this signature"                                           long:"nonce"          required:"true"`
   770  	BridgeAddress string        `description:"The address of the vega bridge this transaction will be submitted to" long:"bridge-address" required:"true"`
   771  	Signatures    string        `description:"The signature bundle to verify"                                       long:"signatures"     required:"true"`
   772  }
   773  
   774  func (opts *ERC20VerifySetWithdrawDelayCmd) Execute(_ []string) error {
   775  	if _, err := flags.NewParser(opts, flags.Default|flags.IgnoreUnknown).Parse(); err != nil {
   776  		return err
   777  	}
   778  
   779  	nonce, overflowed := num.UintFromString(opts.Nonce, 10)
   780  	if overflowed {
   781  		return errors.New("invalid nonce, needs to be base 10 and not overflow")
   782  	}
   783  
   784  	if len(opts.Signatures) <= 0 {
   785  		return errors.New("missing signatures")
   786  	}
   787  
   788  	if (len(opts.Signatures)-2)%130 != 0 {
   789  		return errors.New("invalid signatures format")
   790  	}
   791  
   792  	erc20Logic := bridges.NewERC20Logic(nil, opts.BridgeAddress, erc20Cmd.ChainID, erc20Cmd.ChainID == "")
   793  	addresses, err := erc20Logic.VerifyWithdrawDelay(
   794  		opts.Delay, nonce, opts.Signatures,
   795  	)
   796  	if err != nil {
   797  		return fmt.Errorf("unable to generate signature: %w", err)
   798  	}
   799  
   800  	sort.Strings(addresses)
   801  	for _, v := range addresses {
   802  		fmt.Printf("%v\n", v)
   803  	}
   804  	return nil
   805  }