diff --git a/contract/contract_test.go b/contract/contract_test.go index 7774a046..ae631d07 100644 --- a/contract/contract_test.go +++ b/contract/contract_test.go @@ -294,8 +294,8 @@ func TestContract_EIP1559(t *testing.T) { txnObj, err := client.Eth().GetTransactionByHash(txn.Hash()) assert.NoError(t, err) + assert.Zero(t, txnObj.GasPrice) assert.NotZero(t, txnObj.Gas) - assert.NotZero(t, txnObj.GasPrice) assert.NotZero(t, txnObj.MaxFeePerGas) assert.NotZero(t, txnObj.MaxPriorityFeePerGas) } diff --git a/jsonrpc/eth.go b/jsonrpc/eth.go index d1053462..f3096064 100644 --- a/jsonrpc/eth.go +++ b/jsonrpc/eth.go @@ -266,10 +266,21 @@ func (f *FeeHistory) UnmarshalJSON(data []byte) error { } // FeeHistory returns base fee per gas and transaction effective priority fee -func (e *Eth) FeeHistory(from, to ethgo.BlockNumber) (*FeeHistory, error) { +func (e *Eth) FeeHistory(blockCount uint64, newestBlock ethgo.BlockNumber, rewardPercentiles []float64) (*FeeHistory, error) { var out *FeeHistory - if err := e.c.Call("eth_feeHistory", &out, from.String(), to.String(), nil); err != nil { + if err := e.c.Call("eth_feeHistory", &out, blockCount, newestBlock.String(), rewardPercentiles); err != nil { return nil, err } return out, nil } + +// MaxPriorityFeePerGas returns a fee per gas that is an estimate of how much you can pay as a priority fee, or 'tip', +// to get a transaction included in the current block (EIP-1559). +func (e *Eth) MaxPriorityFeePerGas() (*big.Int, error) { + var out string + if err := e.c.Call("eth_maxPriorityFeePerGas", &out); err != nil { + return big.NewInt(0), err + } + + return parseBigInt(out), nil +} diff --git a/jsonrpc/eth_test.go b/jsonrpc/eth_test.go index bf8f6737..916b633c 100644 --- a/jsonrpc/eth_test.go +++ b/jsonrpc/eth_test.go @@ -394,10 +394,46 @@ func TestEthFeeHistory(t *testing.T) { lastBlock, err := c.Eth().BlockNumber() assert.NoError(t, err) - from := ethgo.BlockNumber(lastBlock - 2) - to := ethgo.BlockNumber(lastBlock) - - fee, err := c.Eth().FeeHistory(from, to) + fee, err := c.Eth().FeeHistory(1, ethgo.BlockNumber(lastBlock), []float64{25, 75}) assert.NoError(t, err) assert.NotNil(t, fee) } + +func TestEthMaxPriorityFeePerGas(t *testing.T) { + s := testutil.NewTestServer(t) + c, err := NewClient(s.HTTPAddr()) + require.NoError(t, err) + + initialMaxPriorityFee, err := c.Eth().MaxPriorityFeePerGas() + require.NoError(t, err) + + // wait for 2 blocks + require.NoError(t, s.ProcessBlock()) + require.NoError(t, s.ProcessBlock()) + + txn := ðgo.Transaction{ + To: &testutil.DummyAddr, + Value: ethgo.Gwei(1), + Type: ethgo.TransactionDynamicFee, + MaxPriorityFeePerGas: ethgo.Gwei(1), + } + + latestBlock, err := c.Eth().BlockNumber() + require.NoError(t, err) + + feeHistory, err := c.Eth().FeeHistory(1, ethgo.BlockNumber(latestBlock), nil) + require.NoError(t, err) + + latestBaseFee := feeHistory.BaseFee[len(feeHistory.BaseFee)-1] + txn.MaxFeePerGas = new(big.Int).Add(latestBaseFee, txn.MaxPriorityFeePerGas) + + receipt, err := s.SendTxn(txn) + require.NoError(t, err) + require.Equal(t, uint64(1), receipt.Status) + + newMaxPriorityFee, err := c.Eth().MaxPriorityFeePerGas() + t.Log(initialMaxPriorityFee) + t.Log(newMaxPriorityFee) + require.NoError(t, err) + require.True(t, initialMaxPriorityFee.Cmp(newMaxPriorityFee) <= 0) +} diff --git a/structs_marshal.go b/structs_marshal.go index c058c682..b88e079e 100644 --- a/structs_marshal.go +++ b/structs_marshal.go @@ -117,18 +117,20 @@ func (t *Transaction) marshalJSON(a *fastjson.Arena) *fastjson.Value { if t.Value != nil { o.Set("value", a.NewString(fmt.Sprintf("0x%x", t.Value))) } - o.Set("gasPrice", a.NewString(fmt.Sprintf("0x%x", t.GasPrice))) - + if t.Type == TransactionDynamicFee { + if t.MaxPriorityFeePerGas != nil { + o.Set("maxPriorityFeePerGas", a.NewString(fmt.Sprintf("0x%x", t.MaxPriorityFeePerGas))) + } + if t.MaxFeePerGas != nil { + o.Set("maxFeePerGas", a.NewString(fmt.Sprintf("0x%x", t.MaxFeePerGas))) + } + } else { + o.Set("gasPrice", a.NewString(fmt.Sprintf("0x%x", t.GasPrice))) + } // gas limit fields if t.Gas != 0 { o.Set("gas", a.NewString(fmt.Sprintf("0x%x", t.Gas))) } - if t.MaxPriorityFeePerGas != nil { - o.Set("maxPriorityFeePerGas", a.NewString(fmt.Sprintf("0x%x", t.MaxPriorityFeePerGas))) - } - if t.MaxFeePerGas != nil { - o.Set("maxFeePerGas", a.NewString(fmt.Sprintf("0x%x", t.MaxFeePerGas))) - } if t.Nonce != 0 { // we can remove this once we include support for custom nonces @@ -298,4 +300,4 @@ func (s StateOverride) MarshalJSON() ([]byte, error) { defaultArena.Put(a) return res, nil -} +} diff --git a/structs_unmarshal.go b/structs_unmarshal.go index 4b7ef4eb..a3f28c0b 100644 --- a/structs_unmarshal.go +++ b/structs_unmarshal.go @@ -156,8 +156,17 @@ func (t *Transaction) unmarshalJSON(v *fastjson.Value) error { if err = decodeAddr(&t.From, v, "from"); err != nil { return err } - if t.GasPrice, err = decodeUint(v, "gasPrice"); err != nil { - return err + if typ == TransactionDynamicFee { + if t.MaxPriorityFeePerGas, err = decodeBigInt(t.MaxPriorityFeePerGas, v, "maxPriorityFeePerGas"); err != nil { + return err + } + if t.MaxFeePerGas, err = decodeBigInt(t.MaxFeePerGas, v, "maxFeePerGas"); err != nil { + return err + } + } else { + if t.GasPrice, err = decodeUint(v, "gasPrice"); err != nil { + return err + } } if t.Input, err = decodeBytes(t.Input[:0], v, "input"); err != nil { return err @@ -207,15 +216,6 @@ func (t *Transaction) unmarshalJSON(v *fastjson.Value) error { return err } - if typ == TransactionDynamicFee { - if t.MaxPriorityFeePerGas, err = decodeBigInt(t.MaxPriorityFeePerGas, v, "maxPriorityFeePerGas"); err != nil { - return err - } - if t.MaxFeePerGas, err = decodeBigInt(t.MaxFeePerGas, v, "maxFeePerGas"); err != nil { - return err - } - } - // Check if the block hash field is set // If it's not -> the transaction is a pending txn, so these fields should be omitted // If it is -> the transaction is a sealed txn, so these fields should be included diff --git a/testsuite/transaction-eip1159.json b/testsuite/transaction-eip1159.json index 534ebe36..bad0eb94 100644 --- a/testsuite/transaction-eip1159.json +++ b/testsuite/transaction-eip1159.json @@ -3,10 +3,9 @@ "from": "0x0000000000000000000000000000000000000001", "input": "0x00", "value": "0x0", - "gasPrice": "0x0", - "gas": "0x10", "maxPriorityFeePerGas": "0x10", "maxFeePerGas": "0x10", + "gas": "0x10", "nonce": "0x10", "to": null, "v":"0x25", diff --git a/testutil/server.go b/testutil/server.go index 2de865e3..e70cdfc8 100644 --- a/testutil/server.go +++ b/testutil/server.go @@ -247,8 +247,15 @@ func (t *TestServer) SendTxn(txn *ethgo.Transaction) (*ethgo.Receipt, error) { if isEmptyAddr(txn.From) { txn.From = t.Account(0) } - if txn.GasPrice == 0 { - txn.GasPrice = DefaultGasPrice + + if txn.Type == ethgo.TransactionDynamicFee { + if txn.MaxPriorityFeePerGas == nil || txn.MaxPriorityFeePerGas.Cmp(big.NewInt(0)) == 0 { + txn.MaxPriorityFeePerGas = new(big.Int).SetUint64(DefaultGasPrice) + } + } else { + if txn.GasPrice == 0 { + txn.GasPrice = DefaultGasPrice + } } if txn.Gas == 0 { txn.Gas = DefaultGasLimit