Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
Sidu28 committed Feb 8, 2024
1 parent ef017d7 commit 6842aed
Show file tree
Hide file tree
Showing 4 changed files with 336 additions and 1 deletion.
191 changes: 191 additions & 0 deletions chain_client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
package eigenpodproofs

import (
"context"
"crypto/ecdsa"
"errors"
"fmt"
"math/big"

"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/rs/zerolog/log"
)

var (
FallbackGasTipCap = big.NewInt(15000000000)
ErrCannotGetECDSAPubKey = errors.New("ErrCannotGetECDSAPubKey")
ErrTransactionFailed = errors.New("ErrTransactionFailed")
)

type ChainClient struct {
*ethclient.Client
privateKey *ecdsa.PrivateKey
AccountAddress common.Address
NoSendTransactOpts *bind.TransactOpts
Contracts map[common.Address]*bind.BoundContract
}

func NewChainClient(ethClient *ethclient.Client, privateKeyString string) (*ChainClient, error) {
var (
accountAddress common.Address
privateKey *ecdsa.PrivateKey
opts *bind.TransactOpts
err error
)

if len(privateKeyString) != 0 {
privateKey, err = crypto.HexToECDSA(privateKeyString)
if err != nil {
return nil, fmt.Errorf("NewClient: cannot parse private key: %w", err)
}
publicKey := privateKey.Public()
publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)

if !ok {
log.Error().Msg("NewClient: cannot get publicKeyECDSA")
return nil, ErrCannotGetECDSAPubKey
}
accountAddress = crypto.PubkeyToAddress(*publicKeyECDSA)

chainIDBigInt, err := ethClient.ChainID(context.Background())
if err != nil {
return nil, fmt.Errorf("NewClient: cannot get chainId: %w", err)
}

// generate and memoize NoSendTransactOpts
opts, err = bind.NewKeyedTransactorWithChainID(privateKey, chainIDBigInt)
if err != nil {
return nil, fmt.Errorf("NewClient: cannot create NoSendTransactOpts: %w", err)
}
opts.NoSend = true
}

c := &ChainClient{
privateKey: privateKey,
AccountAddress: accountAddress,
Client: ethClient,
Contracts: make(map[common.Address]*bind.BoundContract),
}

c.NoSendTransactOpts = opts

return c, nil
}

func (c *ChainClient) GetCurrentBlockNumber(ctx context.Context) (uint32, error) {
bn, err := c.Client.BlockNumber(ctx)
return uint32(bn), err
}

func (c *ChainClient) GetAccountAddress() common.Address {
return c.AccountAddress
}

func (c *ChainClient) GetNoSendTransactOpts() *bind.TransactOpts {
return c.NoSendTransactOpts
}

