Skip to content

Commit 1809604

Browse files
authored
Add custom opts in transaction (#195)
* Add custom opts in transaction * Update changelog
1 parent dffc7cc commit 1809604

File tree

9 files changed

+124
-73
lines changed

9 files changed

+124
-73
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 custom `TxnOpts` to send a transaction in `contract` [[GH-195](https://github.com/umbracle/ethgo/issues/195)]
45
- Add `ens resolve` command to resolve an ENS name [[GH-196](https://github.com/umbracle/ethgo/issues/196)]
56
- Fix signing of typed transactions [[GH-197](https://github.com/umbracle/ethgo/issues/197)]
67
- Fix. Use `ethgo.BlockNumber` input to make `Call` in contract [[GH-194](https://github.com/umbracle/ethgo/issues/194)]

Makefile

-5
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,3 @@
33
build-artifacts:
44
@echo "--> Build Artifacts"
55
@sh -c ./scripts/build-artifacts.sh
6-
7-
.PHONY: build-abigen
8-
build-abigen:
9-
@echo "--> Build abigen"
10-
@sh -c ./scripts/build-abigen.sh

builtin/ens/ens.go

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

builtin/ens/resolver.go

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

builtin/erc20/erc20.go

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cmd/abigen/testdata/testdata.go

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

contract/contract.go

+73-61
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414
// Provider handles the interactions with the Ethereum 1x node
1515
type Provider interface {
1616
Call(ethgo.Address, []byte, *CallOpts) ([]byte, error)
17-
Txn(ethgo.Address, ethgo.Key, []byte, *TxnOpts) (Txn, error)
17+
Txn(ethgo.Address, ethgo.Key, []byte) (Txn, error)
1818
}
1919

2020
type jsonRPCNodeProvider struct {
@@ -40,99 +40,112 @@ func (j *jsonRPCNodeProvider) Call(addr ethgo.Address, input []byte, opts *CallO
4040
return raw, nil
4141
}
4242

43-
func (j *jsonRPCNodeProvider) Txn(addr ethgo.Address, key ethgo.Key, input []byte, opts *TxnOpts) (Txn, error) {
44-
var err error
43+
func (j *jsonRPCNodeProvider) Txn(addr ethgo.Address, key ethgo.Key, input []byte) (Txn, error) {
44+
txn := &jsonrpcTransaction{
45+
opts: &TxnOpts{},
46+
input: input,
47+
client: j.client,
48+
key: key,
49+
to: addr,
50+
}
51+
return txn, nil
52+
}
4553

46-
from := key.Address()
54+
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
63+
}
64+
65+
func (j *jsonrpcTransaction) Hash() ethgo.Hash {
66+
return j.hash
67+
}
68+
69+
func (j *jsonrpcTransaction) WithOpts(opts *TxnOpts) {
70+
j.opts = opts
71+
}
72+
73+
func (j *jsonrpcTransaction) Build() error {
74+
var err error
75+
from := j.key.Address()
4776

4877
// estimate gas price
49-
if opts.GasPrice == 0 {
50-
opts.GasPrice, err = j.client.GasPrice()
78+
if j.opts.GasPrice == 0 {
79+
j.opts.GasPrice, err = j.client.GasPrice()
5180
if err != nil {
52-
return nil, err
81+
return err
5382
}
5483
}
5584
// estimate gas limit
56-
if opts.GasLimit == 0 {
85+
if j.opts.GasLimit == 0 {
5786
msg := &ethgo.CallMsg{
5887
From: from,
5988
To: nil,
60-
Data: input,
61-
Value: opts.Value,
62-
GasPrice: opts.GasPrice,
89+
Data: j.input,
90+
Value: j.opts.Value,
91+
GasPrice: j.opts.GasPrice,
6392
}
64-
if addr != ethgo.ZeroAddress {
65-
msg.To = &addr
93+
if j.to != ethgo.ZeroAddress {
94+
msg.To = &j.to
6695
}
67-
opts.GasLimit, err = j.client.EstimateGas(msg)
96+
j.opts.GasLimit, err = j.client.EstimateGas(msg)
6897
if err != nil {
69-
return nil, err
98+
return err
7099
}
71100
}
72101
// calculate the nonce
73-
if opts.Nonce == 0 {
74-
opts.Nonce, err = j.client.GetNonce(from, ethgo.Latest)
102+
if j.opts.Nonce == 0 {
103+
j.opts.Nonce, err = j.client.GetNonce(from, ethgo.Latest)
75104
if err != nil {
76-
return nil, fmt.Errorf("failed to calculate nonce: %v", err)
105+
return fmt.Errorf("failed to calculate nonce: %v", err)
77106
}
78107
}
79108

80109
chainID, err := j.client.ChainID()
81110
if err != nil {
82-
return nil, err
111+
return err
83112
}
84113

85114
// send transaction
86115
rawTxn := &ethgo.Transaction{
87116
From: from,
88-
Input: input,
89-
GasPrice: opts.GasPrice,
90-
Gas: opts.GasLimit,
91-
Value: opts.Value,
92-
Nonce: opts.Nonce,
117+
Input: j.input,
118+
GasPrice: j.opts.GasPrice,
119+
Gas: j.opts.GasLimit,
120+
Value: j.opts.Value,
121+
Nonce: j.opts.Nonce,
122+
ChainID: chainID,
123+
}
124+
if j.to != ethgo.ZeroAddress {
125+
rawTxn.To = &j.to
93126
}
94-
if addr != ethgo.ZeroAddress {
95-
rawTxn.To = &addr
127+
j.txn = rawTxn
128+
return nil
129+
}
130+
131+
func (j *jsonrpcTransaction) Do() error {
132+
if j.txn == nil {
133+
if err := j.Build(); err != nil {
134+
return err
135+
}
96136
}
97137

98-
signer := wallet.NewEIP155Signer(chainID.Uint64())
99-
signedTxn, err := signer.SignTx(rawTxn, key)
138+
signer := wallet.NewEIP155Signer(j.txn.ChainID.Uint64())
139+
signedTxn, err := signer.SignTx(j.txn, j.key)
100140
if err != nil {
101-
return nil, err
141+
return err
102142
}
103143
txnRaw, err := signedTxn.MarshalRLPTo(nil)
104144
if err != nil {
105-
return nil, err
106-
}
107-
108-
txn := &jsonrpcTransaction{
109-
txn: signedTxn,
110-
txnRaw: txnRaw,
111-
client: j.client,
145+
return err
112146
}
113-
return txn, nil
114-
}
115147

116-
type jsonrpcTransaction struct {
117-
hash ethgo.Hash
118-
client *jsonrpc.Eth
119-
txn *ethgo.Transaction
120-
txnRaw []byte
121-
}
122-
123-
func (j *jsonrpcTransaction) Hash() ethgo.Hash {
124-
return j.hash
125-
}
126-
127-
func (j *jsonrpcTransaction) EstimatedGas() uint64 {
128-
return j.txn.Gas
129-
}
130-
131-
func (j *jsonrpcTransaction) GasPrice() uint64 {
132-
return j.txn.GasPrice
133-
}
134-
135-
func (j *jsonrpcTransaction) Do() error {
148+
j.txnRaw = txnRaw
136149
hash, err := j.client.SendRawTransaction(j.txnRaw)
137150
if err != nil {
138151
return err
@@ -162,8 +175,7 @@ func (j *jsonrpcTransaction) Wait() (*ethgo.Receipt, error) {
162175
// Txn is the transaction object returned
163176
type Txn interface {
164177
Hash() ethgo.Hash
165-
EstimatedGas() uint64
166-
GasPrice() uint64
178+
WithOpts(opts *TxnOpts)
167179
Do() error
168180
Wait() (*ethgo.Receipt, error)
169181
}
@@ -289,7 +301,7 @@ func (a *Contract) Txn(method string, args ...interface{}) (Txn, error) {
289301
}
290302
}
291303

292-
txn, err := a.provider.Txn(a.addr, a.key, input, &TxnOpts{})
304+
txn, err := a.provider.Txn(a.addr, a.key, input)
293305
if err != nil {
294306
return nil, err
295307
}

contract/contract_test.go

+42-3
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ func TestContract_Deploy(t *testing.T) {
9999

100100
// create an address and fund it
101101
key, _ := wallet.GenerateKey()
102-
s.Transfer(key.Address(), big.NewInt(1000000000000000000))
102+
s.Fund(key.Address())
103103

104104
p, _ := jsonrpc.NewClient(s.HTTPAddr())
105105

@@ -138,7 +138,7 @@ func TestContract_Transaction(t *testing.T) {
138138

139139
// create an address and fund it
140140
key, _ := wallet.GenerateKey()
141-
s.Transfer(key.Address(), big.NewInt(1000000000000000000))
141+
s.Fund(key.Address())
142142

143143
cc := &testutil.Contract{}
144144
cc.AddEvent(testutil.NewEvent("A").Add("uint256", true))
@@ -171,7 +171,7 @@ func TestContract_CallAtBlock(t *testing.T) {
171171

172172
// create an address and fund it
173173
key, _ := wallet.GenerateKey()
174-
s.Transfer(key.Address(), big.NewInt(1000000000000000000))
174+
s.Fund(key.Address())
175175

176176
cc := &testutil.Contract{}
177177
cc.AddCallback(func() string {
@@ -223,3 +223,42 @@ func TestContract_CallAtBlock(t *testing.T) {
223223
checkVal(ethgo.BlockNumber(receipt.BlockNumber-1), big.NewInt(1))
224224
}
225225
}
226+
227+
func TestContract_SendValueContractCall(t *testing.T) {
228+
s := testutil.NewTestServer(t, nil)
229+
defer s.Close()
230+
231+
key, _ := wallet.GenerateKey()
232+
s.Fund(key.Address())
233+
234+
cc := &testutil.Contract{}
235+
cc.AddCallback(func() string {
236+
return `
237+
function deposit() public payable {
238+
}`
239+
})
240+
241+
artifact, addr := s.DeployContract(cc)
242+
243+
abi, err := abi.NewABI(artifact.Abi)
244+
assert.NoError(t, err)
245+
246+
contract := NewContract(addr, abi, WithJsonRPCEndpoint(s.HTTPAddr()), WithSender(key))
247+
248+
balance := big.NewInt(1)
249+
250+
txn, err := contract.Txn("deposit")
251+
txn.WithOpts(&TxnOpts{Value: balance})
252+
assert.NoError(t, err)
253+
254+
err = txn.Do()
255+
assert.NoError(t, err)
256+
257+
_, err = txn.Wait()
258+
assert.NoError(t, err)
259+
260+
client, _ := jsonrpc.NewClient(s.HTTPAddr())
261+
found, err := client.Eth().GetBalance(addr, ethgo.Latest)
262+
assert.NoError(t, err)
263+
assert.Equal(t, found, balance)
264+
}

testutil/server.go

+4
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,10 @@ func (t *TestServer) Call(msg *ethgo.CallMsg) (string, error) {
205205
return resp, nil
206206
}
207207

208+
func (t *TestServer) Fund(address ethgo.Address) *ethgo.Receipt {
209+
return t.Transfer(address, big.NewInt(1000000000000000000))
210+
}
211+
208212
func (t *TestServer) Transfer(address ethgo.Address, value *big.Int) *ethgo.Receipt {
209213
receipt, err := t.SendTxn(&ethgo.Transaction{
210214
From: t.accounts[0],

0 commit comments

Comments
 (0)