github.com/smartcontractkit/chainlink-testing-framework/libs@v0.0.0-20240227141906-ec710b4eb1a3/blockchain/ethereum.go (about)

     1  package blockchain
     2  
     3  // Contains implementations for multi and single node ethereum clients
     4  import (
     5  	"bytes"
     6  	"context"
     7  	"crypto/ecdsa"
     8  	"encoding/hex"
     9  	"errors"
    10  	"fmt"
    11  	"math/big"
    12  	"regexp"
    13  	"strconv"
    14  	"strings"
    15  	"sync"
    16  	"time"
    17  
    18  	"github.com/ethereum/go-ethereum"
    19  	"github.com/ethereum/go-ethereum/accounts/abi"
    20  	"github.com/ethereum/go-ethereum/accounts/abi/bind"
    21  	"github.com/ethereum/go-ethereum/common"
    22  	"github.com/ethereum/go-ethereum/common/hexutil"
    23  	"github.com/ethereum/go-ethereum/core/types"
    24  	"github.com/ethereum/go-ethereum/crypto"
    25  	"github.com/ethereum/go-ethereum/ethclient"
    26  	"github.com/ethereum/go-ethereum/rpc"
    27  	"github.com/rs/zerolog"
    28  	"go.uber.org/atomic"
    29  	"golang.org/x/sync/errgroup"
    30  
    31  	"github.com/smartcontractkit/chainlink-testing-framework/libs/k8s/environment"
    32  	"github.com/smartcontractkit/chainlink-testing-framework/libs/utils/conversions"
    33  )
    34  
    35  const MaxTimeoutForFinality = 15 * time.Minute
    36  
    37  // EthereumClient wraps the client and the BlockChain network to interact with an EVM based Blockchain
    38  type EthereumClient struct {
    39  	ID                   int
    40  	Client               *ethclient.Client
    41  	rawRPC               *rpc.Client
    42  	NetworkConfig        EVMNetwork
    43  	Wallets              []*EthereumWallet
    44  	DefaultWallet        *EthereumWallet
    45  	NonceSettings        *NonceSettings
    46  	FinalizedHeader      atomic.Pointer[FinalizedHeader]
    47  	headerSubscriptions  map[string]HeaderEventSubscription
    48  	subscriptionMutex    *sync.Mutex
    49  	queueTransactions    bool
    50  	gasStats             *GasStats
    51  	connectionIssueCh    chan time.Time
    52  	connectionRestoredCh chan time.Time
    53  	doneChan             chan struct{}
    54  	l                    zerolog.Logger
    55  	subscriptionWg       sync.WaitGroup
    56  }
    57  
    58  // newEVMClient creates an EVM client for a single node/URL
    59  func newEVMClient(networkSettings EVMNetwork, logger zerolog.Logger) (EVMClient, error) {
    60  	logger.Info().
    61  		Str("Name", networkSettings.Name).
    62  		Str("URL", networkSettings.URL).
    63  		Int64("Chain ID", networkSettings.ChainID).
    64  		Bool("Simulated", networkSettings.Simulated).
    65  		Bool("Supports EIP-1559", networkSettings.SupportsEIP1559).
    66  		Bool("Finality Tag", networkSettings.FinalityTag).
    67  		Msg("Connecting client")
    68  	cl, err := ethclient.Dial(networkSettings.URL)
    69  	if err != nil {
    70  		return nil, err
    71  	}
    72  	raw, err := rpc.Dial(networkSettings.URL)
    73  	if err != nil {
    74  		return nil, err
    75  	}
    76  
    77  	ec := &EthereumClient{
    78  		NetworkConfig:       networkSettings,
    79  		Client:              cl,
    80  		rawRPC:              raw,
    81  		Wallets:             make([]*EthereumWallet, 0),
    82  		headerSubscriptions: map[string]HeaderEventSubscription{},
    83  		subscriptionMutex:   &sync.Mutex{},
    84  		queueTransactions:   false,
    85  
    86  		connectionIssueCh:    make(chan time.Time, 100), // buffered to prevent blocking, size is probably overkill, but some tests might not care
    87  		connectionRestoredCh: make(chan time.Time, 100),
    88  		doneChan:             make(chan struct{}),
    89  		l:                    logger,
    90  	}
    91  
    92  	if ec.NetworkConfig.Simulated {
    93  		ec.NonceSettings = newNonceSettings()
    94  	} else { // un-simulated chain means potentially running tests in parallel, need to share nonces
    95  		ec.NonceSettings = useGlobalNonceManager(ec.GetChainID())
    96  	}
    97  
    98  	if err := ec.LoadWallets(networkSettings); err != nil {
    99  		return nil, err
   100  	}
   101  	ec.gasStats = NewGasStats(ec.ID)
   102  	err = ec.subscribeToNewHeaders()
   103  	if err != nil {
   104  		return nil, err
   105  	}
   106  
   107  	// Check if the chain supports EIP-1559
   108  	// https://eips.ethereum.org/EIPS/eip-1559
   109  	if networkSettings.SupportsEIP1559 {
   110  		ec.l.Debug().Msg("Network supports EIP-1559, using Dynamic transactions")
   111  	} else {
   112  		ec.l.Debug().Msg("Network does NOT support EIP-1559, using Legacy transactions")
   113  	}
   114  
   115  	return wrapSingleClient(networkSettings, ec), nil
   116  }
   117  
   118  // SyncNonce sets the NonceMu and Nonces value based on existing EVMClient
   119  // it ensures the instance of EthereumClient is synced with passed EVMClient's nonce updates.
   120  func (e *EthereumClient) SyncNonce(c EVMClient) {
   121  	n := c.GetNonceSetting()
   122  	n.NonceMu.Lock()
   123  	defer n.NonceMu.Unlock()
   124  	e.NonceSettings.NonceMu = n.NonceMu
   125  	e.NonceSettings.Nonces = n.Nonces
   126  }
   127  
   128  // Get returns the underlying client type to be used generically across the framework for switching
   129  // network types
   130  func (e *EthereumClient) Get() interface{} {
   131  	return e
   132  }
   133  
   134  // GetNetworkName retrieves the ID of the network that the client interacts with
   135  func (e *EthereumClient) GetNetworkName() string {
   136  	return e.NetworkConfig.Name
   137  }
   138  
   139  // NetworkSimulated returns true if the network is a simulated geth instance, false otherwise
   140  func (e *EthereumClient) NetworkSimulated() bool {
   141  	return e.NetworkConfig.Simulated
   142  }
   143  
   144  func (e *EthereumClient) GetNonceSetting() NonceSettings {
   145  	e.NonceSettings.NonceMu.Lock()
   146  	defer e.NonceSettings.NonceMu.Unlock()
   147  	return NonceSettings{
   148  		NonceMu: e.NonceSettings.NonceMu,
   149  		Nonces:  e.NonceSettings.Nonces,
   150  	}
   151  }
   152  
   153  // GetChainID retrieves the ChainID of the network that the client interacts with
   154  func (e *EthereumClient) GetChainID() *big.Int {
   155  	return big.NewInt(e.NetworkConfig.ChainID)
   156  }
   157  
   158  // GetClients not used, only applicable to EthereumMultinodeClient
   159  func (e *EthereumClient) GetClients() []EVMClient {
   160  	return []EVMClient{e}
   161  }
   162  
   163  // DefaultWallet returns the default wallet for the network
   164  func (e *EthereumClient) GetDefaultWallet() *EthereumWallet {
   165  	return e.DefaultWallet
   166  }
   167  
   168  // DefaultWallet returns the default wallet for the network
   169  func (e *EthereumClient) GetWallets() []*EthereumWallet {
   170  	return e.Wallets
   171  }
   172  
   173  // DefaultWallet returns the default wallet for the network
   174  func (e *EthereumClient) GetNetworkConfig() *EVMNetwork {
   175  	return &e.NetworkConfig
   176  }
   177  
   178  // SetID sets client id, only used for multi-node networks
   179  func (e *EthereumClient) SetID(id int) {
   180  	e.ID = id
   181  }
   182  
   183  // SetDefaultWallet sets default wallet
   184  func (e *EthereumClient) SetDefaultWallet(num int) error {
   185  	if num >= len(e.GetWallets()) {
   186  		return fmt.Errorf("no wallet #%d found for default client", num)
   187  	}
   188  	e.DefaultWallet = e.Wallets[num]
   189  	return nil
   190  }
   191  
   192  // SetWallets sets all wallets to be used by the client
   193  func (e *EthereumClient) SetWallets(wallets []*EthereumWallet) {
   194  	e.Wallets = wallets
   195  }
   196  
   197  // LoadWallets loads wallets from config
   198  func (e *EthereumClient) LoadWallets(cfg EVMNetwork) error {
   199  	pkStrings := cfg.PrivateKeys
   200  	for _, pks := range pkStrings {
   201  		w, err := NewEthereumWallet(pks)
   202  		if err != nil {
   203  			return err
   204  		}
   205  		e.Wallets = append(e.Wallets, w)
   206  	}
   207  	if len(e.Wallets) == 0 {
   208  		return fmt.Errorf("no private keys found to load wallets")
   209  	}
   210  	e.DefaultWallet = e.Wallets[0]
   211  	return nil
   212  }
   213  
   214  // BalanceAt returns the ETH balance of the specified address
   215  func (e *EthereumClient) BalanceAt(ctx context.Context, address common.Address) (*big.Int, error) {
   216  	return e.Client.BalanceAt(ctx, address, nil)
   217  }
   218  
   219  // SwitchNode not used, only applicable to EthereumMultinodeClient
   220  func (e *EthereumClient) SwitchNode(_ int) error {
   221  	return nil
   222  }
   223  
   224  // HeaderHashByNumber gets header hash by block number
   225  func (e *EthereumClient) HeaderHashByNumber(ctx context.Context, bn *big.Int) (string, error) {
   226  	h, err := e.HeaderByNumber(ctx, bn)
   227  	if err != nil {
   228  		return "", err
   229  	}
   230  	return h.Hash.String(), nil
   231  }
   232  
   233  // HeaderTimestampByNumber gets header timestamp by number
   234  func (e *EthereumClient) HeaderTimestampByNumber(ctx context.Context, bn *big.Int) (uint64, error) {
   235  	h, err := e.HeaderByNumber(ctx, bn)
   236  	if err != nil {
   237  		return 0, err
   238  	}
   239  	return uint64(h.Timestamp.UTC().Unix()), nil
   240  }
   241  
   242  // BlockNumber gets latest block number
   243  func (e *EthereumClient) LatestBlockNumber(ctx context.Context) (uint64, error) {
   244  	bn, err := e.Client.BlockNumber(ctx)
   245  	if err != nil {
   246  		return 0, err
   247  	}
   248  	return bn, nil
   249  }
   250  
   251  func (e *EthereumClient) SendTransaction(ctx context.Context, tx *types.Transaction) error {
   252  	// for instant txs, wait for permission to go
   253  	if e.NetworkConfig.MinimumConfirmations <= 0 {
   254  		fromAddr, err := types.Sender(types.LatestSignerForChainID(tx.ChainId()), tx)
   255  		if err != nil {
   256  			return err
   257  		}
   258  		<-e.NonceSettings.registerInstantTransaction(fromAddr.Hex(), tx.Nonce())
   259  	}
   260  	return e.Client.SendTransaction(ctx, tx)
   261  }
   262  
   263  // Fund sends some ETH to an address using the default wallet
   264  func (e *EthereumClient) Fund(
   265  	toAddress string,
   266  	amount *big.Float,
   267  	gasEstimations GasEstimations,
   268  ) error {
   269  	privateKey, err := crypto.HexToECDSA(e.DefaultWallet.PrivateKey())
   270  	if err != nil {
   271  		return fmt.Errorf("invalid private key: %w", err)
   272  	}
   273  	to := common.HexToAddress(toAddress)
   274  
   275  	nonce, err := e.GetNonce(context.Background(), common.HexToAddress(e.DefaultWallet.Address()))
   276  	if err != nil {
   277  		return err
   278  	}
   279  
   280  	tx, err := e.NewTx(privateKey, nonce, to, conversions.EtherToWei(amount), gasEstimations)
   281  	if err != nil {
   282  		return err
   283  	}
   284  
   285  	e.l.Info().
   286  		Str("Token", "ETH").
   287  		Str("From", e.DefaultWallet.Address()).
   288  		Str("To", toAddress).
   289  		Str("Hash", tx.Hash().Hex()).
   290  		Uint64("Nonce", tx.Nonce()).
   291  		Str("Network Name", e.GetNetworkName()).
   292  		Str("Amount", amount.String()).
   293  		Uint64("Estimated Gas Cost", tx.Cost().Uint64()).
   294  		Msg("Funding Address")
   295  	if err := e.SendTransaction(context.Background(), tx); err != nil {
   296  		if strings.Contains(err.Error(), "nonce") {
   297  			err = fmt.Errorf("using nonce %d err: %w", nonce, err)
   298  		}
   299  		return err
   300  	}
   301  
   302  	return e.ProcessTransaction(tx)
   303  }
   304  
   305  // ReturnFunds achieves a lazy method of fund return as too many guarantees get too complex
   306  func (e *EthereumClient) ReturnFunds(fromKey *ecdsa.PrivateKey) error {
   307  	fromAddress, err := conversions.PrivateKeyToAddress(fromKey)
   308  	if err != nil {
   309  		return err
   310  	}
   311  	nonce, err := e.Client.PendingNonceAt(context.Background(), fromAddress)
   312  	if err != nil {
   313  		return err
   314  	}
   315  	balance, err := e.Client.BalanceAt(context.Background(), fromAddress, nil)
   316  	if err != nil {
   317  		return err
   318  
   319  	}
   320  	gasLimit, err := e.Client.EstimateGas(context.Background(), ethereum.CallMsg{
   321  		From: fromAddress,
   322  		To:   &e.DefaultWallet.address,
   323  	})
   324  	if err != nil {
   325  		e.l.Warn().Int("Default", 21_000).Msg("Could not estimate gas for return funds transaction, using default")
   326  		gasLimit = 21_000
   327  	}
   328  	gasPrice, err := e.Client.SuggestGasPrice(context.Background())
   329  	if err != nil {
   330  		return err
   331  	}
   332  	totalGasCost := new(big.Int).Mul(big.NewInt(0).SetUint64(gasLimit), gasPrice)
   333  	toSend := new(big.Int).Sub(balance, totalGasCost)
   334  
   335  	tx := types.NewTransaction(nonce, e.DefaultWallet.address, toSend, gasLimit, gasPrice, nil)
   336  	signedTx, err := types.SignTx(tx, types.LatestSignerForChainID(e.GetChainID()), fromKey)
   337  	if err != nil {
   338  		return err
   339  	}
   340  
   341  	// There are several errors that can happen when trying to drain an ETH wallet.
   342  	// Ultimately, we want our money back, so we'll catch errors and react to them until we get something through.
   343  
   344  	// Try to send the money back, see if we hit any issues, and if we recognize them
   345  	fundReturnErr := e.Client.SendTransaction(context.Background(), signedTx)
   346  
   347  	// Handle overshot error
   348  	overshotRe := regexp.MustCompile(`overshot (\d+)`)
   349  	for fundReturnErr != nil && strings.Contains(fundReturnErr.Error(), "overshot") {
   350  		submatches := overshotRe.FindStringSubmatch(fundReturnErr.Error())
   351  		if len(submatches) < 1 {
   352  			return fmt.Errorf("error parsing overshot amount in error: %w", err)
   353  		}
   354  		numberString := submatches[1]
   355  		overshotAmount, err := strconv.Atoi(numberString)
   356  		if err != nil {
   357  			return err
   358  		}
   359  		toSend.Sub(toSend, big.NewInt(int64(overshotAmount)))
   360  		tx := types.NewTransaction(nonce, e.DefaultWallet.address, toSend, gasLimit, gasPrice, nil)
   361  		signedTx, err = types.SignTx(tx, types.LatestSignerForChainID(e.GetChainID()), fromKey)
   362  		if err != nil {
   363  			return err
   364  		}
   365  		fundReturnErr = e.Client.SendTransaction(context.Background(), signedTx)
   366  	}
   367  
   368  	// Handle insufficient funds error
   369  	// We don't get an overshot calculation, we just know it was too much, so subtract by 1 GWei and try again
   370  	for fundReturnErr != nil && (strings.Contains(fundReturnErr.Error(), "insufficient funds") || strings.Contains(fundReturnErr.Error(), "gas too low")) {
   371  		toSend.Sub(toSend, big.NewInt(GWei))
   372  		gasLimit += 21_000 // Add 21k gas for each attempt in case gas limit is too low
   373  		tx := types.NewTransaction(nonce, e.DefaultWallet.address, toSend, gasLimit, gasPrice, nil)
   374  		signedTx, err = types.SignTx(tx, types.LatestSignerForChainID(e.GetChainID()), fromKey)
   375  		if err != nil {
   376  			return err
   377  		}
   378  		fundReturnErr = e.Client.SendTransaction(context.Background(), signedTx)
   379  	}
   380  
   381  	e.l.Info().
   382  		Uint64("Funds", toSend.Uint64()).
   383  		Str("From", fromAddress.Hex()).
   384  		Str("To", e.DefaultWallet.Address()).
   385  		Msg("Returning funds to Default Wallet")
   386  	return fundReturnErr
   387  }
   388  
   389  // EstimateCostForChainlinkOperations calculates required amount of ETH for amountOfOperations Chainlink operations
   390  // based on the network's suggested gas price and the chainlink gas limit. This is fairly imperfect and should be used
   391  // as only a rough, upper-end estimate instead of an exact calculation.
   392  // See https://ethereum.org/en/developers/docs/gas/#post-london for info on how gas calculation works
   393  func (e *EthereumClient) EstimateCostForChainlinkOperations(amountOfOperations int) (*big.Float, error) {
   394  	bigAmountOfOperations := big.NewInt(int64(amountOfOperations))
   395  	gasPriceInWei, err := e.Client.SuggestGasPrice(context.Background())
   396  	if err != nil {
   397  		return nil, err
   398  	}
   399  
   400  	// https://ethereum.stackexchange.com/questions/19665/how-to-calculate-transaction-fee
   401  	// total gas limit = chainlink gas limit + gas limit buffer
   402  	gasLimit := e.NetworkConfig.GasEstimationBuffer + e.NetworkConfig.ChainlinkTransactionLimit
   403  	// gas cost for TX = total gas limit * estimated gas price
   404  	gasCostPerOperationWei := big.NewInt(1).Mul(big.NewInt(1).SetUint64(gasLimit), gasPriceInWei)
   405  	gasCostPerOperationETH := conversions.WeiToEther(gasCostPerOperationWei)
   406  	// total Wei needed for all TXs = total value for TX * number of TXs
   407  	totalWeiForAllOperations := big.NewInt(1).Mul(gasCostPerOperationWei, bigAmountOfOperations)
   408  	totalEthForAllOperations := conversions.WeiToEther(totalWeiForAllOperations)
   409  
   410  	e.l.Debug().
   411  		Int("Number of Operations", amountOfOperations).
   412  		Uint64("Gas Limit per Operation", gasLimit).
   413  		Str("Value per Operation (ETH)", gasCostPerOperationETH.String()).
   414  		Str("Total (ETH)", totalEthForAllOperations.String()).
   415  		Msg("Calculated ETH for Chainlink Operations")
   416  
   417  	return totalEthForAllOperations, nil
   418  }
   419  
   420  func (e *EthereumClient) RawJsonRPCCall(ctx context.Context, result interface{}, method string, params ...interface{}) error {
   421  	err := e.rawRPC.CallContext(ctx, &result, method, params...)
   422  
   423  	return err
   424  }
   425  
   426  // DeployContract acts as a general contract deployment tool to an ethereum chain
   427  func (e *EthereumClient) DeployContract(
   428  	contractName string,
   429  	deployer ContractDeployer,
   430  ) (*common.Address, *types.Transaction, interface{}, error) {
   431  	opts, err := e.TransactionOpts(e.DefaultWallet)
   432  	if err != nil {
   433  		return nil, nil, nil, err
   434  	}
   435  	if !e.NetworkConfig.SupportsEIP1559 {
   436  		opts.GasPrice, err = e.EstimateGasPrice()
   437  		if err != nil {
   438  			return nil, nil, nil, err
   439  		}
   440  	}
   441  
   442  	contractAddress, transaction, contractInstance, err := deployer(opts, e.Client)
   443  	if err != nil {
   444  		if strings.Contains(err.Error(), "nonce") {
   445  			err = fmt.Errorf("using nonce %d err: %w", opts.Nonce.Uint64(), err)
   446  		}
   447  		return nil, nil, nil, err
   448  	}
   449  
   450  	if err = e.ProcessTransaction(transaction); err != nil {
   451  		return nil, nil, nil, err
   452  	}
   453  
   454  	e.l.Info().
   455  		Str("Contract Address", contractAddress.Hex()).
   456  		Str("Contract Name", contractName).
   457  		Str("From", e.DefaultWallet.Address()).
   458  		Str("Total Gas Cost", conversions.WeiToEther(transaction.Cost()).String()).
   459  		Str("Network Name", e.NetworkConfig.Name).
   460  		Msg("Deployed contract")
   461  	return &contractAddress, transaction, contractInstance, err
   462  }
   463  
   464  // LoadContract load already deployed contract instance
   465  func (e *EthereumClient) LoadContract(contractName string, contractAddress common.Address, loader ContractLoader) (interface{}, error) {
   466  	contractInstance, err := loader(contractAddress, e.Client)
   467  	if err != nil {
   468  		return nil, err
   469  	}
   470  	e.l.Info().
   471  		Str("Contract Address", contractAddress.Hex()).
   472  		Str("Contract Name", contractName).
   473  		Str("Network Name", e.NetworkConfig.Name).
   474  		Msg("Loaded contract instance")
   475  	return contractInstance, err
   476  }
   477  
   478  // TransactionOpts returns the base Tx options for 'transactions' that interact with a smart contract. Since most
   479  // contract interactions in this framework are designed to happen through abigen calls, it's intentionally quite bare.
   480  func (e *EthereumClient) TransactionOpts(from *EthereumWallet) (*bind.TransactOpts, error) {
   481  	privateKey, err := crypto.HexToECDSA(from.PrivateKey())
   482  	if err != nil {
   483  		return nil, fmt.Errorf("invalid private key: %w", err)
   484  	}
   485  	opts, err := bind.NewKeyedTransactorWithChainID(privateKey, big.NewInt(e.NetworkConfig.ChainID))
   486  	if err != nil {
   487  		return nil, err
   488  	}
   489  	opts.From = common.HexToAddress(from.Address())
   490  	opts.Context = context.Background()
   491  
   492  	nonce, err := e.GetNonce(context.Background(), common.HexToAddress(from.Address()))
   493  	if err != nil {
   494  		return nil, err
   495  	}
   496  	opts.Nonce = big.NewInt(int64(nonce))
   497  
   498  	if e.NetworkConfig.MinimumConfirmations <= 0 { // Wait for your turn to send on an L2 chain
   499  		<-e.NonceSettings.registerInstantTransaction(from.Address(), nonce)
   500  	}
   501  	// if the gas limit is less than the default gas limit, use the default
   502  	if e.NetworkConfig.DefaultGasLimit > opts.GasLimit {
   503  		opts.GasLimit = e.NetworkConfig.DefaultGasLimit
   504  	}
   505  	if !e.NetworkConfig.SupportsEIP1559 {
   506  		opts.GasPrice, err = e.EstimateGasPrice()
   507  		if err != nil {
   508  			return nil, err
   509  		}
   510  	}
   511  	return opts, nil
   512  }
   513  
   514  func (e *EthereumClient) NewTx(
   515  	fromPrivateKey *ecdsa.PrivateKey,
   516  	nonce uint64,
   517  	to common.Address,
   518  	value *big.Int,
   519  	gasEstimations GasEstimations,
   520  ) (*types.Transaction, error) {
   521  	var (
   522  		tx  *types.Transaction
   523  		err error
   524  	)
   525  	if e.NetworkConfig.SupportsEIP1559 {
   526  		tx, err = types.SignNewTx(fromPrivateKey, types.LatestSignerForChainID(e.GetChainID()), &types.DynamicFeeTx{
   527  			ChainID:   e.GetChainID(),
   528  			Nonce:     nonce,
   529  			To:        &to,
   530  			Value:     value,
   531  			GasTipCap: gasEstimations.GasTipCap,
   532  			GasFeeCap: gasEstimations.GasFeeCap,
   533  			Gas:       gasEstimations.GasUnits,
   534  		})
   535  		if err != nil {
   536  			return nil, err
   537  		}
   538  	} else {
   539  		tx, err = types.SignNewTx(fromPrivateKey, types.LatestSignerForChainID(e.GetChainID()), &types.LegacyTx{
   540  			Nonce:    nonce,
   541  			To:       &to,
   542  			Value:    value,
   543  			GasPrice: gasEstimations.GasPrice,
   544  			Gas:      gasEstimations.GasUnits,
   545  		})
   546  		if err != nil {
   547  			return nil, err
   548  		}
   549  	}
   550  	return tx, nil
   551  }
   552  
   553  // MarkTxAsSent On an L2 chain, indicate the tx has been sent
   554  func (e *EthereumClient) MarkTxAsSentOnL2(tx *types.Transaction) error {
   555  	if e.NetworkConfig.MinimumConfirmations > 0 {
   556  		return nil
   557  	}
   558  	fromAddr, err := types.Sender(types.LatestSignerForChainID(tx.ChainId()), tx)
   559  	if err != nil {
   560  		return err
   561  	}
   562  	e.NonceSettings.sentInstantTransaction(fromAddr.Hex())
   563  	return nil
   564  }
   565  
   566  // ProcessTransaction will queue or wait on a transaction depending on whether parallel transactions are enabled
   567  func (e *EthereumClient) ProcessTransaction(tx *types.Transaction) error {
   568  	e.l.Trace().Str("Hash", tx.Hash().Hex()).Msg("Processing Tx")
   569  	var txConfirmer HeaderEventSubscription
   570  	if e.GetNetworkConfig().MinimumConfirmations <= 0 {
   571  		err := e.MarkTxAsSentOnL2(tx)
   572  		if err != nil {
   573  			return err
   574  		}
   575  		txConfirmer = NewInstantConfirmer(e, tx.Hash(), nil, nil, e.l)
   576  	} else {
   577  		txConfirmer = NewTransactionConfirmer(e, tx, e.GetNetworkConfig().MinimumConfirmations, e.l)
   578  	}
   579  
   580  	e.AddHeaderEventSubscription(tx.Hash().String(), txConfirmer)
   581  
   582  	if !e.queueTransactions { // For sequential transactions
   583  		e.l.Debug().Str("Hash", tx.Hash().String()).Msg("Waiting for TX to confirm before moving on")
   584  		defer e.DeleteHeaderEventSubscription(tx.Hash().String())
   585  		return txConfirmer.Wait()
   586  	}
   587  	return nil
   588  }
   589  
   590  // ProcessEvent will queue or wait on an event depending on whether parallel transactions are enabled
   591  func (e *EthereumClient) ProcessEvent(name string, event *types.Log, confirmedChan chan bool, errorChan chan error) error {
   592  	var eventConfirmer HeaderEventSubscription
   593  	if e.GetNetworkConfig().MinimumConfirmations <= 0 {
   594  		eventConfirmer = NewInstantConfirmer(e, event.TxHash, confirmedChan, errorChan, e.l)
   595  	} else {
   596  		eventConfirmer = NewEventConfirmer(name, e, event, e.GetNetworkConfig().MinimumConfirmations, confirmedChan, errorChan)
   597  	}
   598  
   599  	subscriptionHash := fmt.Sprintf("%s-%s", event.TxHash.Hex(), name) // Many events can occupy the same tx hash
   600  	e.AddHeaderEventSubscription(subscriptionHash, eventConfirmer)
   601  
   602  	if !e.queueTransactions { // For sequential transactions
   603  		e.l.Debug().Str("Hash", event.Address.Hex()).Msg("Waiting for Event to confirm before moving on")
   604  		defer e.DeleteHeaderEventSubscription(subscriptionHash)
   605  		return eventConfirmer.Wait()
   606  	}
   607  	return nil
   608  }
   609  
   610  // PollFinalizedHeader continuously polls the latest finalized header and stores it in the client
   611  func (e *EthereumClient) PollFinality() error {
   612  	if e.NetworkConfig.FinalityDepth > 0 {
   613  		return fmt.Errorf("finality depth is greater than zero. no need to poll for finality")
   614  	}
   615  	f := newGlobalFinalizedHeaderManager(e)
   616  	if f == nil {
   617  		return fmt.Errorf("could not create finalized header manager")
   618  	}
   619  	e.FinalizedHeader.Store(f)
   620  	e.AddHeaderEventSubscription(FinalizedHeaderKey, f)
   621  	return nil
   622  }
   623  
   624  // CancelFinalityPolling stops polling for the latest finalized header
   625  func (e *EthereumClient) CancelFinalityPolling() {
   626  	if _, ok := e.headerSubscriptions[FinalizedHeaderKey]; ok {
   627  		e.DeleteHeaderEventSubscription(FinalizedHeaderKey)
   628  	}
   629  }
   630  
   631  // WaitForFinalizedTx waits for a transaction to be finalized
   632  // If the network is simulated, it will return immediately
   633  // otherwise it waits for the transaction to be finalized and returns the block number and time of the finalization
   634  func (e *EthereumClient) WaitForFinalizedTx(txHash common.Hash) (*big.Int, time.Time, error) {
   635  	if e.NetworkSimulated() {
   636  		return nil, time.Time{}, nil
   637  	}
   638  
   639  	receipt, err := e.Client.TransactionReceipt(context.Background(), txHash)
   640  	if err != nil {
   641  		return nil, time.Time{}, err
   642  	}
   643  	txHdr, err := e.HeaderByNumber(context.Background(), receipt.BlockNumber)
   644  	if err != nil {
   645  		return nil, time.Time{}, err
   646  	}
   647  	finalizer := NewTransactionFinalizer(e, txHdr, receipt.TxHash)
   648  	key := "txFinalizer-" + txHash.String()
   649  	e.AddHeaderEventSubscription(key, finalizer)
   650  	defer e.DeleteHeaderEventSubscription(key)
   651  	err = finalizer.Wait()
   652  	if err != nil {
   653  		return nil, time.Time{}, err
   654  	}
   655  	return finalizer.FinalizedBy, finalizer.FinalizedAt, nil
   656  }
   657  
   658  // IsTxHeadFinalized checks if the transaction is finalized on chain
   659  // in case of network with finality tag if the tx is not finalized it returns false,
   660  // the latest finalized header number and the time at which it was finalized
   661  // if the tx is finalized it returns true, the finalized header number by which the tx was considered finalized and the time at which it was finalized
   662  // In case of simulated network, it always returns true
   663  func (e *EthereumClient) IsTxHeadFinalized(txHdr, header *SafeEVMHeader) (bool, *big.Int, time.Time, error) {
   664  	if e.NetworkSimulated() {
   665  		return true, nil, time.Time{}, nil
   666  	}
   667  	if e.NetworkConfig.FinalityDepth > 0 {
   668  		if header.Number.Cmp(new(big.Int).Add(txHdr.Number,
   669  			big.NewInt(int64(e.NetworkConfig.FinalityDepth)))) > 0 {
   670  			return true, header.Number, header.Timestamp, nil
   671  		}
   672  		return false, nil, time.Time{}, nil
   673  	}
   674  	fHead := e.FinalizedHeader.Load()
   675  	if fHead != nil {
   676  		latestFinalized := fHead.LatestFinalized.Load().(*big.Int)
   677  		latestFinalizedAt := fHead.FinalizedAt.Load().(time.Time)
   678  		if latestFinalized.Cmp(txHdr.Number) >= 0 {
   679  			return true, latestFinalized, latestFinalizedAt, nil
   680  		}
   681  		return false, latestFinalized, latestFinalizedAt, nil
   682  	}
   683  	return false, nil, time.Time{}, fmt.Errorf("no finalized head found. start polling for finalized header")
   684  }
   685  
   686  // IsTxConfirmed checks if the transaction is confirmed on chain or not
   687  func (e *EthereumClient) IsTxConfirmed(txHash common.Hash) (bool, error) {
   688  	ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
   689  	tx, isPending, err := e.Client.TransactionByHash(ctx, txHash)
   690  	cancel()
   691  	if err != nil {
   692  		if errors.Is(err, ethereum.NotFound) { // not found is fine, it's not on chain yet
   693  			return false, nil
   694  		}
   695  		return !isPending, err
   696  	}
   697  	if !isPending && e.NetworkConfig.MinimumConfirmations > 0 { // Instant chains don't bother with this receipt nonsense
   698  		ctx, cancel = context.WithTimeout(context.Background(), time.Second*5)
   699  		receipt, err := e.Client.TransactionReceipt(ctx, txHash)
   700  		cancel()
   701  		if err != nil {
   702  			if errors.Is(err, ethereum.NotFound) { // not found is fine, it's not on chain yet
   703  				return false, nil
   704  			}
   705  			return !isPending, err
   706  		}
   707  		e.gasStats.AddClientTXData(TXGasData{
   708  			TXHash:            txHash.String(),
   709  			Value:             tx.Value().Uint64(),
   710  			GasLimit:          tx.Gas(),
   711  			GasUsed:           receipt.GasUsed,
   712  			GasPrice:          tx.GasPrice().Uint64(),
   713  			CumulativeGasUsed: receipt.CumulativeGasUsed,
   714  		})
   715  		if receipt.Status == 0 { // 0 indicates failure, 1 indicates success
   716  			reason, err := e.errorReason(e.Client, tx, receipt)
   717  			if err != nil {
   718  				e.l.Warn().Str("TX Hash", txHash.Hex()).
   719  					Str("To", tx.To().Hex()).
   720  					Uint64("Nonce", tx.Nonce()).
   721  					Str("Error extracting reason", err.Error()).
   722  					Msg("Transaction failed and was reverted! Unable to retrieve reason!")
   723  			} else {
   724  				e.l.Warn().Str("TX Hash", txHash.Hex()).
   725  					Str("Revert reason", reason).
   726  					Msg("Transaction failed and was reverted!")
   727  			}
   728  			return false, fmt.Errorf("transaction failed and was reverted")
   729  		}
   730  	}
   731  	return !isPending, err
   732  }
   733  
   734  // IsEventConfirmed returns if eth client can confirm that the event happened
   735  func (e *EthereumClient) IsEventConfirmed(event *types.Log) (confirmed, removed bool, err error) {
   736  	if event.Removed {
   737  		return false, event.Removed, nil
   738  	}
   739  	eventTx, isPending, err := e.Client.TransactionByHash(context.Background(), event.TxHash)
   740  	if err != nil {
   741  		return false, event.Removed, err
   742  	}
   743  	if isPending {
   744  		return false, event.Removed, nil
   745  	}
   746  	eventReceipt, err := e.Client.TransactionReceipt(context.Background(), eventTx.Hash())
   747  	if err != nil {
   748  		return false, event.Removed, err
   749  	}
   750  	if eventReceipt.Status == 0 { // Failed event tx
   751  		reason, err := e.errorReason(e.Client, eventTx, eventReceipt)
   752  		if err != nil {
   753  			e.l.Warn().Str("TX Hash", eventTx.Hash().Hex()).
   754  				Str("Error extracting reason", err.Error()).
   755  				Msg("Transaction failed and was reverted! Unable to retrieve reason!")
   756  		} else {
   757  			e.l.Warn().Str("TX Hash", eventTx.Hash().Hex()).
   758  				Str("Revert reason", reason).
   759  				Msg("Transaction failed and was reverted!")
   760  		}
   761  		return false, event.Removed, err
   762  	}
   763  	headerByNumber, err := e.HeaderByNumber(context.Background(), big.NewInt(0).SetUint64(event.BlockNumber))
   764  	if err != nil || headerByNumber == nil {
   765  		return false, event.Removed, err
   766  	}
   767  	if headerByNumber.Hash != event.BlockHash {
   768  		return false, event.Removed, nil
   769  	}
   770  
   771  	return true, event.Removed, nil
   772  }
   773  
   774  // GetTxReceipt returns the receipt of the transaction if available, error otherwise
   775  func (e *EthereumClient) GetTxReceipt(txHash common.Hash) (*types.Receipt, error) {
   776  	receipt, err := e.Client.TransactionReceipt(context.Background(), txHash)
   777  	if err != nil {
   778  		return nil, err
   779  	}
   780  	return receipt, nil
   781  }
   782  
   783  // RevertReasonFromTx returns the revert reason for the transaction error by parsing through abi defined error list
   784  func (e *EthereumClient) RevertReasonFromTx(txHash common.Hash, abiString string) (string, interface{}, error) {
   785  	tx, _, err := e.Client.TransactionByHash(context.Background(), txHash)
   786  	if err != nil {
   787  		return "", nil, err
   788  	}
   789  	re, err := e.GetTxReceipt(txHash)
   790  	if err != nil {
   791  		return "", nil, err
   792  	}
   793  	errData, err := e.errorReason(e.Client, tx, re)
   794  	if err != nil {
   795  		return "", nil, err
   796  	}
   797  	if errData == "" {
   798  		return "", nil, fmt.Errorf("no revert reason found")
   799  	}
   800  	data, err := hex.DecodeString(errData[2:])
   801  	if err != nil {
   802  		return "", nil, err
   803  	}
   804  	jsonABI, err := abi.JSON(strings.NewReader(abiString))
   805  	if err != nil {
   806  		return "", nil, err
   807  	}
   808  	for errName, abiError := range jsonABI.Errors {
   809  		if bytes.Equal(data[:4], abiError.ID.Bytes()[:4]) {
   810  			// Found a matching error
   811  			v, err := abiError.Unpack(data)
   812  			if err != nil {
   813  				return "", nil, err
   814  			}
   815  			return errName, v, nil
   816  		}
   817  	}
   818  	return "", nil, fmt.Errorf("revert Reason could not be found for given abistring")
   819  }
   820  
   821  // ParallelTransactions when enabled, sends the transaction without waiting for transaction confirmations. The hashes
   822  // are then stored within the client and confirmations can be waited on by calling WaitForEvents.
   823  func (e *EthereumClient) ParallelTransactions(enabled bool) {
   824  	e.queueTransactions = enabled
   825  }
   826  
   827  // Close tears down the current open Ethereum client
   828  func (e *EthereumClient) Close() error {
   829  	// close(e.NonceSettings.doneChan)
   830  	close(e.doneChan)
   831  	e.subscriptionWg.Wait()
   832  	return nil
   833  }
   834  
   835  // EstimateTransactionGasCost estimates the current total gas cost for a simple transaction
   836  func (e *EthereumClient) EstimateTransactionGasCost() (*big.Int, error) {
   837  	gasPrice, err := e.Client.SuggestGasPrice(context.Background())
   838  	if err != nil {
   839  		return nil, err
   840  	}
   841  	return gasPrice.Mul(gasPrice, big.NewInt(21000)), err
   842  }
   843  
   844  // GasStats retrieves all information on gas spent by this client
   845  func (e *EthereumClient) GasStats() *GasStats {
   846  	return e.gasStats
   847  }
   848  
   849  // EstimateGas estimates all gas values based on call data
   850  func (e *EthereumClient) EstimateGas(callMsg ethereum.CallMsg) (GasEstimations, error) {
   851  	var (
   852  		gasUnits  uint64
   853  		gasTipCap *big.Int
   854  		gasFeeCap *big.Int
   855  		err       error
   856  	)
   857  	if callMsg.To == nil && callMsg.Data == nil {
   858  		return GasEstimations{}, fmt.Errorf("you've called EstimateGas with a nil To address, this can cause weird errors and inaccuracies, provide a To address in your callMsg, or use EstimateGasPrice for just a price")
   859  	}
   860  	ctx, cancel := context.WithTimeout(context.Background(), e.NetworkConfig.Timeout.Duration)
   861  	// Gas Units
   862  	gasUnits, err = e.Client.EstimateGas(ctx, callMsg)
   863  	cancel()
   864  	if err != nil {
   865  		return GasEstimations{}, err
   866  	}
   867  
   868  	gasPriceBuffer := big.NewInt(0).SetUint64(e.NetworkConfig.GasEstimationBuffer)
   869  	// Legacy Gas Price
   870  	ctx, cancel = context.WithTimeout(context.Background(), e.NetworkConfig.Timeout.Duration)
   871  	gasPrice, err := e.Client.SuggestGasPrice(ctx)
   872  	cancel()
   873  	if err != nil {
   874  		return GasEstimations{}, err
   875  	}
   876  	gasPrice.Add(gasPrice, gasPriceBuffer)
   877  
   878  	if e.NetworkConfig.SupportsEIP1559 {
   879  		// GasTipCap
   880  		ctx, cancel := context.WithTimeout(context.Background(), e.NetworkConfig.Timeout.Duration)
   881  		gasTipCap, err = e.Client.SuggestGasTipCap(ctx)
   882  		cancel()
   883  		if err != nil {
   884  			return GasEstimations{}, err
   885  		}
   886  		gasTipCap.Add(gasTipCap, gasPriceBuffer)
   887  
   888  		// GasFeeCap
   889  		ctx, cancel = context.WithTimeout(context.Background(), e.NetworkConfig.Timeout.Duration)
   890  		latestHeader, err := e.HeaderByNumber(ctx, nil)
   891  		cancel()
   892  		if err != nil {
   893  			return GasEstimations{}, err
   894  		}
   895  		baseFeeMult := big.NewInt(1).Mul(latestHeader.BaseFee, big.NewInt(2))
   896  		gasFeeCap = baseFeeMult.Add(baseFeeMult, gasTipCap)
   897  	} else {
   898  		gasFeeCap = gasPrice
   899  		gasTipCap = gasPrice
   900  	}
   901  
   902  	// Total Gas Cost
   903  	totalGasCost := big.NewInt(0).Mul(gasFeeCap, new(big.Int).SetUint64(gasUnits))
   904  
   905  	return GasEstimations{
   906  		GasUnits:     gasUnits,
   907  		GasPrice:     gasPrice,
   908  		GasFeeCap:    gasFeeCap,
   909  		GasTipCap:    gasTipCap,
   910  		TotalGasCost: totalGasCost,
   911  	}, nil
   912  }
   913  
   914  func (e *EthereumClient) EstimateGasPrice() (*big.Int, error) {
   915  	ctx, cancel := context.WithTimeout(context.Background(), e.NetworkConfig.Timeout.Duration)
   916  	defer cancel()
   917  	return e.Client.SuggestGasPrice(ctx)
   918  }
   919  
   920  // ConnectionIssue returns a channel that will receive a timestamp when the connection is lost
   921  func (e *EthereumClient) ConnectionIssue() chan time.Time {
   922  	return e.connectionIssueCh
   923  }
   924  
   925  // ConnectionRestored returns a channel that will receive a timestamp when the connection is restored
   926  func (e *EthereumClient) ConnectionRestored() chan time.Time {
   927  	return e.connectionRestoredCh
   928  }
   929  
   930  func (e *EthereumClient) Backend() bind.ContractBackend {
   931  	return e.Client
   932  }
   933  
   934  func (e *EthereumClient) DeployBackend() bind.DeployBackend {
   935  	return e.Client
   936  }
   937  
   938  func (e *EthereumClient) SubscribeNewHeaders(
   939  	ctx context.Context,
   940  	headerChan chan *SafeEVMHeader,
   941  ) (ethereum.Subscription, error) {
   942  	clientSub, err := e.rawRPC.EthSubscribe(ctx, headerChan, "newHeads")
   943  	if err != nil {
   944  		return nil, err
   945  	}
   946  
   947  	return clientSub, err
   948  }
   949  
   950  // HeaderByNumber retrieves a Safe EVM header by number, nil for latest
   951  func (e *EthereumClient) HeaderByNumber(
   952  	ctx context.Context,
   953  	number *big.Int,
   954  ) (*SafeEVMHeader, error) {
   955  	var head *SafeEVMHeader
   956  	err := e.rawRPC.CallContext(ctx, &head, "eth_getBlockByNumber", toBlockNumArg(number), false)
   957  	if err == nil && head == nil {
   958  		err = ethereum.NotFound
   959  	}
   960  	return head, err
   961  }
   962  
   963  // HeaderByHash retrieves a Safe EVM header by hash
   964  func (e *EthereumClient) HeaderByHash(ctx context.Context, hash common.Hash) (*SafeEVMHeader, error) {
   965  	var head *SafeEVMHeader
   966  	err := e.rawRPC.CallContext(ctx, &head, "eth_getBlockByHash", hash, false)
   967  	if err == nil && head == nil {
   968  		err = ethereum.NotFound
   969  	}
   970  	return head, err
   971  }
   972  
   973  // toBlockNumArg translates a block number to the correct argument for the RPC call
   974  func toBlockNumArg(number *big.Int) string {
   975  	if number == nil {
   976  		return "latest"
   977  	}
   978  	pending := big.NewInt(-1)
   979  	if number.Cmp(pending) == 0 {
   980  		return "pending"
   981  	}
   982  	return hexutil.EncodeBig(number)
   983  }
   984  
   985  // AddHeaderEventSubscription adds a new header subscriber within the client to receive new headers
   986  func (e *EthereumClient) AddHeaderEventSubscription(key string, subscriber HeaderEventSubscription) {
   987  	e.subscriptionMutex.Lock()
   988  	defer e.subscriptionMutex.Unlock()
   989  	e.headerSubscriptions[key] = subscriber
   990  }
   991  
   992  // DeleteHeaderEventSubscription removes a header subscriber from the map
   993  func (e *EthereumClient) DeleteHeaderEventSubscription(key string) {
   994  	e.subscriptionMutex.Lock()
   995  	defer e.subscriptionMutex.Unlock()
   996  	delete(e.headerSubscriptions, key)
   997  }
   998  
   999  // WaitForEvents is a blocking function that waits for all event subscriptions that have been queued within the client.
  1000  func (e *EthereumClient) WaitForEvents() error {
  1001  	e.l.Debug().Msg("Waiting for blockchain events to finish before continuing")
  1002  	queuedEvents := e.GetHeaderSubscriptions()
  1003  
  1004  	g := errgroup.Group{}
  1005  
  1006  	for subName, sub := range queuedEvents {
  1007  		subName := subName
  1008  		sub := sub
  1009  		g.Go(func() error {
  1010  			defer func() {
  1011  				// if the subscription is complete, delete it from the queue
  1012  				if sub.Complete() {
  1013  					e.DeleteHeaderEventSubscription(subName)
  1014  				}
  1015  			}()
  1016  			return sub.Wait()
  1017  		})
  1018  	}
  1019  
  1020  	return g.Wait()
  1021  }
  1022  
  1023  // SubscribeFilterLogs subscribes to the results of a streaming filter query.
  1024  func (e *EthereumClient) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) {
  1025  	return e.Client.SubscribeFilterLogs(ctx, q, ch)
  1026  }
  1027  
  1028  // FilterLogs executes a filter query
  1029  func (e *EthereumClient) FilterLogs(ctx context.Context, filterQuery ethereum.FilterQuery) ([]types.Log, error) {
  1030  	return e.Client.FilterLogs(ctx, filterQuery)
  1031  }
  1032  
  1033  // GetLatestFinalizedBlockHeader returns the latest finalized block header
  1034  // if finality tag is enabled, it returns the latest finalized block header
  1035  // otherwise it returns the block header for the block obtained by latest block number - finality depth
  1036  func (e *EthereumClient) GetLatestFinalizedBlockHeader(ctx context.Context) (*types.Header, error) {
  1037  	if e.NetworkConfig.FinalityTag {
  1038  		return e.Client.HeaderByNumber(ctx, big.NewInt(rpc.FinalizedBlockNumber.Int64()))
  1039  	}
  1040  	if e.NetworkConfig.FinalityDepth == 0 {
  1041  		return nil, fmt.Errorf("finality depth is 0 and finality tag is not enabled")
  1042  	}
  1043  	header, err := e.Client.HeaderByNumber(ctx, nil)
  1044  	if err != nil {
  1045  		return nil, err
  1046  	}
  1047  	latestBlockNumber := header.Number.Uint64()
  1048  	finalizedBlockNumber := latestBlockNumber - e.NetworkConfig.FinalityDepth
  1049  	return e.Client.HeaderByNumber(ctx, big.NewInt(int64(finalizedBlockNumber)))
  1050  }
  1051  
  1052  // EstimatedFinalizationTime returns the estimated time it takes for a block to be finalized
  1053  // for networks with finality tag enabled, it returns the time between the current and next finalized block
  1054  // for networks with finality depth enabled, it returns the time to mine blocks equal to finality depth
  1055  func (e *EthereumClient) EstimatedFinalizationTime(ctx context.Context) (time.Duration, error) {
  1056  	if e.NetworkConfig.TimeToReachFinality.Duration != 0 {
  1057  		return e.NetworkConfig.TimeToReachFinality.Duration, nil
  1058  	}
  1059  	e.l.Info().Msg("TimeToReachFinality is not provided. Calculating estimated finalization time")
  1060  	if e.NetworkConfig.FinalityTag {
  1061  		return e.TimeBetweenFinalizedBlocks(ctx, MaxTimeoutForFinality)
  1062  	}
  1063  	blckTime, err := e.AvgBlockTime(ctx)
  1064  	if err != nil {
  1065  		return 0, err
  1066  	}
  1067  	if e.NetworkConfig.FinalityDepth == 0 {
  1068  		return 0, fmt.Errorf("finality depth is 0 and finality tag is not enabled")
  1069  	}
  1070  	timeBetween := time.Duration(e.NetworkConfig.FinalityDepth) * blckTime
  1071  	e.l.Info().
  1072  		Str("Time", timeBetween.String()).
  1073  		Str("Network", e.GetNetworkName()).
  1074  		Msg("Estimated finalization time")
  1075  	return timeBetween, nil
  1076  
  1077  }
  1078  
  1079  // TimeBetweenFinalizedBlocks is used to calculate the time between finalized blocks for chains with finality tag enabled
  1080  func (e *EthereumClient) TimeBetweenFinalizedBlocks(ctx context.Context, maxTimeToWait time.Duration) (time.Duration, error) {
  1081  	if !e.NetworkConfig.FinalityTag {
  1082  		return 0, fmt.Errorf("finality tag is not enabled; cannot calculate time between finalized blocks")
  1083  	}
  1084  	currentFinalizedHeader, err := e.GetLatestFinalizedBlockHeader(ctx)
  1085  	if err != nil {
  1086  		return 0, err
  1087  	}
  1088  	hdrChannel := make(chan *types.Header)
  1089  	var sub ethereum.Subscription
  1090  	sub, err = e.Client.SubscribeNewHead(ctx, hdrChannel)
  1091  	if err != nil {
  1092  		return 0, err
  1093  	}
  1094  	defer sub.Unsubscribe()
  1095  	c, cancel := context.WithTimeout(ctx, maxTimeToWait)
  1096  	defer cancel()
  1097  	for {
  1098  		select {
  1099  		case <-c.Done():
  1100  			return 0, fmt.Errorf("timed out waiting for next finalized block. If the finality time is more than %s, provide it as TimeToReachFinality in Network config: %w", maxTimeToWait, c.Err())
  1101  		case <-hdrChannel:
  1102  			// a new header is received now query the finalized block
  1103  			nextFinalizedHeader, err := e.GetLatestFinalizedBlockHeader(ctx)
  1104  			if err != nil {
  1105  				return 0, err
  1106  			}
  1107  			if nextFinalizedHeader.Number.Cmp(currentFinalizedHeader.Number) > 0 {
  1108  				timeBetween := time.Unix(int64(nextFinalizedHeader.Time), 0).Sub(time.Unix(int64(currentFinalizedHeader.Time), 0))
  1109  				e.l.Info().
  1110  					Str("Time", timeBetween.String()).
  1111  					Str("Network", e.GetNetworkName()).
  1112  					Msg("Time between finalized blocks")
  1113  				return timeBetween, nil
  1114  			}
  1115  		case subErr := <-sub.Err():
  1116  			return 0, subErr
  1117  		}
  1118  	}
  1119  }
  1120  
  1121  // AvgBlockTime calculates the average block time over the last 100 blocks for non-simulated networks
  1122  // and the last 10 blocks for simulated networks.
  1123  func (e *EthereumClient) AvgBlockTime(ctx context.Context) (time.Duration, error) {
  1124  	header, err := e.Client.HeaderByNumber(ctx, nil)
  1125  	if err != nil {
  1126  		return 0, err
  1127  	}
  1128  	latestBlockNumber := header.Number.Uint64()
  1129  	numBlocks := uint64(100) // Number of blocks to consider for calculating block time
  1130  	if e.NetworkSimulated() {
  1131  		numBlocks = uint64(10)
  1132  	}
  1133  	startBlockNumber := latestBlockNumber - numBlocks + 1
  1134  	if startBlockNumber <= 0 {
  1135  		return 0, fmt.Errorf("not enough blocks mined to calculate block time")
  1136  	}
  1137  	totalTime := time.Duration(0)
  1138  	var previousHeader *types.Header
  1139  	previousHeader, err = e.Client.HeaderByNumber(ctx, big.NewInt(int64(startBlockNumber-1)))
  1140  	if err != nil {
  1141  		return totalTime, err
  1142  	}
  1143  	for i := startBlockNumber; i <= latestBlockNumber; i++ {
  1144  		hdr, err := e.Client.HeaderByNumber(ctx, big.NewInt(int64(i)))
  1145  		if err != nil {
  1146  			return totalTime, err
  1147  		}
  1148  
  1149  		blockTime := time.Unix(int64(hdr.Time), 0)
  1150  		if err != nil {
  1151  			return totalTime, err
  1152  		}
  1153  		previousBlockTime := time.Unix(int64(previousHeader.Time), 0)
  1154  		blockDuration := blockTime.Sub(previousBlockTime)
  1155  		totalTime += blockDuration
  1156  		previousHeader = hdr
  1157  	}
  1158  
  1159  	averageBlockTime := totalTime / time.Duration(numBlocks)
  1160  
  1161  	return averageBlockTime, nil
  1162  }
  1163  
  1164  // EthereumMultinodeClient wraps the client and the BlockChain network to interact with an EVM based Blockchain with multiple nodes
  1165  type EthereumMultinodeClient struct {
  1166  	DefaultClient EVMClient
  1167  	Clients       []EVMClient
  1168  }
  1169  
  1170  func (e *EthereumMultinodeClient) Backend() bind.ContractBackend {
  1171  	return e.DefaultClient.Backend()
  1172  }
  1173  
  1174  func (e *EthereumMultinodeClient) DeployBackend() bind.DeployBackend {
  1175  	return e.DefaultClient.DeployBackend()
  1176  }
  1177  
  1178  func (e *EthereumMultinodeClient) SubscribeNewHeaders(
  1179  	ctx context.Context,
  1180  	headerChan chan *SafeEVMHeader,
  1181  ) (ethereum.Subscription, error) {
  1182  	return e.DefaultClient.SubscribeNewHeaders(ctx, headerChan)
  1183  }
  1184  
  1185  // HeaderByNumber retrieves a Safe EVM header by number, nil for latest
  1186  func (e *EthereumMultinodeClient) HeaderByNumber(
  1187  	ctx context.Context,
  1188  	number *big.Int,
  1189  ) (*SafeEVMHeader, error) {
  1190  	return e.DefaultClient.HeaderByNumber(ctx, number)
  1191  }
  1192  
  1193  // HeaderByHash retrieves a Safe EVM header by hash
  1194  func (e *EthereumMultinodeClient) HeaderByHash(ctx context.Context, hash common.Hash) (*SafeEVMHeader, error) {
  1195  	return e.DefaultClient.HeaderByHash(ctx, hash)
  1196  }
  1197  
  1198  func (e *EthereumMultinodeClient) RawJsonRPCCall(ctx context.Context, result interface{}, method string, params ...interface{}) error {
  1199  	err := e.DefaultClient.RawJsonRPCCall(ctx, result, method, params)
  1200  
  1201  	return err
  1202  }
  1203  
  1204  // LoadContract load already deployed contract instance
  1205  func (e *EthereumMultinodeClient) LoadContract(contractName string, address common.Address, loader ContractLoader) (interface{}, error) {
  1206  	return e.DefaultClient.LoadContract(contractName, address, loader)
  1207  }
  1208  
  1209  // EstimateCostForChainlinkOperations calculates TXs cost as a dirty estimation based on transactionLimit for that network
  1210  func (e *EthereumMultinodeClient) EstimateCostForChainlinkOperations(amountOfOperations int) (*big.Float, error) {
  1211  	return e.DefaultClient.EstimateCostForChainlinkOperations(amountOfOperations)
  1212  }
  1213  
  1214  func (e *EthereumMultinodeClient) GetHeaderSubscriptions() map[string]HeaderEventSubscription {
  1215  	return e.DefaultClient.GetHeaderSubscriptions()
  1216  }
  1217  
  1218  // NewEVMClientFromNetwork returns a multi-node EVM client connected to the specified network
  1219  func NewEVMClientFromNetwork(networkSettings EVMNetwork, logger zerolog.Logger) (EVMClient, error) {
  1220  	ecl := &EthereumMultinodeClient{}
  1221  	for idx, networkURL := range networkSettings.URLs {
  1222  		networkSettings.URL = networkURL
  1223  		ec, err := newEVMClient(networkSettings, logger)
  1224  		if err != nil {
  1225  			return nil, err
  1226  		}
  1227  		// a call to BalanceAt (can be any on chain call) to ensure the client is connected
  1228  		_, err = ec.BalanceAt(context.Background(), ec.GetDefaultWallet().address)
  1229  		if err == nil {
  1230  			ec.SetID(idx)
  1231  			ecl.Clients = append(ecl.Clients, ec)
  1232  			break
  1233  		}
  1234  	}
  1235  	ecl.DefaultClient = ecl.Clients[0]
  1236  	wrappedClient := wrapMultiClient(networkSettings, ecl)
  1237  	// required in Geth when you need to call "simulate" transactions from nodes
  1238  	if ecl.NetworkSimulated() {
  1239  		zero := common.HexToAddress("0x0")
  1240  		gasEstimations, err := wrappedClient.EstimateGas(ethereum.CallMsg{
  1241  			To: &zero,
  1242  		})
  1243  		if err != nil {
  1244  			return nil, err
  1245  		}
  1246  		if err := ecl.Fund("0x0", big.NewFloat(1000), gasEstimations); err != nil {
  1247  			return nil, err
  1248  		}
  1249  	}
  1250  	return wrappedClient, nil
  1251  }
  1252  
  1253  // NewEVMClient returns a multi-node EVM client connected to the specified network
  1254  // Note: This should mostly be deprecated in favor of ConnectEVMClient. This is really only used when needing to connect
  1255  // to simulated networks
  1256  func NewEVMClient(networkSettings EVMNetwork, env *environment.Environment, logger zerolog.Logger) (EVMClient, error) {
  1257  	if env == nil {
  1258  		return nil, fmt.Errorf("environment nil, use ConnectEVMClient or provide a non-nil environment")
  1259  	}
  1260  
  1261  	if networkSettings.Simulated {
  1262  		if _, ok := env.URLs[networkSettings.Name]; !ok {
  1263  			return nil, fmt.Errorf("network %s not found in environment", networkSettings.Name)
  1264  		}
  1265  		networkSettings.URLs = env.URLs[networkSettings.Name]
  1266  	}
  1267  
  1268  	return ConnectEVMClient(networkSettings, logger)
  1269  }
  1270  
  1271  // ConnectEVMClient returns a multi-node EVM client connected to a specified network, using only URLs.
  1272  // Should mostly be used for inside K8s, non-simulated tests.
  1273  func ConnectEVMClient(networkSettings EVMNetwork, logger zerolog.Logger) (EVMClient, error) {
  1274  	if len(networkSettings.URLs) == 0 {
  1275  		return nil, fmt.Errorf("no URLs provided to connect to network")
  1276  	}
  1277  
  1278  	ecl := &EthereumMultinodeClient{}
  1279  
  1280  	for idx, networkURL := range networkSettings.URLs {
  1281  		networkSettings.URL = networkURL
  1282  		ec, err := newEVMClient(networkSettings, logger)
  1283  
  1284  		if err != nil {
  1285  			logger.Info().
  1286  				Err(err).
  1287  				Str("URL Suffix", networkURL[len(networkURL)-6:]).
  1288  				Msg("failed to create new EVM client")
  1289  			continue
  1290  		}
  1291  		// a call to BalanceAt to ensure the client is connected
  1292  		_, err = ec.BalanceAt(context.Background(), ec.GetDefaultWallet().address)
  1293  		if err == nil {
  1294  			ec.SetID(idx)
  1295  			ecl.Clients = append(ecl.Clients, ec)
  1296  			break
  1297  		}
  1298  	}
  1299  	if len(ecl.Clients) == 0 {
  1300  		return nil, fmt.Errorf("failed to create new EVM client")
  1301  	}
  1302  	ecl.DefaultClient = ecl.Clients[0]
  1303  	wrappedClient := wrapMultiClient(networkSettings, ecl)
  1304  	// required in Geth when you need to call "simulate" transactions from nodes
  1305  	if ecl.NetworkSimulated() {
  1306  		zero := common.HexToAddress("0x0")
  1307  		gasEstimations, err := wrappedClient.EstimateGas(ethereum.CallMsg{
  1308  			To: &zero,
  1309  		})
  1310  		if err != nil {
  1311  			return nil, err
  1312  		}
  1313  		if err := ecl.Fund("0x0", big.NewFloat(1000), gasEstimations); err != nil {
  1314  			return nil, err
  1315  		}
  1316  	}
  1317  
  1318  	return wrappedClient, nil
  1319  }
  1320  
  1321  // ConcurrentEVMClient returns a multi-node EVM client connected to a specified network
  1322  // It is used for concurrent interactions from different threads with the same network and from same owner
  1323  // account. This ensures that correct nonce value is fetched when an instance of EVMClient is initiated using this method.
  1324  // This is mainly useful for simulated networks as we don't use global nonce manager for them.
  1325  func ConcurrentEVMClient(networkSettings EVMNetwork, env *environment.Environment, existing EVMClient, logger zerolog.Logger) (EVMClient, error) {
  1326  	// if not simulated use the NewEVMClient
  1327  	if !networkSettings.Simulated {
  1328  		return ConnectEVMClient(networkSettings, logger)
  1329  	}
  1330  	ecl := &EthereumMultinodeClient{}
  1331  	if env != nil {
  1332  		if _, ok := env.URLs[existing.GetNetworkConfig().Name]; !ok {
  1333  			return nil, fmt.Errorf("network %s not found in environment", existing.GetNetworkConfig().Name)
  1334  		}
  1335  		networkSettings.URLs = env.URLs[existing.GetNetworkConfig().Name]
  1336  	}
  1337  	for idx, networkURL := range networkSettings.URLs {
  1338  		networkSettings.URL = networkURL
  1339  		ec, err := newEVMClient(networkSettings, logger)
  1340  		if err != nil {
  1341  			logger.Info().
  1342  				Err(err).
  1343  				Str("URL Suffix", networkURL[len(networkURL)-6:]).
  1344  				Msg("failed to create new EVM client")
  1345  			continue
  1346  		}
  1347  		// a call to BalanceAt (can be any on chain call) to ensure the client is connected
  1348  		_, err = ec.BalanceAt(context.Background(), ec.GetDefaultWallet().address)
  1349  		if err == nil {
  1350  			ec.SyncNonce(existing)
  1351  			ec.SetID(idx)
  1352  			ecl.Clients = append(ecl.Clients, ec)
  1353  			break
  1354  		}
  1355  	}
  1356  	if len(ecl.Clients) == 0 {
  1357  		return nil, fmt.Errorf("failed to create new EVM client")
  1358  	}
  1359  	ecl.DefaultClient = ecl.Clients[0]
  1360  	wrappedClient := wrapMultiClient(networkSettings, ecl)
  1361  	// no need to fund the account as it is already funded in the existing client
  1362  	return wrappedClient, nil
  1363  }
  1364  
  1365  // Get gets default client as an interface{}
  1366  func (e *EthereumMultinodeClient) Get() interface{} {
  1367  	return e.DefaultClient
  1368  }
  1369  func (e *EthereumMultinodeClient) GetNonceSetting() NonceSettings {
  1370  	return e.DefaultClient.GetNonceSetting()
  1371  }
  1372  
  1373  func (e *EthereumMultinodeClient) SyncNonce(c EVMClient) {
  1374  	e.DefaultClient.SyncNonce(c)
  1375  }
  1376  
  1377  // GetNetworkName gets the ID of the chain that the clients are connected to
  1378  func (e *EthereumMultinodeClient) GetNetworkName() string {
  1379  	return e.DefaultClient.GetNetworkName()
  1380  }
  1381  
  1382  // GetNetworkType retrieves the type of network this is running on
  1383  func (e *EthereumMultinodeClient) NetworkSimulated() bool {
  1384  	return e.DefaultClient.NetworkSimulated()
  1385  }
  1386  
  1387  // GetChainID retrieves the ChainID of the network that the client interacts with
  1388  func (e *EthereumMultinodeClient) GetChainID() *big.Int {
  1389  	return e.DefaultClient.GetChainID()
  1390  }
  1391  
  1392  // GetClients gets clients for all nodes connected
  1393  func (e *EthereumMultinodeClient) GetClients() []EVMClient {
  1394  	cl := make([]EVMClient, 0)
  1395  	cl = append(cl, e.Clients...)
  1396  	return cl
  1397  }
  1398  
  1399  // GetDefaultWallet returns the default wallet for the network
  1400  func (e *EthereumMultinodeClient) GetDefaultWallet() *EthereumWallet {
  1401  	return e.DefaultClient.GetDefaultWallet()
  1402  }
  1403  
  1404  // GetWallets returns the default wallet for the network
  1405  func (e *EthereumMultinodeClient) GetWallets() []*EthereumWallet {
  1406  	return e.DefaultClient.GetWallets()
  1407  }
  1408  
  1409  // GetNetworkConfig return the network config
  1410  func (e *EthereumMultinodeClient) GetNetworkConfig() *EVMNetwork {
  1411  	return e.DefaultClient.GetNetworkConfig()
  1412  }
  1413  
  1414  // SetID sets client ID in a multi-node environment
  1415  func (e *EthereumMultinodeClient) SetID(id int) {
  1416  	e.DefaultClient.SetID(id)
  1417  }
  1418  
  1419  // SetDefaultWallet sets default wallet
  1420  func (e *EthereumMultinodeClient) SetDefaultWallet(num int) error {
  1421  	return e.DefaultClient.SetDefaultWallet(num)
  1422  }
  1423  
  1424  // SetWallets sets the default client's wallets
  1425  func (e *EthereumMultinodeClient) SetWallets(wallets []*EthereumWallet) {
  1426  	e.DefaultClient.SetWallets(wallets)
  1427  }
  1428  
  1429  // LoadWallets loads wallets using private keys provided in the config
  1430  func (e *EthereumMultinodeClient) LoadWallets(cfg EVMNetwork) error {
  1431  	pkStrings := cfg.PrivateKeys
  1432  	wallets := make([]*EthereumWallet, 0)
  1433  	for _, pks := range pkStrings {
  1434  		w, err := NewEthereumWallet(pks)
  1435  		if err != nil {
  1436  			return err
  1437  		}
  1438  		wallets = append(wallets, w)
  1439  	}
  1440  	for _, c := range e.Clients {
  1441  		c.SetWallets(wallets)
  1442  	}
  1443  	return nil
  1444  }
  1445  
  1446  // BalanceAt returns the ETH balance of the specified address
  1447  func (e *EthereumMultinodeClient) BalanceAt(ctx context.Context, address common.Address) (*big.Int, error) {
  1448  	return e.DefaultClient.BalanceAt(ctx, address)
  1449  }
  1450  
  1451  // SwitchNode sets default client to perform calls to the network
  1452  func (e *EthereumMultinodeClient) SwitchNode(clientID int) error {
  1453  	if clientID > len(e.Clients) {
  1454  		return fmt.Errorf("client for node %d not found", clientID)
  1455  	}
  1456  	e.DefaultClient = e.Clients[clientID]
  1457  	return nil
  1458  }
  1459  
  1460  // HeaderHashByNumber gets header hash by block number
  1461  func (e *EthereumMultinodeClient) HeaderHashByNumber(ctx context.Context, bn *big.Int) (string, error) {
  1462  	return e.DefaultClient.HeaderHashByNumber(ctx, bn)
  1463  }
  1464  
  1465  // HeaderTimestampByNumber gets header timestamp by number
  1466  func (e *EthereumMultinodeClient) HeaderTimestampByNumber(ctx context.Context, bn *big.Int) (uint64, error) {
  1467  	return e.DefaultClient.HeaderTimestampByNumber(ctx, bn)
  1468  }
  1469  
  1470  // LatestBlockNumber gets the latest block number from the default client
  1471  func (e *EthereumMultinodeClient) LatestBlockNumber(ctx context.Context) (uint64, error) {
  1472  	return e.DefaultClient.LatestBlockNumber(ctx)
  1473  }
  1474  
  1475  // SendTransaction wraps ethereum's SendTransaction to make it safe with instant transaction types
  1476  func (e *EthereumMultinodeClient) SendTransaction(ctx context.Context, tx *types.Transaction) error {
  1477  	return e.DefaultClient.SendTransaction(ctx, tx)
  1478  }
  1479  
  1480  // Fund funds a specified address with ETH from the given wallet
  1481  func (e *EthereumMultinodeClient) Fund(toAddress string, nativeAmount *big.Float, gasEstimations GasEstimations) error {
  1482  	return e.DefaultClient.Fund(toAddress, nativeAmount, gasEstimations)
  1483  }
  1484  
  1485  func (e *EthereumMultinodeClient) ReturnFunds(fromKey *ecdsa.PrivateKey) error {
  1486  	return e.DefaultClient.ReturnFunds(fromKey)
  1487  }
  1488  
  1489  // DeployContract deploys a specified contract
  1490  func (e *EthereumMultinodeClient) DeployContract(
  1491  	contractName string,
  1492  	deployer ContractDeployer,
  1493  ) (*common.Address, *types.Transaction, interface{}, error) {
  1494  	return e.DefaultClient.DeployContract(contractName, deployer)
  1495  }
  1496  
  1497  // TransactionOpts returns the base Tx options for 'transactions' that interact with a smart contract. Since most
  1498  // contract interactions in this framework are designed to happen through abigen calls, it's intentionally quite bare.
  1499  func (e *EthereumMultinodeClient) TransactionOpts(from *EthereumWallet) (*bind.TransactOpts, error) {
  1500  	return e.DefaultClient.TransactionOpts(from)
  1501  }
  1502  
  1503  func (e *EthereumMultinodeClient) NewTx(
  1504  	fromPrivateKey *ecdsa.PrivateKey,
  1505  	nonce uint64,
  1506  	to common.Address,
  1507  	value *big.Int,
  1508  	gasEstimations GasEstimations,
  1509  ) (*types.Transaction, error) {
  1510  	return e.DefaultClient.NewTx(fromPrivateKey, nonce, to, value, gasEstimations)
  1511  }
  1512  
  1513  // ProcessTransaction returns the result of the default client's processed transaction
  1514  func (e *EthereumMultinodeClient) ProcessTransaction(tx *types.Transaction) error {
  1515  	return e.DefaultClient.ProcessTransaction(tx)
  1516  }
  1517  
  1518  // ProcessEvent returns the result of the default client's processed event
  1519  func (e *EthereumMultinodeClient) ProcessEvent(name string, event *types.Log, confirmedChan chan bool, errorChan chan error) error {
  1520  	return e.DefaultClient.ProcessEvent(name, event, confirmedChan, errorChan)
  1521  }
  1522  
  1523  // IsTxConfirmed returns the default client's transaction confirmations
  1524  func (e *EthereumMultinodeClient) IsTxConfirmed(txHash common.Hash) (bool, error) {
  1525  	return e.DefaultClient.IsTxConfirmed(txHash)
  1526  }
  1527  
  1528  // IsEventConfirmed returns if the default client can confirm the event has happened
  1529  func (e *EthereumMultinodeClient) IsEventConfirmed(event *types.Log) (confirmed, removed bool, err error) {
  1530  	return e.DefaultClient.IsEventConfirmed(event)
  1531  }
  1532  
  1533  // IsTxFinalized returns if the default client can confirm the transaction has been finalized
  1534  func (e *EthereumMultinodeClient) IsTxHeadFinalized(txHdr, header *SafeEVMHeader) (bool, *big.Int, time.Time, error) {
  1535  	return e.DefaultClient.IsTxHeadFinalized(txHdr, header)
  1536  }
  1537  
  1538  // WaitForTxTobeFinalized waits for the transaction to be finalized
  1539  func (e *EthereumMultinodeClient) WaitForFinalizedTx(txHash common.Hash) (*big.Int, time.Time, error) {
  1540  	return e.DefaultClient.WaitForFinalizedTx(txHash)
  1541  }
  1542  
  1543  // MarkTxAsSentOnL2 marks the transaction as sent on L2
  1544  func (e *EthereumMultinodeClient) MarkTxAsSentOnL2(tx *types.Transaction) error {
  1545  	return e.DefaultClient.MarkTxAsSentOnL2(tx)
  1546  }
  1547  
  1548  // PollFinality polls for finality
  1549  func (e *EthereumMultinodeClient) PollFinality() error {
  1550  	return e.DefaultClient.PollFinality()
  1551  }
  1552  
  1553  // StopPollingForFinality stops polling for finality
  1554  func (e *EthereumMultinodeClient) CancelFinalityPolling() {
  1555  	e.DefaultClient.CancelFinalityPolling()
  1556  }
  1557  
  1558  // GetTxReceipt returns the receipt of the transaction if available, error otherwise
  1559  func (e *EthereumMultinodeClient) GetTxReceipt(txHash common.Hash) (*types.Receipt, error) {
  1560  	return e.DefaultClient.GetTxReceipt(txHash)
  1561  }
  1562  
  1563  func (e *EthereumMultinodeClient) RevertReasonFromTx(txHash common.Hash, abiString string) (string, interface{}, error) {
  1564  	return e.DefaultClient.RevertReasonFromTx(txHash, abiString)
  1565  }
  1566  
  1567  // ParallelTransactions when enabled, sends the transaction without waiting for transaction confirmations. The hashes
  1568  // are then stored within the client and confirmations can be waited on by calling WaitForEvents.
  1569  // When disabled, the minimum confirmations are waited on when the transaction is sent, so parallelisation is disabled.
  1570  func (e *EthereumMultinodeClient) ParallelTransactions(enabled bool) {
  1571  	for _, c := range e.Clients {
  1572  		c.ParallelTransactions(enabled)
  1573  	}
  1574  }
  1575  
  1576  // Close tears down the all the clients
  1577  func (e *EthereumMultinodeClient) Close() error {
  1578  	for _, c := range e.Clients {
  1579  		if err := c.Close(); err != nil {
  1580  			return err
  1581  		}
  1582  	}
  1583  	return nil
  1584  }
  1585  
  1586  func (e *EthereumMultinodeClient) EstimateTransactionGasCost() (*big.Int, error) {
  1587  	return e.DefaultClient.EstimateTransactionGasCost()
  1588  }
  1589  
  1590  // GasStats gets gas stats instance
  1591  func (e *EthereumMultinodeClient) GasStats() *GasStats {
  1592  	return e.DefaultClient.GasStats()
  1593  }
  1594  
  1595  func (e *EthereumMultinodeClient) EstimateGas(callMsg ethereum.CallMsg) (GasEstimations, error) {
  1596  	return e.DefaultClient.EstimateGas(callMsg)
  1597  }
  1598  
  1599  func (e *EthereumMultinodeClient) EstimateGasPrice() (*big.Int, error) {
  1600  	return e.DefaultClient.EstimateGasPrice()
  1601  }
  1602  
  1603  func (e *EthereumMultinodeClient) ConnectionIssue() chan time.Time {
  1604  	return e.DefaultClient.ConnectionIssue()
  1605  }
  1606  func (e *EthereumMultinodeClient) ConnectionRestored() chan time.Time {
  1607  	return e.DefaultClient.ConnectionRestored()
  1608  }
  1609  
  1610  // AddHeaderEventSubscription adds a new header subscriber within the client to receive new headers
  1611  func (e *EthereumMultinodeClient) AddHeaderEventSubscription(key string, subscriber HeaderEventSubscription) {
  1612  	e.DefaultClient.AddHeaderEventSubscription(key, subscriber)
  1613  }
  1614  
  1615  // SubscribeFilterLogs subscribes to the results of a streaming filter query.
  1616  func (e *EthereumMultinodeClient) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, logs chan<- types.Log) (ethereum.Subscription, error) {
  1617  	return e.DefaultClient.SubscribeFilterLogs(ctx, q, logs)
  1618  }
  1619  
  1620  // FilterLogs executes a filter query
  1621  func (e *EthereumMultinodeClient) FilterLogs(ctx context.Context, filterQuery ethereum.FilterQuery) ([]types.Log, error) {
  1622  	return e.DefaultClient.FilterLogs(ctx, filterQuery)
  1623  }
  1624  
  1625  func (e *EthereumMultinodeClient) GetLatestFinalizedBlockHeader(ctx context.Context) (*types.Header, error) {
  1626  	return e.DefaultClient.GetLatestFinalizedBlockHeader(ctx)
  1627  }
  1628  
  1629  func (e *EthereumMultinodeClient) EstimatedFinalizationTime(ctx context.Context) (time.Duration, error) {
  1630  	return e.DefaultClient.EstimatedFinalizationTime(ctx)
  1631  }
  1632  
  1633  func (e *EthereumMultinodeClient) AvgBlockTime(ctx context.Context) (time.Duration, error) {
  1634  	return e.DefaultClient.AvgBlockTime(ctx)
  1635  }
  1636  
  1637  // DeleteHeaderEventSubscription removes a header subscriber from the map
  1638  func (e *EthereumMultinodeClient) DeleteHeaderEventSubscription(key string) {
  1639  	e.DefaultClient.DeleteHeaderEventSubscription(key)
  1640  }
  1641  
  1642  // WaitForEvents is a blocking function that waits for all event subscriptions for all clients
  1643  func (e *EthereumMultinodeClient) WaitForEvents() error {
  1644  	g := errgroup.Group{}
  1645  	for _, c := range e.Clients {
  1646  		c := c
  1647  		g.Go(func() error {
  1648  			return c.WaitForEvents()
  1649  		})
  1650  	}
  1651  	return g.Wait()
  1652  }