// EstimateGasPriceAndLimitAndSendTx sends and returns an otherwise identical txn
// to the one provided but with updated gas prices sampled from the existing network
// conditions and an accurate gasLimit
//
// Note: tx must be a to a contract, not an EOA
//
// Slightly modified from: https://github.com/ethereum-optimism/optimism/blob/ec266098641820c50c39c31048aa4e953bece464/batch-submitter/drivers/sequencer/driver.go#L314
func (c *ChainClient) EstimateGasPriceAndLimitAndSendTx(
ctx context.Context,
tx *types.Transaction,
tag string,
) (*types.Receipt, error) {
gasTipCap, err := c.SuggestGasTipCap(ctx)
if err != nil {
// If the transaction failed because the backend does not support
// eth_maxPriorityFeePerGas, fallback to using the default constant.
// Currently Alchemy is the only backend provider that exposes this
// method, so in the event their API is unreachable we can fallback to a
// degraded mode of operation. This also applies to our test
// environments, as hardhat doesn't support the query either.
log.Debug().Msgf("EstimateGasPriceAndLimitAndSendTx: cannot get gasTipCap: %v", err)
gasTipCap = FallbackGasTipCap
}

header, err := c.HeaderByNumber(ctx, nil)
if err != nil {
return nil, err
}
gasFeeCap := new(big.Int).Add(header.BaseFee, gasTipCap)

// The estimated gas limits performed by RawTransact fail semi-regularly
// with out of gas exceptions. To remedy this we extract the internal calls
// to perform gas price/gas limit estimation here and add a buffer to
// account for any network variability.
gasLimit, err := c.Client.EstimateGas(ctx, ethereum.CallMsg{
From: c.AccountAddress,
To: tx.To(),
GasTipCap: gasTipCap,
GasFeeCap: gasFeeCap,
Value: nil,
Data: tx.Data(),
})

if err != nil {
return nil, err
}

opts, err := bind.NewKeyedTransactorWithChainID(c.privateKey, tx.ChainId())
if err != nil {
return nil, fmt.Errorf("EstimateGasPriceAndLimitAndSendTx: cannot create transactOpts: %w", err)
}
opts.Context = ctx
opts.Nonce = new(big.Int).SetUint64(tx.Nonce())
opts.GasTipCap = gasTipCap
opts.GasFeeCap = gasFeeCap
opts.GasLimit = addGasBuffer(gasLimit)

contract := c.Contracts[*tx.To()]
// if the contract has not been cached
if contract == nil {
// create a dummy bound contract tied to the `to` address of the transaction
contract = bind.NewBoundContract(*tx.To(), abi.ABI{}, c.Client, c.Client, c.Client)
// cache the contract for later use
c.Contracts[*tx.To()] = contract
}

tx, err = contract.RawTransact(opts, tx.Data())
if err != nil {
return nil, fmt.Errorf("EstimateGasPriceAndLimitAndSendTx: failed to send txn (%s): %w", tag, err)
}

receipt, err := c.EnsureTransactionEvaled(
tx,
tag,
)
if err != nil {
return nil, err
}

return receipt, err
}

func (c *ChainClient) EnsureTransactionEvaled(tx *types.Transaction, tag string) (*types.Receipt, error) {
receipt, err := bind.WaitMined(context.Background(), c.Client, tx)
if err != nil {
return nil, fmt.Errorf("EnsureTransactionEvaled: failed to wait for transaction (%s) to mine: %w", tag, err)
}
if receipt.Status != 1 {
log.Debug().Msgf("EnsureTransactionEvaled: transaction (%s) failed: %v", tag, receipt)
return nil, ErrTransactionFailed
}
log.Debug().Msgf("EnsureTransactionEvaled: transaction (%s) succeeded: %v", tag, receipt)
return receipt, nil
}

func addGasBuffer(gasLimit uint64) uint64 {
return 6 * gasLimit / 5 // add 20% buffer to gas limit
}
26 changes: 25 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.20

require (
github.com/attestantio/go-eth2-client v0.19.9
github.com/ethereum/go-ethereum v1.13.5
github.com/ethereum/go-ethereum v1.13.11
github.com/ferranbt/fastssz v0.1.3
github.com/hashicorp/golang-lru/v2 v2.0.7
github.com/minio/sha256-simd v1.0.1
Expand All @@ -14,19 +14,43 @@ require (
)

require (
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/StackExchange/wmi v1.2.1 // indirect
github.com/bits-and-blooms/bitset v1.10.0 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect
github.com/consensys/bavard v0.1.13 // indirect
github.com/consensys/gnark-crypto v0.12.1 // indirect
github.com/crate-crypto/go-kzg-4844 v0.7.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/deckarep/golang-set/v2 v2.1.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
github.com/ethereum/c-kzg-4844 v0.4.0 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/goccy/go-yaml v1.9.2 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/websocket v1.4.2 // indirect
github.com/holiman/uint256 v1.2.4 // indirect
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mmcloughlin/addchain v0.4.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7 // indirect
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect
github.com/supranational/blst v0.3.11 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
golang.org/x/crypto v0.18.0 // indirect
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/sync v0.5.0 // indirect
golang.org/x/sys v0.16.0 // indirect
golang.org/x/tools v0.15.0 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
rsc.io/tmplfunc v0.0.3 // indirect
)
Loading

0 comments on commit 6842aed

Please sign in to comment.