Skip to content

Commit

Permalink
Merge pull request #35 from KyberNetwork/feat/EstimateBundleGas
Browse files Browse the repository at this point in the history
Feat: estimate bundle gas
  • Loading branch information
datluongductuan authored Apr 9, 2024
2 parents f06730b + fbe4797 commit 89021a3
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 30 deletions.
23 changes: 2 additions & 21 deletions pkg/eth/simulator.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"math/big"

"github.com/KyberNetwork/tradinglib/pkg/mev"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
Expand All @@ -28,33 +29,13 @@ func (s *Simulator) EstimateGasWithOverrides(
) (uint64, error) {
var hex hexutil.Uint64
err := s.c.CallContext(
ctx, &hex, "eth_estimateGas", toCallArg(msg),
ctx, &hex, "eth_estimateGas", mev.ToCallArg(msg),
toBlockNumArg(blockNumber), overrides,
)

return uint64(hex), err
}

func toCallArg(msg ethereum.CallMsg) interface{} {
arg := map[string]interface{}{
"from": msg.From,
"to": msg.To,
}
if len(msg.Data) > 0 {
arg["input"] = hexutil.Bytes(msg.Data)
}
if msg.Value != nil {
arg["value"] = (*hexutil.Big)(msg.Value)
}
if msg.Gas != 0 {
arg["gas"] = hexutil.Uint64(msg.Gas)
}
if msg.GasPrice != nil {
arg["gasPrice"] = (*hexutil.Big)(msg.GasPrice)
}
return arg
}

