github.com/0chain/gosdk@v1.17.11/zcnbridge/bridge_test.go (about)

     1  package zcnbridge
     2  
     3  import (
     4  	"context"
     5  	"encoding/hex"
     6  	"encoding/json"
     7  	"github.com/0chain/gosdk/zcnbridge/ethereum/uniswapnetwork"
     8  	"github.com/ethereum/go-ethereum/accounts/abi"
     9  	"log"
    10  	"math/big"
    11  	"os"
    12  	"path"
    13  	"strconv"
    14  	"testing"
    15  	"time"
    16  
    17  	"github.com/0chain/gosdk/zcnbridge/ethereum/zcntoken"
    18  
    19  	sdkcommon "github.com/0chain/gosdk/core/common"
    20  	"github.com/0chain/gosdk/zcnbridge/ethereum"
    21  	"github.com/0chain/gosdk/zcnbridge/ethereum/authorizers"
    22  	binding "github.com/0chain/gosdk/zcnbridge/ethereum/bridge"
    23  	bridgemocks "github.com/0chain/gosdk/zcnbridge/mocks"
    24  	"github.com/0chain/gosdk/zcnbridge/transaction"
    25  	transactionmocks "github.com/0chain/gosdk/zcnbridge/transaction/mocks"
    26  	"github.com/0chain/gosdk/zcnbridge/wallet"
    27  	"github.com/0chain/gosdk/zcnbridge/zcnsc"
    28  	"github.com/0chain/gosdk/zcncore"
    29  	eth "github.com/ethereum/go-ethereum"
    30  	"github.com/ethereum/go-ethereum/accounts"
    31  	"github.com/ethereum/go-ethereum/accounts/keystore"
    32  	"github.com/ethereum/go-ethereum/common"
    33  	"github.com/spf13/viper"
    34  	"github.com/stretchr/testify/mock"
    35  	"github.com/stretchr/testify/require"
    36  )
    37  
    38  const (
    39  	ethereumAddress = "0xD8c9156e782C68EE671C09b6b92de76C97948432"
    40  
    41  	alchemyEthereumNodeURL  = "https://eth-mainnet.g.alchemy.com/v2/9VanLUbRE0pLmDHwCHGJlhs9GHosrfD9"
    42  	tenderlyEthereumNodeURL = "https://rpc.tenderly.co/fork/835ecb4e-1f60-4129-adc2-b0c741193839"
    43  	infuraEthereumNodeURL   = "https://mainnet.infura.io/v3/7238211010344719ad14a89db874158c"
    44  
    45  	password = "02289b9"
    46  
    47  	authorizerDelegatedAddress = "0xa149B58b7e1390D152383BB03dBc79B390F648e2"
    48  
    49  	bridgeAddress      = "0x7bbbEa24ac1751317D7669f05558632c4A9113D7"
    50  	tokenAddress       = "0xb9EF770B6A5e12E45983C5D80545258aA38F3B78"
    51  	authorizersAddress = "0xEAe8229c0E457efBA1A1769e7F8c20110fF68E61"
    52  	uniswapAddress     = "0x4c12C2FeEDD86267d17dB64BaB2cFD12cD8611f5"
    53  
    54  	zcnTxnID = "b26abeb31fcee5d2e75b26717722938a06fa5ce4a5b5e68ddad68357432caace"
    55  	amount   = 1
    56  	txnFee   = 1
    57  	nonce    = 1
    58  
    59  	ethereumTxnID = "0x3b59971c2aa294739cd73912f0c5a7996aafb796238cf44408b0eb4af0fbac82"
    60  
    61  	clientId = "d6e9b3222434faa043c683d1a939d6a0fa2818c4d56e794974d64a32005330d3"
    62  )
    63  
    64  var (
    65  	uniswapSmartContractCode = "60806040526004361061002d5760003560e01c806318ae74a41461003957806397a40b341461006957610034565b3661003457005b600080fd5b610053600480360381019061004e9190610781565b6100a6565b60405161006091906107bd565b60405180910390f35b34801561007557600080fd5b50610090600480360381019061008b91906107d8565b61017e565b60405161009d91906107bd565b60405180910390f35b60008060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663fb3bdb4134856100ef61061a565b33426040518663ffffffff1660e01b81526004016101109493929190610917565b60006040518083038185885af115801561012e573d6000803e3d6000fd5b50505050506040513d6000823e3d601f19601f820116820180604052508101906101589190610ad1565b90508060018151811061016e5761016d610b1a565b5b6020026020010151915050919050565b6000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd3330856040518463ffffffff1660e01b81526004016101df93929190610b49565b6020604051808303816000875af11580156101fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102229190610bb8565b50600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663095ea7b360008054906101000a900473ffffffffffffffffffffffffffffffffffffffff16846040518363ffffffff1660e01b81526004016102a0929190610be5565b6020604051808303816000875af11580156102bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102e39190610bb8565b506060600367ffffffffffffffff81111561030157610300610979565b5b60405190808252806020026020018201604052801561032f5781602001602082028036833780820191505090505b50905073a0b86991c6218b36c1d19d4a2e9eb0ce3606eb488160008151811061035b5761035a610b1a565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2816001815181106103be576103bd610b1a565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073b9ef770b6a5e12e45983c5d80545258aa38f3b788160028151811061042157610420610b1a565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638803dbee86868533426040518663ffffffff1660e01b81526004016104bf959493929190610c0e565b6000604051808303816000875af11580156104de573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906105079190610ad1565b9050838160008151811061051e5761051d610b1a565b5b602002602001015110156105f457600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb338360008151811061057f5761057e610b1a565b5b6020026020010151876105929190610c97565b6040518363ffffffff1660e01b81526004016105af929190610be5565b6020604051808303816000875af11580156105ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105f29190610bb8565b505b8060028151811061060857610607610b1a565b5b60200260200101519250505092915050565b60606000600267ffffffffffffffff81111561063957610638610979565b5b6040519080825280602002602001820160405280156106675781602001602082028036833780820191505090505b50905073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28160008151811061069357610692610b1a565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073b9ef770b6a5e12e45983c5d80545258aa38f3b78816001815181106106f6576106f5610b1a565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508091505090565b6000604051905090565b600080fd5b600080fd5b6000819050919050565b61075e8161074b565b811461076957600080fd5b50565b60008135905061077b81610755565b92915050565b60006020828403121561079757610796610741565b5b60006107a58482850161076c565b91505092915050565b6107b78161074b565b82525050565b60006020820190506107d260008301846107ae565b92915050565b600080604083850312156107ef576107ee610741565b5b60006107fd8582860161076c565b925050602061080e8582860161076c565b9150509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061086f82610844565b9050919050565b61087f81610864565b82525050565b60006108918383610876565b60208301905092915050565b6000602082019050919050565b60006108b582610818565b6108bf8185610823565b93506108ca83610834565b8060005b838110156108fb5781516108e28882610885565b97506108ed8361089d565b9250506001810190506108ce565b5085935050505092915050565b61091181610864565b82525050565b600060808201905061092c60008301876107ae565b818103602083015261093e81866108aa565b905061094d6040830185610908565b61095a60608301846107ae565b95945050505050565b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6109b182610968565b810181811067ffffffffffffffff821117156109d0576109cf610979565b5b80604052505050565b60006109e3610737565b90506109ef82826109a8565b919050565b600067ffffffffffffffff821115610a0f57610a0e610979565b5b602082029050602081019050919050565b600080fd5b600081519050610a3481610755565b92915050565b6000610a4d610a48846109f4565b6109d9565b90508083825260208201905060208402830185811115610a7057610a6f610a20565b5b835b81811015610a995780610a858882610a25565b845260208401935050602081019050610a72565b5050509392505050565b600082601f830112610ab857610ab7610963565b5b8151610ac8848260208601610a3a565b91505092915050565b600060208284031215610ae757610ae6610741565b5b600082015167ffffffffffffffff811115610b0557610b04610746565b5b610b1184828501610aa3565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000606082019050610b5e6000830186610908565b610b6b6020830185610908565b610b7860408301846107ae565b949350505050565b60008115159050919050565b610b9581610b80565b8114610ba057600080fd5b50565b600081519050610bb281610b8c565b92915050565b600060208284031215610bce57610bcd610741565b5b6000610bdc84828501610ba3565b91505092915050565b6000604082019050610bfa6000830185610908565b610c0760208301846107ae565b9392505050565b600060a082019050610c2360008301886107ae565b610c3060208301876107ae565b8181036040830152610c4281866108aa565b9050610c516060830185610908565b610c5e60808301846107ae565b9695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000610ca28261074b565b9150610cad8361074b565b9250828203905081811115610cc557610cc4610c68565b5b9291505056fea26469706673582212207de082f4e5f623e928f9b99a8e233f194bacc23969b40ea49a470ecfd2a1fb8464736f6c63430008140033"
    66  )
    67  
    68  var (
    69  	testKeyStoreLocation = path.Join(".", EthereumWalletStorageDir)
    70  )
    71  
    72  var (
    73  	ethereumSignatures = []*ethereum.AuthorizerSignature{
    74  		{
    75  			ID:        "0x2ec8F26ccC678c9faF0Df20208aEE3AF776160CD",
    76  			Signature: []byte("0xEAe8229c0E457efBA1A1769e7F8c20110fF68E61"),
    77  		},
    78  	}
    79  
    80  	zcnScSignatures = []*zcnsc.AuthorizerSignature{
    81  		{
    82  			ID:        "0x2ec8F26ccC678c9faF0Df20208aEE3AF776160CD",
    83  			Signature: "0xEAe8229c0E457efBA1A1769e7F8c20110fF68E61",
    84  		},
    85  	}
    86  )
    87  
    88  type ethereumClientMock struct {
    89  	mock.TestingT
    90  }
    91  
    92  func (ecm *ethereumClientMock) Cleanup(callback func()) {
    93  	callback()
    94  }
    95  
    96  type transactionMock struct {
    97  	mock.TestingT
    98  }
    99  
   100  func (tem *transactionMock) Cleanup(callback func()) {
   101  	callback()
   102  }
   103  
   104  type transactionProviderMock struct {
   105  	mock.TestingT
   106  }
   107  
   108  func (tem *transactionProviderMock) Cleanup(callback func()) {
   109  	callback()
   110  }
   111  
   112  type keyStoreMock struct {
   113  	mock.TestingT
   114  }
   115  
   116  func (ksm *keyStoreMock) Cleanup(callback func()) {
   117  	callback()
   118  }
   119  
   120  type authorizerConfigTarget struct {
   121  	Fee sdkcommon.Balance `json:"fee"`
   122  }
   123  
   124  type authorizerNodeTarget struct {
   125  	ID        string                  `json:"id"`
   126  	PublicKey string                  `json:"public_key"`
   127  	URL       string                  `json:"url"`
   128  	Config    *authorizerConfigTarget `json:"config"`
   129  }
   130  
   131  type authorizerConfigSource struct {
   132  	Fee string `json:"fee"`
   133  }
   134  
   135  type authorizerNodeSource struct {
   136  	ID     string                  `json:"id"`
   137  	Config *authorizerConfigSource `json:"config"`
   138  }
   139  
   140  func (an *authorizerNodeTarget) decode(input []byte) error {
   141  	var objMap map[string]*json.RawMessage
   142  	err := json.Unmarshal(input, &objMap)
   143  	if err != nil {
   144  		return err
   145  	}
   146  
   147  	id, ok := objMap["id"]
   148  	if ok {
   149  		var idStr *string
   150  		err = json.Unmarshal(*id, &idStr)
   151  		if err != nil {
   152  			return err
   153  		}
   154  		an.ID = *idStr
   155  	}
   156  
   157  	pk, ok := objMap["public_key"]
   158  	if ok {
   159  		var pkStr *string
   160  		err = json.Unmarshal(*pk, &pkStr)
   161  		if err != nil {
   162  			return err
   163  		}
   164  		an.PublicKey = *pkStr
   165  	}
   166  
   167  	url, ok := objMap["url"]
   168  	if ok {
   169  		var urlStr *string
   170  		err = json.Unmarshal(*url, &urlStr)
   171  		if err != nil {
   172  			return err
   173  		}
   174  		an.URL = *urlStr
   175  	}
   176  
   177  	rawCfg, ok := objMap["config"]
   178  	if ok {
   179  		var cfg = &authorizerConfigTarget{}
   180  		err = cfg.decode(*rawCfg)
   181  		if err != nil {
   182  			return err
   183  		}
   184  
   185  		an.Config = cfg
   186  	}
   187  
   188  	return nil
   189  }
   190  
   191  func (c *authorizerConfigTarget) decode(input []byte) (err error) {
   192  	const (
   193  		Fee = "fee"
   194  	)
   195  
   196  	var objMap map[string]*json.RawMessage
   197  	err = json.Unmarshal(input, &objMap)
   198  	if err != nil {
   199  		return err
   200  	}
   201  
   202  	fee, ok := objMap[Fee]
   203  	if ok {
   204  		var feeStr *string
   205  		err = json.Unmarshal(*fee, &feeStr)
   206  		if err != nil {
   207  			return err
   208  		}
   209  
   210  		var balance, err = strconv.ParseInt(*feeStr, 10, 64)
   211  		if err != nil {
   212  			return err
   213  		}
   214  
   215  		c.Fee = sdkcommon.Balance(balance)
   216  	}
   217  
   218  	return nil
   219  }
   220  
   221  func getEthereumClient(t mock.TestingT) *bridgemocks.EthereumClient {
   222  	return bridgemocks.NewEthereumClient(&ethereumClientMock{t})
   223  }
   224  
   225  func getBridgeClient(ethereumNodeURL string, ethereumClient EthereumClient, transactionProvider transaction.TransactionProvider, keyStore KeyStore) *BridgeClient {
   226  	cfg := viper.New()
   227  
   228  	tempConfigFile, err := os.CreateTemp(".", "config.yaml")
   229  	if err != nil {
   230  		log.Fatalln(err)
   231  	}
   232  
   233  	defer func(name string) {
   234  		err := os.Remove(name)
   235  		if err != nil {
   236  			log.Fatalln(err)
   237  		}
   238  	}(tempConfigFile.Name())
   239  
   240  	cfg.SetConfigFile(tempConfigFile.Name())
   241  
   242  	cfg.SetDefault("bridge.bridge_address", bridgeAddress)
   243  	cfg.SetDefault("bridge.token_address", tokenAddress)
   244  	cfg.SetDefault("bridge.authorizers_address", authorizersAddress)
   245  	cfg.SetDefault("bridge.uniswap_address", uniswapAddress)
   246  	cfg.SetDefault("bridge.ethereum_address", ethereumAddress)
   247  	cfg.SetDefault("bridge.password", password)
   248  	cfg.SetDefault("bridge.gas_limit", 0)
   249  	cfg.SetDefault("bridge.consensus_threshold", 0)
   250  
   251  	return NewBridgeClient(
   252  		cfg.GetString("bridge.bridge_address"),
   253  		cfg.GetString("bridge.token_address"),
   254  		cfg.GetString("bridge.authorizers_address"),
   255  		cfg.GetString("bridge.uniswap_address"),
   256  		cfg.GetString("bridge.ethereum_address"),
   257  		ethereumNodeURL,
   258  		cfg.GetString("bridge.password"),
   259  		cfg.GetUint64("bridge.gas_limit"),
   260  		cfg.GetFloat64("bridge.consensus_threshold"),
   261  
   262  		ethereumClient,
   263  		transactionProvider,
   264  		keyStore,
   265  	)
   266  }
   267  
   268  func prepareEthereumClientGeneralMockCalls(ethereumClient *mock.Mock) {
   269  	ethereumClient.On("EstimateGas", mock.Anything, mock.Anything).Return(uint64(400000), nil)
   270  	ethereumClient.On("ChainID", mock.Anything).Return(big.NewInt(400000), nil)
   271  	ethereumClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(nonce), nil)
   272  	ethereumClient.On("SuggestGasPrice", mock.Anything).Return(big.NewInt(400000), nil)
   273  	ethereumClient.On("SendTransaction", mock.Anything, mock.Anything).Return(nil)
   274  }
   275  
   276  func getTransaction(t mock.TestingT) *transactionmocks.Transaction {
   277  	return transactionmocks.NewTransaction(&transactionMock{t})
   278  }
   279  
   280  func prepareTransactionGeneralMockCalls(transaction *mock.Mock) {
   281  	transaction.On("ExecuteSmartContract", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(zcnTxnID, nil)
   282  	transaction.On("Verify", mock.Anything).Return(nil)
   283  }
   284  
   285  func getTransactionProvider(t mock.TestingT) *transactionmocks.TransactionProvider {
   286  	return transactionmocks.NewTransactionProvider(&transactionProviderMock{t})
   287  }
   288  
   289  func prepareTransactionProviderGeneralMockCalls(transactionProvider *mock.Mock, transaction *transactionmocks.Transaction) {
   290  	transactionProvider.On("NewTransactionEntity", mock.Anything).Return(transaction, nil)
   291  }
   292  
   293  func getKeyStore(t mock.TestingT) *bridgemocks.KeyStore {
   294  	return bridgemocks.NewKeyStore(&keyStoreMock{t})
   295  }
   296  
   297  func prepareKeyStoreGeneralMockCalls(keyStore *bridgemocks.KeyStore) {
   298  	ks := keystore.NewKeyStore(testKeyStoreLocation, keystore.StandardScryptN, keystore.StandardScryptP)
   299  
   300  	keyStore.On("Find", mock.Anything).Return(accounts.Account{Address: common.HexToAddress(ethereumAddress)}, nil)
   301  	keyStore.On("TimedUnlock", mock.Anything, mock.Anything, mock.Anything).Run(
   302  		func(args mock.Arguments) {
   303  			err := ks.TimedUnlock(args.Get(0).(accounts.Account), args.Get(1).(string), args.Get(2).(time.Duration))
   304  			if err != nil {
   305  				log.Fatalln(err)
   306  			}
   307  		},
   308  	).Return(nil)
   309  	keyStore.On("SignHash", mock.Anything, mock.Anything).Return([]byte(ethereumAddress), nil)
   310  
   311  	keyStore.On("GetEthereumKeyStore").Return(ks)
   312  }
   313  
   314  func Test_ZCNBridge(t *testing.T) {
   315  	ethereumClient := getEthereumClient(t)
   316  	prepareEthereumClientGeneralMockCalls(&ethereumClient.Mock)
   317  
   318  	tx := getTransaction(t)
   319  	prepareTransactionGeneralMockCalls(&tx.Mock)
   320  
   321  	transactionProvider := getTransactionProvider(t)
   322  	prepareTransactionProviderGeneralMockCalls(&transactionProvider.Mock, tx)
   323  
   324  	keyStore := getKeyStore(t)
   325  	prepareKeyStoreGeneralMockCalls(keyStore)
   326  
   327  	bridgeClient := getBridgeClient(alchemyEthereumNodeURL, ethereumClient, transactionProvider, keyStore)
   328  
   329  	t.Run("should update authorizer config.", func(t *testing.T) {
   330  		source := &authorizerNodeSource{
   331  			ID: "12345678",
   332  			Config: &authorizerConfigSource{
   333  				Fee: "999",
   334  			},
   335  		}
   336  		target := &authorizerNodeTarget{}
   337  
   338  		bytes, err := json.Marshal(source)
   339  		require.NoError(t, err)
   340  
   341  		err = target.decode(bytes)
   342  		require.NoError(t, err)
   343  
   344  		require.Equal(t, "", target.URL)
   345  		require.Equal(t, "", target.PublicKey)
   346  		require.Equal(t, "12345678", target.ID)
   347  		require.Equal(t, sdkcommon.Balance(999), target.Config.Fee)
   348  	})
   349  
   350  	t.Run("should check configuration formating in MintWZCN", func(t *testing.T) {
   351  		_, err := bridgeClient.MintWZCN(context.Background(), &ethereum.MintPayload{
   352  			ZCNTxnID:   zcnTxnID,
   353  			Amount:     amount,
   354  			To:         ethereumAddress,
   355  			Nonce:      nonce,
   356  			Signatures: ethereumSignatures,
   357  		})
   358  		require.NoError(t, err)
   359  
   360  		var sigs [][]byte
   361  		for _, signature := range ethereumSignatures {
   362  			sigs = append(sigs, signature.Signature)
   363  		}
   364  
   365  		to := common.HexToAddress(bridgeAddress)
   366  		fromAddress := common.HexToAddress(ethereumAddress)
   367  
   368  		rawAbi, err := binding.BridgeMetaData.GetAbi()
   369  		require.NoError(t, err)
   370  
   371  		pack, err := rawAbi.Pack("mint", common.HexToAddress(ethereumAddress),
   372  			big.NewInt(amount),
   373  			DefaultClientIDEncoder(zcnTxnID),
   374  			big.NewInt(nonce),
   375  			sigs)
   376  		require.NoError(t, err)
   377  
   378  		require.True(t, ethereumClient.AssertCalled(
   379  			t,
   380  			"EstimateGas",
   381  			context.Background(),
   382  			eth.CallMsg{
   383  				To:   &to,
   384  				From: fromAddress,
   385  				Data: pack,
   386  			},
   387  		))
   388  	})
   389  
   390  	t.Run("should check configuration formating in BurnWZCN", func(t *testing.T) {
   391  		_, err := bridgeClient.BurnWZCN(context.Background(), amount)
   392  		require.NoError(t, err)
   393  
   394  		to := common.HexToAddress(bridgeAddress)
   395  		fromAddress := common.HexToAddress(ethereumAddress)
   396  
   397  		rawAbi, err := binding.BridgeMetaData.GetAbi()
   398  		require.NoError(t, err)
   399  
   400  		pack, err := rawAbi.Pack("burn", big.NewInt(amount), DefaultClientIDEncoder(zcncore.GetClientWalletID()))
   401  		require.NoError(t, err)
   402  
   403  		require.True(t, ethereumClient.AssertCalled(
   404  			t,
   405  			"EstimateGas",
   406  			context.Background(),
   407  			eth.CallMsg{
   408  				To:   &to,
   409  				From: fromAddress,
   410  				Data: pack,
   411  			},
   412  		))
   413  	})
   414  
   415  	t.Run("should check configuration used by MintZCN", func(t *testing.T) {
   416  		payload := &zcnsc.MintPayload{
   417  			EthereumTxnID:     ethereumTxnID,
   418  			Amount:            sdkcommon.Balance(amount),
   419  			Nonce:             nonce,
   420  			Signatures:        zcnScSignatures,
   421  			ReceivingClientID: clientId,
   422  		}
   423  
   424  		_, err := bridgeClient.MintZCN(context.Background(), payload)
   425  		require.NoError(t, err)
   426  
   427  		require.True(t, tx.AssertCalled(
   428  			t,
   429  			"ExecuteSmartContract",
   430  			context.Background(),
   431  			wallet.ZCNSCSmartContractAddress,
   432  			wallet.MintFunc,
   433  			payload,
   434  			uint64(0),
   435  		))
   436  	})
   437  
   438  	t.Run("should check configuration used by BurnZCN", func(t *testing.T) {
   439  		_, err := bridgeClient.BurnZCN(context.Background(), amount, txnFee)
   440  		require.NoError(t, err)
   441  
   442  		require.True(t, tx.AssertCalled(
   443  			t,
   444  			"ExecuteSmartContract",
   445  			context.Background(),
   446  			wallet.ZCNSCSmartContractAddress,
   447  			wallet.BurnFunc,
   448  			zcnsc.BurnPayload{
   449  				EthereumAddress: ethereumAddress,
   450  			},
   451  			uint64(amount),
   452  		))
   453  	})
   454  
   455  	t.Run("should check configuration used by AddEthereumAuthorizer", func(t *testing.T) {
   456  		_, err := bridgeClient.AddEthereumAuthorizer(context.Background(), common.HexToAddress(authorizerDelegatedAddress))
   457  		require.NoError(t, err)
   458  
   459  		to := common.HexToAddress(authorizersAddress)
   460  		fromAddress := common.HexToAddress(ethereumAddress)
   461  
   462  		rawAbi, err := authorizers.AuthorizersMetaData.GetAbi()
   463  		require.NoError(t, err)
   464  
   465  		pack, err := rawAbi.Pack("addAuthorizers", common.HexToAddress(authorizerDelegatedAddress))
   466  		require.NoError(t, err)
   467  
   468  		require.True(t, ethereumClient.AssertCalled(
   469  			t,
   470  			"EstimateGas",
   471  			context.Background(),
   472  			eth.CallMsg{
   473  				To:   &to,
   474  				From: fromAddress,
   475  				Data: pack,
   476  			},
   477  		))
   478  	})
   479  
   480  	t.Run("should check configuration used by RemoveAuthorizer", func(t *testing.T) {
   481  		_, err := bridgeClient.RemoveEthereumAuthorizer(context.Background(), common.HexToAddress(authorizerDelegatedAddress))
   482  		require.NoError(t, err)
   483  
   484  		to := common.HexToAddress(authorizersAddress)
   485  		fromAddress := common.HexToAddress(ethereumAddress)
   486  
   487  		rawAbi, err := authorizers.AuthorizersMetaData.GetAbi()
   488  		require.NoError(t, err)
   489  
   490  		pack, err := rawAbi.Pack("removeAuthorizers", common.HexToAddress(authorizerDelegatedAddress))
   491  		require.NoError(t, err)
   492  
   493  		require.True(t, ethereumClient.AssertCalled(
   494  			t,
   495  			"EstimateGas",
   496  			context.Background(),
   497  			eth.CallMsg{
   498  				To:   &to,
   499  				From: fromAddress,
   500  				Data: pack,
   501  			},
   502  		))
   503  	})
   504  
   505  	t.Run("should check configuration used by IncreaseBurnerAllowance", func(t *testing.T) {
   506  		_, err := bridgeClient.IncreaseBurnerAllowance(context.Background(), amount)
   507  		require.NoError(t, err)
   508  
   509  		spenderAddress := common.HexToAddress(bridgeAddress)
   510  
   511  		to := common.HexToAddress(tokenAddress)
   512  		fromAddress := common.HexToAddress(ethereumAddress)
   513  
   514  		rawAbi, err := zcntoken.TokenMetaData.GetAbi()
   515  		require.NoError(t, err)
   516  
   517  		pack, err := rawAbi.Pack("increaseApproval", spenderAddress, big.NewInt(amount))
   518  		require.NoError(t, err)
   519  
   520  		require.True(t, ethereumClient.AssertCalled(
   521  			t,
   522  			"EstimateGas",
   523  			context.Background(),
   524  			eth.CallMsg{
   525  				To:   &to,
   526  				From: fromAddress,
   527  				Data: pack,
   528  			},
   529  		))
   530  	})
   531  
   532  	t.Run("should check configuration used by SwapETH", func(t *testing.T) {
   533  		uniswapSmartContractCodeRaw, err := hex.DecodeString(uniswapSmartContractCode)
   534  		require.NoError(t, err)
   535  
   536  		ethereumClient.On("PendingCodeAt", mock.Anything, mock.Anything).Return(uniswapSmartContractCodeRaw, nil)
   537  
   538  		_, err = bridgeClient.SwapETH(context.Background(), amount, amount)
   539  		require.NoError(t, err)
   540  
   541  		// 1. To address parameter.
   542  		to := common.HexToAddress(bridgeClient.UniswapAddress)
   543  
   544  		// 2. From address parameter.
   545  		from := common.HexToAddress(bridgeClient.EthereumAddress)
   546  
   547  		// 3. Swap amount parameter
   548  		swapAmount := big.NewInt(amount)
   549  
   550  		var rawAbi *abi.ABI
   551  
   552  		rawAbi, err = uniswapnetwork.UniswapMetaData.GetAbi()
   553  		require.NoError(t, err)
   554  
   555  		var pack []byte
   556  
   557  		pack, err = rawAbi.Pack("swapETHForZCNExactAmountOut", swapAmount)
   558  		require.NoError(t, err)
   559  
   560  		require.True(t, ethereumClient.AssertCalled(
   561  			t,
   562  			"EstimateGas",
   563  			context.Background(),
   564  			eth.CallMsg{
   565  				To:       &to,
   566  				From:     from,
   567  				Data:     pack,
   568  				Value:    swapAmount,
   569  				GasPrice: big.NewInt(400000),
   570  			},
   571  		))
   572  	})
   573  
   574  	t.Run("should check configuration used by SwapUSDC", func(t *testing.T) {
   575  		uniswapSmartContractCodeRaw, err := hex.DecodeString(uniswapSmartContractCode)
   576  		require.NoError(t, err)
   577  
   578  		ethereumClient.On("PendingCodeAt", mock.Anything, mock.Anything).Return(uniswapSmartContractCodeRaw, nil)
   579  
   580  		_, err = bridgeClient.SwapUSDC(context.Background(), amount, amount)
   581  		require.NoError(t, err)
   582  
   583  		// 1. To address parameter.
   584  		to := common.HexToAddress(bridgeClient.UniswapAddress)
   585  
   586  		// 2. From address parameter.
   587  		from := common.HexToAddress(bridgeClient.EthereumAddress)
   588  
   589  		// 3. Swap amount parameter
   590  		swapAmount := big.NewInt(amount)
   591  
   592  		var rawAbi *abi.ABI
   593  
   594  		rawAbi, err = uniswapnetwork.UniswapMetaData.GetAbi()
   595  		require.NoError(t, err)
   596  
   597  		var pack []byte
   598  
   599  		pack, err = rawAbi.Pack("swapUSDCForZCNExactAmountOut", swapAmount, swapAmount)
   600  		require.NoError(t, err)
   601  
   602  		require.True(t, ethereumClient.AssertCalled(
   603  			t,
   604  			"EstimateGas",
   605  			context.Background(),
   606  			eth.CallMsg{
   607  				To:       &to,
   608  				From:     from,
   609  				Data:     pack,
   610  				Value:    big.NewInt(0),
   611  				GasPrice: big.NewInt(400000),
   612  			},
   613  		))
   614  	})
   615  
   616  	t.Run("should check configuration used by CreateSignedTransactionFromKeyStore", func(t *testing.T) {
   617  		bridgeClient.CreateSignedTransactionFromKeyStore(ethereumClient, 400000)
   618  
   619  		require.True(t, ethereumClient.AssertCalled(
   620  			t,
   621  			"PendingNonceAt",
   622  			context.Background(),
   623  			common.HexToAddress(ethereumAddress)))
   624  
   625  		require.True(t, keyStore.AssertCalled(
   626  			t,
   627  			"TimedUnlock",
   628  			accounts.Account{
   629  				Address: common.HexToAddress(ethereumAddress),
   630  			},
   631  			password,
   632  			time.Second*2,
   633  		))
   634  	})
   635  
   636  	t.Run("should check if gas price estimation works with correct alchemy ethereum node url", func(t *testing.T) {
   637  		bridgeClient = getBridgeClient(alchemyEthereumNodeURL, ethereumClient, transactionProvider, keyStore)
   638  
   639  		_, err := bridgeClient.EstimateGasPrice(context.Background())
   640  		require.Contains(t, err.Error(), "Must be authenticated!")
   641  	})
   642  
   643  	t.Run("should check if gas price estimation works with correct tenderly ethereum node url", func(t *testing.T) {
   644  		bridgeClient = getBridgeClient(tenderlyEthereumNodeURL, ethereumClient, transactionProvider, keyStore)
   645  
   646  		_, err := bridgeClient.EstimateGasPrice(context.Background())
   647  		require.NoError(t, err)
   648  	})
   649  
   650  	t.Run("should check if gas price estimation works with incorrect ethereum node url", func(t *testing.T) {
   651  		bridgeClient = getBridgeClient(infuraEthereumNodeURL, ethereumClient, transactionProvider, keyStore)
   652  
   653  		_, err := bridgeClient.EstimateGasPrice(context.Background())
   654  		require.Error(t, err)
   655  	})
   656  }