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

     1  package blockchain
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"math/big"
     7  	"strings"
     8  
     9  	"github.com/ethereum/go-ethereum/accounts/abi/bind"
    10  	"github.com/ethereum/go-ethereum/common"
    11  	"github.com/ethereum/go-ethereum/core/types"
    12  	"github.com/ethereum/go-ethereum/crypto"
    13  	"github.com/rs/zerolog/log"
    14  
    15  	"github.com/smartcontractkit/chainlink-testing-framework/libs/utils/conversions"
    16  )
    17  
    18  // Handles specific issues with the Celo EVM chain: https://docs.celo.org/
    19  
    20  // CeloMultinodeClient represents a multi-node, EVM compatible client for the Celo network
    21  type CeloMultinodeClient struct {
    22  	*EthereumMultinodeClient
    23  }
    24  
    25  // CeloClient represents a single node, EVM compatible client for the Celo network
    26  type CeloClient struct {
    27  	*EthereumClient
    28  }
    29  
    30  // DeployContract uses legacy txs for Celo to bypass Geth checking Celo headers which do not have a required
    31  // sha3Uncles field
    32  func (e *CeloClient) DeployContract(
    33  	contractName string,
    34  	deployer ContractDeployer,
    35  ) (*common.Address, *types.Transaction, interface{}, error) {
    36  	suggestedPrice, err := e.Client.SuggestGasPrice(context.Background())
    37  	if err != nil {
    38  		return nil, nil, nil, err
    39  	}
    40  	gasPriceBuffer := big.NewInt(0).SetUint64(e.NetworkConfig.GasEstimationBuffer)
    41  
    42  	opts, err := e.TransactionOpts(e.DefaultWallet)
    43  	if err != nil {
    44  		return nil, nil, nil, err
    45  	}
    46  	opts.GasPrice = suggestedPrice.Add(gasPriceBuffer, suggestedPrice)
    47  
    48  	contractAddress, transaction, contractInstance, err := deployer(opts, e.Client)
    49  	if err != nil {
    50  		if strings.Contains(err.Error(), "nonce") {
    51  			err = fmt.Errorf("using nonce %d err: %w", opts.Nonce.Uint64(), err)
    52  		}
    53  		return nil, nil, nil, err
    54  	}
    55  
    56  	if err = e.ProcessTransaction(transaction); err != nil {
    57  		return nil, nil, nil, err
    58  	}
    59  
    60  	log.Info().
    61  		Str("Contract Address", contractAddress.Hex()).
    62  		Str("Contract Name", contractName).
    63  		Str("From", e.DefaultWallet.Address()).
    64  		Str("Total Gas Cost (CELO)", conversions.WeiToEther(transaction.Cost()).String()).
    65  		Str("Network Name", e.NetworkConfig.Name).
    66  		Msg("Deployed contract")
    67  	return &contractAddress, transaction, contractInstance, err
    68  }
    69  
    70  func (e *CeloClient) TransactionOpts(from *EthereumWallet) (*bind.TransactOpts, error) {
    71  	privateKey, err := crypto.HexToECDSA(from.PrivateKey())
    72  	if err != nil {
    73  		return nil, fmt.Errorf("invalid private key: %w", err)
    74  	}
    75  	opts, err := bind.NewKeyedTransactorWithChainID(privateKey, big.NewInt(e.NetworkConfig.ChainID))
    76  	if err != nil {
    77  		return nil, err
    78  	}
    79  	opts.From = common.HexToAddress(from.Address())
    80  	opts.Context = context.Background()
    81  
    82  	nonce, err := e.GetNonce(context.Background(), common.HexToAddress(from.Address()))
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  	opts.Nonce = big.NewInt(int64(nonce))
    87  
    88  	gasPrice, err := e.Client.SuggestGasPrice(context.Background())
    89  	if err != nil {
    90  		return nil, err
    91  	}
    92  	gasPriceBuffer := big.NewInt(0).SetUint64(e.NetworkConfig.GasEstimationBuffer)
    93  	opts.GasPrice = gasPrice.Add(gasPriceBuffer, gasPrice)
    94  
    95  	if e.NetworkConfig.MinimumConfirmations <= 0 { // Wait for your turn to send on an L2 chain
    96  		<-e.NonceSettings.registerInstantTransaction(from.Address(), nonce)
    97  	}
    98  	return opts, nil
    99  }