func toBlockNumArg(number *big.Int) string {
if number == nil {
return "latest"
Expand Down
10 changes: 10 additions & 0 deletions pkg/mev/blxr_bundle_sender.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import (
"net/http"
"strconv"

"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient/gethclient"
"github.com/flashbots/mev-share-node/mevshare"
)

Expand All @@ -32,6 +34,14 @@ type BloxrouteClient struct {
enabledBuilders []BlxrBuilder
}

func (s *BloxrouteClient) EstimateBundleGas(
_ context.Context,
_ []ethereum.CallMsg,
_ *map[common.Address]gethclient.OverrideAccount,
) ([]uint64, error) {
return nil, nil
}

func (s *BloxrouteClient) MevSimulateBundle(
_ uint64,
_ common.Hash,
Expand Down
19 changes: 16 additions & 3 deletions pkg/mev/bundle_sender.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ import (
"net/http"

"github.com/duoxehyon/mev-share-go/rpc"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient/gethclient"
"github.com/flashbots/mev-share-node/mevshare"
)

Expand All @@ -26,7 +28,8 @@ type Client struct {
cancelBySendBundle bool
senderType BundleSenderType
// mevShareClient is the client for mev-share flashbots node
mevShareClient rpc.MevAPIClient
mevShareClient rpc.MevAPIClient
gasBundleEstimator IGasBundleEstimator
}

// NewClient set the flashbotKey to nil will skip adding the signature header.
Expand All @@ -36,7 +39,8 @@ func NewClient(
flashbotKey *ecdsa.PrivateKey,
cancelBySendBundle bool,
senderType BundleSenderType,
) *Client {
gasBundleEstimator IGasBundleEstimator,
) (*Client, error) {
var mevShareClient rpc.MevAPIClient
if flashbotKey != nil {
mevShareClient = rpc.NewClient(endpoint, flashbotKey)
Expand All @@ -49,7 +53,8 @@ func NewClient(
cancelBySendBundle: cancelBySendBundle,
senderType: senderType,
mevShareClient: mevShareClient,
}
gasBundleEstimator: gasBundleEstimator,
}, nil
}

func (s *Client) GetSenderType() BundleSenderType {
Expand Down Expand Up @@ -124,6 +129,14 @@ func (s *Client) flashbotBackrunSendBundle(
return res, err
}

func (s *Client) EstimateBundleGas(
ctx context.Context,
messages []ethereum.CallMsg,
overrides *map[common.Address]gethclient.OverrideAccount,
) ([]uint64, error) {
return s.gasBundleEstimator.EstimateBundleGas(ctx, messages, overrides)
}

func (s *Client) MevSimulateBundle(
blockNumber uint64,
pendingTxHash common.Hash,
Expand Down
26 changes: 20 additions & 6 deletions pkg/mev/bundle_sender_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,11 @@ func TestSendBundle(t *testing.T) {
t.Log("new tx", signedTx.Hash().String())

uuid := uuid.NewString()
sender := mev.NewClient(client, endpoint, privateKey, false, mev.BundleSenderTypeFlashbot)
ethClient, err = ethclient.Dial(endpoint)
require.NoError(t, err)
gasBundleEstimator := mev.NewGasBundleEstimator(ethClient.Client())
sender, err := mev.NewClient(client, endpoint, privateKey, false, mev.BundleSenderTypeFlashbot, gasBundleEstimator)
require.NoError(t, err)

resp, err := sender.SendBundle(ctx, &uuid, blockNumber+12, signedTx)
require.NoError(t, err) // sepolia: code: [-32000], message: [internal server error]
Expand Down Expand Up @@ -95,7 +99,12 @@ func TestCancelBeaver(t *testing.T) {
bundleUUID = uuid.New().String()
)

sender := mev.NewClient(client, endpoint, nil, true, mev.BundleSenderTypeBeaver)
ethClient, err := ethclient.Dial(endpoint)
require.NoError(t, err)
gasBundleEstimator := mev.NewGasBundleEstimator(ethClient.Client())

sender, err := mev.NewClient(client, endpoint, nil, true, mev.BundleSenderTypeBeaver, gasBundleEstimator)
require.NoError(t, err)

require.NoError(t, sender.CancelBundle(ctx, bundleUUID))
}
Expand Down Expand Up @@ -129,10 +138,15 @@ func Test_SimulateBundle(t *testing.T) {
txs = append(txs, &tx)
}

var (
simulationEndpoint = "http://localhost:8545"
client = mev.NewClient(http.DefaultClient, simulationEndpoint, nil, false, mev.BundleSenderTypeFlashbot)
)
simulationEndpoint := "http://localhost:8545"
ethClient, err := ethclient.Dial(simulationEndpoint)
require.NoError(t, err)
gasBundleEstimator := mev.NewGasBundleEstimator(ethClient.Client())

client, err := mev.NewClient(http.DefaultClient,
simulationEndpoint, nil, false,
mev.BundleSenderTypeFlashbot, gasBundleEstimator)
require.NoError(t, err)

simulationResponse, err := client.SimulateBundle(context.Background(), uint64(blockNumber), txs...)
require.NoError(t, err)
Expand Down
50 changes: 50 additions & 0 deletions pkg/mev/gas_bundle_estimator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package mev

import (
"context"

"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/ethclient/gethclient"
"github.com/ethereum/go-ethereum/rpc"
)

type GasBundleEstimator struct {
client *rpc.Client
}

func NewGasBundleEstimator(client *rpc.Client) GasBundleEstimator {
return GasBundleEstimator{
client: client,
}
}

func (g GasBundleEstimator) EstimateBundleGas(
_ context.Context,
messages []ethereum.CallMsg,
overrides *map[common.Address]gethclient.OverrideAccount,
) ([]uint64, error) {
bundles := make([]interface{}, 0, len(messages))
for _, msg := range messages {
bundles = append(bundles, ToCallArg(msg))
}

var gasEstimateCost []hexutil.Uint64

err := g.client.Call(
&gasEstimateCost, ETHEstimateGasBundleMethod,
map[string]interface{}{
"transactions": bundles,
}, "latest", overrides,
)
if err != nil {
return nil, err
}
result := make([]uint64, 0, len(gasEstimateCost))

for _, gasEstimate := range gasEstimateCost {
result = append(result, uint64(gasEstimate))
}
return result, nil
}
42 changes: 42 additions & 0 deletions pkg/mev/pkg.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ import (
"io"
"net/http"

"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient/gethclient"
"github.com/flashbots/mev-share-node/mevshare"
)

Expand All @@ -33,6 +36,7 @@ const (
ETHSendBundleMethod = "eth_sendBundle"
EthCallBundleMethod = "eth_callBundle"
ETHCancelBundleMethod = "eth_cancelBundle"
ETHEstimateGasBundleMethod = "eth_estimateGasBundle"
MevSendBundleMethod = "mev_sendBundle"
MaxBlockFromTarget = 3
)
Expand All @@ -55,13 +59,26 @@ type IBundleSender interface {
ctx context.Context, bundleUUID string,
) error
SimulateBundle(ctx context.Context, blockNumber uint64, txs ...*types.Transaction) (SendBundleResponse, error)
EstimateBundleGas(
ctx context.Context,
messages []ethereum.CallMsg,
overrides *map[common.Address]gethclient.OverrideAccount,
) ([]uint64, error)
MevSimulateBundle(
blockNumber uint64,
pendingTxHash common.Hash,
tx *types.Transaction) (*mevshare.SimMevBundleResponse, error)
GetSenderType() BundleSenderType
}

type IGasBundleEstimator interface {
EstimateBundleGas(
ctx context.Context,
messages []ethereum.CallMsg,
overrides *map[common.Address]gethclient.OverrideAccount,
) ([]uint64, error)
}

var (
_ IBundleSender = &Client{}
_ IBundleSender = &BloxrouteClient{}
Expand Down Expand Up @@ -174,3 +191,28 @@ type TitanCancelBundleResponse struct {
Result int `json:"result,omitempty"`
Error SendBundleError `json:"error,omitempty"`
}

func ToCallArg(msg ethereum.CallMsg) interface{} {
arg := map[string]interface{}{
"from": msg.From,
"to": msg.To,
}
if len(msg.Data) > 0 {
arg["input"] = hexutil.Bytes(msg.Data)
}
if msg.Value != nil {
arg["value"] = (*hexutil.Big)(msg.Value)
}
if msg.Gas != 0 {
arg["gas"] = hexutil.Uint64(msg.Gas)
}
if msg.GasPrice != nil {
arg["gasPrice"] = (*hexutil.Big)(msg.GasPrice)
}
return arg
}

func GetFrom(tx *types.Transaction) (common.Address, error) {
from, err := types.Sender(types.LatestSignerForChainID(tx.ChainId()), tx)
return from, err
}

0 comments on commit 89021a3

Please sign in to comment.