Skip to content

Commit c3af4df

Browse files
authored
Add eip-1559 (#198)
* Add eip-1559 * Update changelog * Fix encoding issue
1 parent 1809604 commit c3af4df

File tree

7 files changed

+91
-21
lines changed

7 files changed

+91
-21
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11

22
# 0.1.2 (Unreleased)
33

4+
- Add option in `contract` to send transactions with EIP-1559 [[GH-198](https://github.com/umbracle/ethgo/issues/198)]
45
- Add custom `TxnOpts` to send a transaction in `contract` [[GH-195](https://github.com/umbracle/ethgo/issues/195)]
56
- Add `ens resolve` command to resolve an ENS name [[GH-196](https://github.com/umbracle/ethgo/issues/196)]
67
- Fix signing of typed transactions [[GH-197](https://github.com/umbracle/ethgo/issues/197)]

contract/contract.go

+40-17
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ type Provider interface {
1818
}
1919

2020
type jsonRPCNodeProvider struct {
21-
client *jsonrpc.Eth
21+
client *jsonrpc.Eth
22+
eip1559 bool
2223
}
2324

2425
func (j *jsonRPCNodeProvider) Call(addr ethgo.Address, input []byte, opts *CallOpts) ([]byte, error) {
@@ -42,24 +43,26 @@ func (j *jsonRPCNodeProvider) Call(addr ethgo.Address, input []byte, opts *CallO
4243

4344
func (j *jsonRPCNodeProvider) Txn(addr ethgo.Address, key ethgo.Key, input []byte) (Txn, error) {
4445
txn := &jsonrpcTransaction{
45-
opts: &TxnOpts{},
46-
input: input,
47-
client: j.client,
48-
key: key,
49-
to: addr,
46+
opts: &TxnOpts{},
47+
input: input,
48+
client: j.client,
49+
key: key,
50+
to: addr,
51+
eip1559: j.eip1559,
5052
}
5153
return txn, nil
5254
}
5355

5456
type jsonrpcTransaction struct {
55-
to ethgo.Address
56-
input []byte
57-
hash ethgo.Hash
58-
opts *TxnOpts
59-
key ethgo.Key
60-
client *jsonrpc.Eth
61-
txn *ethgo.Transaction
62-
txnRaw []byte
57+
to ethgo.Address
58+
input []byte
59+
hash ethgo.Hash
60+
opts *TxnOpts
61+
key ethgo.Key
62+
client *jsonrpc.Eth
63+
txn *ethgo.Transaction
64+
txnRaw []byte
65+
eip1559 bool
6366
}
6467

6568
func (j *jsonrpcTransaction) Hash() ethgo.Hash {
@@ -75,7 +78,7 @@ func (j *jsonrpcTransaction) Build() error {
7578
from := j.key.Address()
7679

7780
// estimate gas price
78-
if j.opts.GasPrice == 0 {
81+
if j.opts.GasPrice == 0 && !j.eip1559 {
7982
j.opts.GasPrice, err = j.client.GasPrice()
8083
if err != nil {
8184
return err
@@ -124,6 +127,19 @@ func (j *jsonrpcTransaction) Build() error {
124127
if j.to != ethgo.ZeroAddress {
125128
rawTxn.To = &j.to
126129
}
130+
131+
if j.eip1559 {
132+
rawTxn.Type = ethgo.TransactionDynamicFee
133+
134+
// use gas price as fee data
135+
gasPrice, err := j.client.GasPrice()
136+
if err != nil {
137+
return err
138+
}
139+
rawTxn.MaxFeePerGas = new(big.Int).SetUint64(gasPrice)
140+
rawTxn.MaxPriorityFeePerGas = new(big.Int).SetUint64(gasPrice)
141+
}
142+
127143
j.txn = rawTxn
128144
return nil
129145
}
@@ -185,6 +201,7 @@ type Opts struct {
185201
JsonRPCClient *jsonrpc.Eth
186202
Provider Provider
187203
Sender ethgo.Key
204+
EIP1559 bool
188205
}
189206

190207
type ContractOption func(*Opts)
@@ -213,6 +230,12 @@ func WithSender(sender ethgo.Key) ContractOption {
213230
}
214231
}
215232

233+
func WithEIP1559() ContractOption {
234+
return func(o *Opts) {
235+
o.EIP1559 = true
236+
}
237+
}
238+
216239
func DeployContract(abi *abi.ABI, bin []byte, args []interface{}, opts ...ContractOption) (Txn, error) {
217240
a := NewContract(ethgo.Address{}, abi, opts...)
218241
a.bin = bin
@@ -231,10 +254,10 @@ func NewContract(addr ethgo.Address, abi *abi.ABI, opts ...ContractOption) *Cont
231254
if opt.Provider != nil {
232255
provider = opt.Provider
233256
} else if opt.JsonRPCClient != nil {
234-
provider = &jsonRPCNodeProvider{client: opt.JsonRPCClient}
257+
provider = &jsonRPCNodeProvider{client: opt.JsonRPCClient, eip1559: opt.EIP1559}
235258
} else {
236259
client, _ := jsonrpc.NewClient(opt.JsonRPCEndpoint)
237-
provider = &jsonRPCNodeProvider{client: client.Eth()}
260+
provider = &jsonRPCNodeProvider{client: client.Eth(), eip1559: opt.EIP1559}
238261
}
239262

240263
a := &Contract{

contract/contract_test.go

+37
Original file line numberDiff line numberDiff line change
@@ -262,3 +262,40 @@ func TestContract_SendValueContractCall(t *testing.T) {
262262
assert.NoError(t, err)
263263
assert.Equal(t, found, balance)
264264
}
265+
266+
func TestContract_EIP1559(t *testing.T) {
267+
s := testutil.NewTestServer(t, nil)
268+
defer s.Close()
269+
270+
key, _ := wallet.GenerateKey()
271+
s.Fund(key.Address())
272+
273+
cc := &testutil.Contract{}
274+
cc.AddOutputCaller("example")
275+
276+
artifact, addr := s.DeployContract(cc)
277+
278+
abi, err := abi.NewABI(artifact.Abi)
279+
assert.NoError(t, err)
280+
281+
client, _ := jsonrpc.NewClient(s.HTTPAddr())
282+
contract := NewContract(addr, abi, WithJsonRPC(client.Eth()), WithSender(key), WithEIP1559())
283+
284+
txn, err := contract.Txn("example")
285+
assert.NoError(t, err)
286+
287+
err = txn.Do()
288+
assert.NoError(t, err)
289+
290+
_, err = txn.Wait()
291+
assert.NoError(t, err)
292+
293+
// get transaction from rpc endpoint
294+
txnObj, err := client.Eth().GetTransactionByHash(txn.Hash())
295+
assert.NoError(t, err)
296+
297+
assert.NotZero(t, txnObj.Gas)
298+
assert.NotZero(t, txnObj.GasPrice)
299+
assert.NotZero(t, txnObj.MaxFeePerGas)
300+
assert.NotZero(t, txnObj.MaxPriorityFeePerGas)
301+
}

structs_unmarshal.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -197,17 +197,17 @@ func (t *Transaction) unmarshalJSON(v *fastjson.Value) error {
197197
}
198198
}
199199

200+
if t.Gas, err = decodeUint(v, "gas"); err != nil {
201+
return err
202+
}
203+
200204
if typ == TransactionDynamicFee {
201205
if t.MaxPriorityFeePerGas, err = decodeBigInt(t.MaxPriorityFeePerGas, v, "maxPriorityFeePerGas"); err != nil {
202206
return err
203207
}
204208
if t.MaxFeePerGas, err = decodeBigInt(t.MaxFeePerGas, v, "maxFeePerGas"); err != nil {
205209
return err
206210
}
207-
} else {
208-
if t.Gas, err = decodeUint(v, "gas"); err != nil {
209-
return err
210-
}
211211
}
212212

213213
// Check if the block hash field is set

testsuite/transaction-eip1159.json

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"input": "0x00",
55
"value": "0x0",
66
"gasPrice": "0x0",
7+
"gas": "0x10",
78
"maxPriorityFeePerGas": "0x10",
89
"maxFeePerGas": "0x10",
910
"nonce": "0x10",

website/components/eip.jsx

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
import Link from 'next/link'
3+
4+
export default function EIPLink({children, num}) {
5+
return <Link href={`https://github.com/ethereum/EIPs/blob/master/EIPS/eip-${num}.md`}>{children}</Link>
6+
}

website/pages/contract.mdx

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11

22
import GoDocLink from '../components/godoc'
3+
import EIPLink from '../components/eip'
34
import {Address, ABI} from '../components/primitives'
45

56
# Contract
@@ -27,6 +28,7 @@ Besides `addr` and `abi`, you can use the option pattern to parametrize the cont
2728
- <GoDocLink href="contract#WithJsonRPCClient">WithJsonRPCClient</GoDocLink>: [`JsonRPC`](/jsonrpc) object to make rpc calls. It takes preference over an address from `WithAddress`.
2829
- <GoDocLink href="contract#WithSigner">WithSigner</GoDocLink>: [`Signer`](/signers/signer) object to send transactions or use a custom `from` address.
2930
- <GoDocLink href="contract#WithProvider">WithProvider</GoDocLink>: Custom <GoDocLink href="contract#NodeProvider">NodeProvider</GoDocLink> implementation to resolve calls and transactions.
31+
- <GoDocLink href="contract#WithEIP1559">WithEIP1559</GoDocLink>: Send transactions with EIP-1559 pricing.
3032

3133
## Examples
3234

0 commit comments

Comments
 (0)