code.vegaprotocol.io/vega@v0.79.0/core/bridges/erc20_logic.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 bridges
    17  
    18  import (
    19  	"encoding/hex"
    20  	"fmt"
    21  	"math/big"
    22  	"time"
    23  
    24  	crypto "code.vegaprotocol.io/vega/libs/crypto/signature"
    25  	"code.vegaprotocol.io/vega/libs/num"
    26  
    27  	"github.com/ethereum/go-ethereum/accounts/abi"
    28  	ethcmn "github.com/ethereum/go-ethereum/common"
    29  )
    30  
    31  // ERC20Logic yea that's a weird name but
    32  // it just matches the name of the contract.
    33  type ERC20Logic struct {
    34  	signer     Signer
    35  	bridgeAddr string
    36  	chainID    string
    37  	v1         bool
    38  }
    39  
    40  func NewERC20Logic(signer Signer, bridgeAddr string, chainID string, v1 bool) *ERC20Logic {
    41  	return &ERC20Logic{
    42  		signer:     signer,
    43  		bridgeAddr: bridgeAddr,
    44  		chainID:    chainID,
    45  		v1:         v1,
    46  	}
    47  }
    48  
    49  func (e ERC20Logic) ListAsset(
    50  	tokenAddress string,
    51  	vegaAssetID string,
    52  	lifetimeLimit *num.Uint,
    53  	withdrawThreshold *num.Uint,
    54  	nonce *num.Uint,
    55  ) (*SignaturePayload, error) {
    56  	typAddr, err := abi.NewType("address", "", nil)
    57  	if err != nil {
    58  		return nil, err
    59  	}
    60  	typBytes32, err := abi.NewType("bytes32", "", nil)
    61  	if err != nil {
    62  		return nil, err
    63  	}
    64  	typString, err := abi.NewType("string", "", nil)
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  	typU256, err := abi.NewType("uint256", "", nil)
    69  	if err != nil {
    70  		return nil, err
    71  	}
    72  
    73  	args := abi.Arguments([]abi.Argument{
    74  		{
    75  			Name: "address",
    76  			Type: typAddr,
    77  		},
    78  		{
    79  			Name: "vega_asset_id",
    80  			Type: typBytes32,
    81  		},
    82  		{
    83  			Name: "lifetime_limit",
    84  			Type: typU256,
    85  		},
    86  		{
    87  			Name: "withdraw_treshold",
    88  			Type: typU256,
    89  		},
    90  		{
    91  			Name: "nonce",
    92  			Type: typU256,
    93  		},
    94  		{
    95  			Name: "func_name",
    96  			Type: typString,
    97  		},
    98  	})
    99  
   100  	tokenAddressEth := ethcmn.HexToAddress(tokenAddress)
   101  	vegaAssetIDBytes, _ := hex.DecodeString(vegaAssetID)
   102  	var vegaAssetIDArray [32]byte
   103  	copy(vegaAssetIDArray[:], vegaAssetIDBytes[:32])
   104  	buf, err := args.Pack([]interface{}{
   105  		tokenAddressEth,
   106  		vegaAssetIDArray,
   107  		lifetimeLimit.BigInt(),
   108  		withdrawThreshold.BigInt(),
   109  		nonce.BigInt(),
   110  		"listAsset",
   111  	}...)
   112  	if err != nil {
   113  		return nil, fmt.Errorf("couldn't pack abi message: %w", err)
   114  	}
   115  
   116  	msg, err := packScheme(buf, e.bridgeAddr, e.chainID, e.v1)
   117  	if err != nil {
   118  		return nil, fmt.Errorf("couldn't pack abi message: %w", err)
   119  	}
   120  
   121  	return sign(e.signer, msg)
   122  }
   123  
   124  func (e ERC20Logic) buildListAssetMessage(
   125  	tokenAddress string,
   126  	vegaAssetID string,
   127  	lifetimeLimit *num.Uint,
   128  	withdrawThreshold *num.Uint,
   129  	nonce *num.Uint,
   130  ) ([]byte, error) {
   131  	typAddr, err := abi.NewType("address", "", nil)
   132  	if err != nil {
   133  		return nil, err
   134  	}
   135  	typBytes32, err := abi.NewType("bytes32", "", nil)
   136  	if err != nil {
   137  		return nil, err
   138  	}
   139  	typString, err := abi.NewType("string", "", nil)
   140  	if err != nil {
   141  		return nil, err
   142  	}
   143  	typU256, err := abi.NewType("uint256", "", nil)
   144  	if err != nil {
   145  		return nil, err
   146  	}
   147  
   148  	args := abi.Arguments([]abi.Argument{
   149  		{
   150  			Name: "address",
   151  			Type: typAddr,
   152  		},
   153  		{
   154  			Name: "vega_asset_id",
   155  			Type: typBytes32,
   156  		},
   157  		{
   158  			Name: "lifetime_limit",
   159  			Type: typU256,
   160  		},
   161  		{
   162  			Name: "withdraw_treshold",
   163  			Type: typU256,
   164  		},
   165  		{
   166  			Name: "nonce",
   167  			Type: typU256,
   168  		},
   169  		{
   170  			Name: "func_name",
   171  			Type: typString,
   172  		},
   173  	})
   174  
   175  	tokenAddressEth := ethcmn.HexToAddress(tokenAddress)
   176  	vegaAssetIDBytes, _ := hex.DecodeString(vegaAssetID)
   177  	var vegaAssetIDArray [32]byte
   178  	copy(vegaAssetIDArray[:], vegaAssetIDBytes[:32])
   179  	buf, err := args.Pack([]interface{}{
   180  		tokenAddressEth,
   181  		vegaAssetIDArray,
   182  		lifetimeLimit.BigInt(),
   183  		withdrawThreshold.BigInt(),
   184  		nonce.BigInt(),
   185  		"listAsset",
   186  	}...)
   187  	if err != nil {
   188  		return nil, fmt.Errorf("couldn't pack abi message: %w", err)
   189  	}
   190  
   191  	msg, err := packScheme(buf, e.bridgeAddr, e.chainID, e.v1)
   192  	if err != nil {
   193  		return nil, fmt.Errorf("couldn't pack abi message: %w", err)
   194  	}
   195  
   196  	return msg, nil
   197  }
   198  
   199  func (e ERC20Logic) VerifyListAsset(
   200  	tokenAddress string,
   201  	vegaAssetID string,
   202  	lifetimeLimit *num.Uint,
   203  	withdrawThreshold *num.Uint,
   204  	nonce *num.Uint,
   205  	signatures string,
   206  ) ([]string, error) {
   207  	msg, err := e.buildListAssetMessage(
   208  		tokenAddress, vegaAssetID, lifetimeLimit, withdrawThreshold, nonce,
   209  	)
   210  	if err != nil {
   211  		return nil, err
   212  	}
   213  
   214  	addresses := []string{}
   215  	var hexCurrent string
   216  	signatures = signatures[2:]
   217  	for len(signatures) > 0 {
   218  		hexCurrent, signatures = signatures[0:130], signatures[130:]
   219  		current, err := hex.DecodeString(hexCurrent)
   220  		if err != nil {
   221  			return nil, fmt.Errorf("invalid signature format: %w", err)
   222  		}
   223  
   224  		address, err := crypto.RecoverEthereumAddress(msg, current)
   225  		if err != nil {
   226  			return nil, fmt.Errorf("error recovering ethereum address: %w", err)
   227  		}
   228  
   229  		addresses = append(addresses, address.Hex())
   230  	}
   231  
   232  	return addresses, nil
   233  }
   234  
   235  func (e ERC20Logic) RemoveAsset(
   236  	tokenAddress string,
   237  	nonce *num.Uint,
   238  ) (*SignaturePayload, error) {
   239  	typAddr, err := abi.NewType("address", "", nil)
   240  	if err != nil {
   241  		return nil, err
   242  	}
   243  	typString, err := abi.NewType("string", "", nil)
   244  	if err != nil {
   245  		return nil, err
   246  	}
   247  	typU256, err := abi.NewType("uint256", "", nil)
   248  	if err != nil {
   249  		return nil, err
   250  	}
   251  
   252  	args := abi.Arguments([]abi.Argument{
   253  		{
   254  			Name: "address",
   255  			Type: typAddr,
   256  		},
   257  		{
   258  			Name: "nonce",
   259  			Type: typU256,
   260  		},
   261  		{
   262  			Name: "func_name",
   263  			Type: typString,
   264  		},
   265  	})
   266  
   267  	tokenAddressEth := ethcmn.HexToAddress(tokenAddress)
   268  	buf, err := args.Pack([]interface{}{
   269  		tokenAddressEth, nonce.BigInt(), "removeAsset",
   270  	}...)
   271  	if err != nil {
   272  		return nil, fmt.Errorf("couldn't pack abi message: %w", err)
   273  	}
   274  
   275  	msg, err := packScheme(buf, e.bridgeAddr, e.chainID, e.v1)
   276  	if err != nil {
   277  		return nil, fmt.Errorf("couldn't pack abi message: %w", err)
   278  	}
   279  
   280  	return sign(e.signer, msg)
   281  }
   282  
   283  func (e ERC20Logic) WithdrawAsset(
   284  	tokenAddress string,
   285  	amount *num.Uint,
   286  	ethPartyAddress string,
   287  	creation time.Time,
   288  	nonce *num.Uint,
   289  ) (*SignaturePayload, error) {
   290  	msg, err := e.buildWithdrawAssetMessage(
   291  		tokenAddress, amount, ethPartyAddress, creation, nonce,
   292  	)
   293  	if err != nil {
   294  		return nil, err
   295  	}
   296  
   297  	return sign(e.signer, msg)
   298  }
   299  
   300  func (e ERC20Logic) buildWithdrawAssetMessage(
   301  	tokenAddress string,
   302  	amount *num.Uint,
   303  	ethPartyAddress string,
   304  	creation time.Time,
   305  	nonce *num.Uint,
   306  ) ([]byte, error) {
   307  	typAddr, err := abi.NewType("address", "", nil)
   308  	if err != nil {
   309  		return nil, err
   310  	}
   311  	typString, err := abi.NewType("string", "", nil)
   312  	if err != nil {
   313  		return nil, err
   314  	}
   315  	typU256, err := abi.NewType("uint256", "", nil)
   316  	if err != nil {
   317  		return nil, err
   318  	}
   319  
   320  	args := abi.Arguments([]abi.Argument{
   321  		{
   322  			Name: "address",
   323  			Type: typAddr,
   324  		},
   325  		{
   326  			Name: "uint256",
   327  			Type: typU256,
   328  		},
   329  		{
   330  			Name: "address",
   331  			Type: typAddr,
   332  		},
   333  		{
   334  			Name: "uint256",
   335  			Type: typU256,
   336  		},
   337  		{
   338  			Name: "nonce",
   339  			Type: typU256,
   340  		},
   341  		{
   342  			Name: "func_name",
   343  			Type: typString,
   344  		},
   345  	})
   346  
   347  	ethTokenAddr := ethcmn.HexToAddress(tokenAddress)
   348  	hexEthPartyAddress := ethcmn.HexToAddress(ethPartyAddress)
   349  	timestamp := big.NewInt(creation.Unix())
   350  
   351  	buf, err := args.Pack([]interface{}{
   352  		ethTokenAddr,
   353  		amount.BigInt(),
   354  		hexEthPartyAddress,
   355  		timestamp,
   356  		nonce.BigInt(),
   357  		"withdrawAsset",
   358  	}...)
   359  	if err != nil {
   360  		return nil, fmt.Errorf("couldn't pack abi message: %w", err)
   361  	}
   362  
   363  	return packScheme(buf, e.bridgeAddr, e.chainID, e.v1)
   364  }
   365  
   366  func (e ERC20Logic) VerifyWithdrawAsset(
   367  	tokenAddress string,
   368  	amount *num.Uint,
   369  	ethPartyAddress string,
   370  	creation time.Time,
   371  	nonce *num.Uint,
   372  	signatures string,
   373  ) ([]string, error) {
   374  	msg, err := e.buildWithdrawAssetMessage(
   375  		tokenAddress, amount, ethPartyAddress, creation, nonce,
   376  	)
   377  	if err != nil {
   378  		return nil, err
   379  	}
   380  
   381  	addresses := []string{}
   382  	var hexCurrent string
   383  	signatures = signatures[2:]
   384  	for len(signatures) > 0 {
   385  		hexCurrent, signatures = signatures[0:130], signatures[130:]
   386  		current, err := hex.DecodeString(hexCurrent)
   387  		if err != nil {
   388  			return nil, fmt.Errorf("invalid signature format: %w", err)
   389  		}
   390  
   391  		address, err := crypto.RecoverEthereumAddress(msg, current)
   392  		if err != nil {
   393  			return nil, fmt.Errorf("error recovering ethereum address: %w", err)
   394  		}
   395  
   396  		addresses = append(addresses, address.Hex())
   397  	}
   398  
   399  	return addresses, nil
   400  }
   401  
   402  func (e ERC20Logic) SetAssetLimits(
   403  	tokenAddress string,
   404  	lifetimeLimit *num.Uint,
   405  	withdrawThreshold *num.Uint,
   406  	nonce *num.Uint,
   407  ) (*SignaturePayload, error) {
   408  	typAddr, err := abi.NewType("address", "", nil)
   409  	if err != nil {
   410  		return nil, err
   411  	}
   412  	typString, err := abi.NewType("string", "", nil)
   413  	if err != nil {
   414  		return nil, err
   415  	}
   416  	typU256, err := abi.NewType("uint256", "", nil)
   417  	if err != nil {
   418  		return nil, err
   419  	}
   420  
   421  	args := abi.Arguments([]abi.Argument{
   422  		{
   423  			Name: "address",
   424  			Type: typAddr,
   425  		},
   426  		{
   427  			Name: "uint256",
   428  			Type: typU256,
   429  		},
   430  		{
   431  			Name: "uint256",
   432  			Type: typU256,
   433  		},
   434  		{
   435  			Name: "uint256",
   436  			Type: typU256,
   437  		},
   438  		{
   439  			Name: "func_name",
   440  			Type: typString,
   441  		},
   442  	})
   443  
   444  	ethTokenAddr := ethcmn.HexToAddress(tokenAddress)
   445  	buf, err := args.Pack([]interface{}{
   446  		ethTokenAddr,
   447  		lifetimeLimit.BigInt(),
   448  		withdrawThreshold.BigInt(),
   449  		nonce.BigInt(),
   450  		"setAssetLimits",
   451  	}...)
   452  	if err != nil {
   453  		return nil, fmt.Errorf("couldn't pack abi message: %w", err)
   454  	}
   455  
   456  	msg, err := packScheme(buf, e.bridgeAddr, e.chainID, e.v1)
   457  	if err != nil {
   458  		return nil, fmt.Errorf("couldn't pack abi message: %w", err)
   459  	}
   460  
   461  	return sign(e.signer, msg)
   462  }
   463  
   464  func (e ERC20Logic) buildSetAssetLimitsMessage(
   465  	tokenAddress string,
   466  	lifetimeLimit *num.Uint,
   467  	withdrawThreshold *num.Uint,
   468  	nonce *num.Uint,
   469  ) ([]byte, error) {
   470  	typAddr, err := abi.NewType("address", "", nil)
   471  	if err != nil {
   472  		return nil, err
   473  	}
   474  	typString, err := abi.NewType("string", "", nil)
   475  	if err != nil {
   476  		return nil, err
   477  	}
   478  	typU256, err := abi.NewType("uint256", "", nil)
   479  	if err != nil {
   480  		return nil, err
   481  	}
   482  
   483  	args := abi.Arguments([]abi.Argument{
   484  		{
   485  			Name: "address",
   486  			Type: typAddr,
   487  		},
   488  		{
   489  			Name: "uint256",
   490  			Type: typU256,
   491  		},
   492  		{
   493  			Name: "uint256",
   494  			Type: typU256,
   495  		},
   496  		{
   497  			Name: "uint256",
   498  			Type: typU256,
   499  		},
   500  		{
   501  			Name: "func_name",
   502  			Type: typString,
   503  		},
   504  	})
   505  
   506  	ethTokenAddr := ethcmn.HexToAddress(tokenAddress)
   507  	buf, err := args.Pack([]interface{}{
   508  		ethTokenAddr,
   509  		lifetimeLimit.BigInt(),
   510  		withdrawThreshold.BigInt(),
   511  		nonce.BigInt(),
   512  		"setAssetLimits",
   513  	}...)
   514  	if err != nil {
   515  		return nil, fmt.Errorf("couldn't pack abi message: %w", err)
   516  	}
   517  
   518  	msg, err := packScheme(buf, e.bridgeAddr, e.chainID, e.v1)
   519  	if err != nil {
   520  		return nil, fmt.Errorf("couldn't pack abi message: %w", err)
   521  	}
   522  
   523  	return msg, nil
   524  }
   525  
   526  func (e ERC20Logic) VerifySetAssetLimits(
   527  	tokenAddress string,
   528  	lifetimeLimit *num.Uint,
   529  	withdrawThreshold *num.Uint,
   530  	nonce *num.Uint,
   531  	signatures string,
   532  ) ([]string, error) {
   533  	msg, err := e.buildSetAssetLimitsMessage(
   534  		tokenAddress, lifetimeLimit, withdrawThreshold, nonce,
   535  	)
   536  	if err != nil {
   537  		return nil, err
   538  	}
   539  
   540  	addresses := []string{}
   541  	var hexCurrent string
   542  	signatures = signatures[2:]
   543  	for len(signatures) > 0 {
   544  		hexCurrent, signatures = signatures[0:130], signatures[130:]
   545  		current, err := hex.DecodeString(hexCurrent)
   546  		if err != nil {
   547  			return nil, fmt.Errorf("invalid signature format: %w", err)
   548  		}
   549  
   550  		address, err := crypto.RecoverEthereumAddress(msg, current)
   551  		if err != nil {
   552  			return nil, fmt.Errorf("error recovering ethereum address: %w", err)
   553  		}
   554  
   555  		addresses = append(addresses, address.Hex())
   556  	}
   557  
   558  	return addresses, nil
   559  }
   560  
   561  func (e ERC20Logic) SetWithdrawDelay(
   562  	delay time.Duration,
   563  	nonce *num.Uint,
   564  ) (*SignaturePayload, error) {
   565  	msg, err := e.buildWithdrawDelayMessage(
   566  		delay, nonce,
   567  	)
   568  	if err != nil {
   569  		return nil, err
   570  	}
   571  
   572  	return sign(e.signer, msg)
   573  }
   574  
   575  func (e ERC20Logic) buildWithdrawDelayMessage(
   576  	delay time.Duration,
   577  	nonce *num.Uint,
   578  ) ([]byte, error) {
   579  	typString, err := abi.NewType("string", "", nil)
   580  	if err != nil {
   581  		return nil, err
   582  	}
   583  	typU256, err := abi.NewType("uint256", "", nil)
   584  	if err != nil {
   585  		return nil, err
   586  	}
   587  
   588  	args := abi.Arguments([]abi.Argument{
   589  		{
   590  			Name: "uint256",
   591  			Type: typU256,
   592  		},
   593  		{
   594  			Name: "uint256",
   595  			Type: typU256,
   596  		},
   597  		{
   598  			Name: "func_name",
   599  			Type: typString,
   600  		},
   601  	})
   602  
   603  	delayBig := big.NewInt(int64(delay.Seconds()))
   604  	buf, err := args.Pack([]interface{}{
   605  		delayBig,
   606  		nonce.BigInt(),
   607  		"setWithdrawDelay",
   608  	}...)
   609  	if err != nil {
   610  		return nil, fmt.Errorf("couldn't pack abi message: %w", err)
   611  	}
   612  
   613  	return packScheme(buf, e.bridgeAddr, e.chainID, e.v1)
   614  }
   615  
   616  func (e ERC20Logic) VerifyWithdrawDelay(
   617  	delay time.Duration,
   618  	nonce *num.Uint,
   619  	signatures string,
   620  ) ([]string, error) {
   621  	msg, err := e.buildWithdrawDelayMessage(
   622  		delay, nonce,
   623  	)
   624  	if err != nil {
   625  		return nil, err
   626  	}
   627  
   628  	addresses := []string{}
   629  	var hexCurrent string
   630  	signatures = signatures[2:]
   631  	for len(signatures) > 0 {
   632  		hexCurrent, signatures = signatures[0:130], signatures[130:]
   633  		current, err := hex.DecodeString(hexCurrent)
   634  		if err != nil {
   635  			return nil, fmt.Errorf("invalid signature format: %w", err)
   636  		}
   637  
   638  		address, err := crypto.RecoverEthereumAddress(msg, current)
   639  		if err != nil {
   640  			return nil, fmt.Errorf("error recovering ethereum address: %w", err)
   641  		}
   642  
   643  		addresses = append(addresses, address.Hex())
   644  	}
   645  
   646  	return addresses, nil
   647  }
   648  
   649  func (e ERC20Logic) GlobalStop(
   650  	nonce *num.Uint,
   651  ) (*SignaturePayload, error) {
   652  	typString, err := abi.NewType("string", "", nil)
   653  	if err != nil {
   654  		return nil, err
   655  	}
   656  	typU256, err := abi.NewType("uint256", "", nil)
   657  	if err != nil {
   658  		return nil, err
   659  	}
   660  
   661  	args := abi.Arguments([]abi.Argument{
   662  		{
   663  			Name: "uint256",
   664  			Type: typU256,
   665  		},
   666  		{
   667  			Name: "func_name",
   668  			Type: typString,
   669  		},
   670  	})
   671  
   672  	buf, err := args.Pack([]interface{}{
   673  		nonce.BigInt(),
   674  		"globalStop",
   675  	}...)
   676  	if err != nil {
   677  		return nil, fmt.Errorf("couldn't pack abi message: %w", err)
   678  	}
   679  
   680  	msg, err := packScheme(buf, e.bridgeAddr, e.chainID, e.v1)
   681  	if err != nil {
   682  		return nil, fmt.Errorf("couldn't pack abi message: %w", err)
   683  	}
   684  
   685  	return sign(e.signer, msg)
   686  }
   687  
   688  func (e ERC20Logic) GlobalResume(
   689  	nonce *num.Uint,
   690  ) (*SignaturePayload, error) {
   691  	typString, err := abi.NewType("string", "", nil)
   692  	if err != nil {
   693  		return nil, err
   694  	}
   695  	typU256, err := abi.NewType("uint256", "", nil)
   696  	if err != nil {
   697  		return nil, err
   698  	}
   699  
   700  	args := abi.Arguments([]abi.Argument{
   701  		{
   702  			Name: "uint256",
   703  			Type: typU256,
   704  		},
   705  		{
   706  			Name: "func_name",
   707  			Type: typString,
   708  		},
   709  	})
   710  
   711  	buf, err := args.Pack([]interface{}{
   712  		nonce.BigInt(),
   713  		"globalResume",
   714  	}...)
   715  	if err != nil {
   716  		return nil, fmt.Errorf("couldn't pack abi message: %w", err)
   717  	}
   718  
   719  	msg, err := packScheme(buf, e.bridgeAddr, e.chainID, e.v1)
   720  	if err != nil {
   721  		return nil, fmt.Errorf("couldn't pack abi message: %w", err)
   722  	}
   723  
   724  	return sign(e.signer, msg)
   725  }
   726  
   727  func (e ERC20Logic) VerifyGlobalResume(
   728  	nonce *num.Uint,
   729  	signatures string,
   730  ) ([]string, error) {
   731  	typString, err := abi.NewType("string", "", nil)
   732  	if err != nil {
   733  		return nil, err
   734  	}
   735  	typU256, err := abi.NewType("uint256", "", nil)
   736  	if err != nil {
   737  		return nil, err
   738  	}
   739  
   740  	args := abi.Arguments([]abi.Argument{
   741  		{
   742  			Name: "uint256",
   743  			Type: typU256,
   744  		},
   745  		{
   746  			Name: "func_name",
   747  			Type: typString,
   748  		},
   749  	})
   750  
   751  	buf, err := args.Pack([]interface{}{
   752  		nonce.BigInt(),
   753  		"globalResume",
   754  	}...)
   755  	if err != nil {
   756  		return nil, fmt.Errorf("couldn't pack abi message: %w", err)
   757  	}
   758  
   759  	msg, err := packScheme(buf, e.bridgeAddr, e.chainID, e.v1)
   760  	if err != nil {
   761  		return nil, fmt.Errorf("couldn't pack abi message: %w", err)
   762  	}
   763  
   764  	addresses := []string{}
   765  	var hexCurrent string
   766  	signatures = signatures[2:]
   767  	for len(signatures) > 0 {
   768  		hexCurrent, signatures = signatures[0:130], signatures[130:]
   769  		current, err := hex.DecodeString(hexCurrent)
   770  		if err != nil {
   771  			return nil, fmt.Errorf("invalid signature format: %w", err)
   772  		}
   773  
   774  		address, err := crypto.RecoverEthereumAddress(msg, current)
   775  		if err != nil {
   776  			return nil, fmt.Errorf("error recovering ethereum address: %w", err)
   777  		}
   778  
   779  		addresses = append(addresses, address.Hex())
   780  	}
   781  
   782  	return addresses, nil
   783  }