From 91240b7ffe5eb35438103b91fa0fa7b4af709bdb Mon Sep 17 00:00:00 2001 From: Ferran Borreguero Date: Sat, 16 Apr 2022 00:07:35 +0200 Subject: [PATCH] Add nonce when sending transaction in contract (#185) * Add nonce when sending transaction in contract * Add Changelog entry --- CHANGELOG.md | 1 + contract/contract.go | 9 +++++++++ contract/contract_test.go | 21 ++++++++++++--------- wallet/signer.go | 14 ++++++++++++-- wallet/signer_test.go | 6 ++++++ 5 files changed, 40 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 608f504b..bd96d2ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # 0.1.1 (Not released) +- Retrieve latest nonce when sending a transaction on `contract` [[GH-185](https://github.com/umbracle/ethgo/issues/185)] - Add `etherscan.GasPrice` function to return last block gas price [[GH-182](https://github.com/umbracle/ethgo/issues/182)] - Add `4byte` package and cli [[GH-178](https://github.com/umbracle/ethgo/issues/178)] - Install and use `ethers.js` spec tests for wallet private key decoding [[GH-177](https://github.com/umbracle/ethgo/issues/177)] diff --git a/contract/contract.go b/contract/contract.go index bad361cf..92a017c3 100644 --- a/contract/contract.go +++ b/contract/contract.go @@ -69,6 +69,13 @@ func (j *jsonRPCNodeProvider) Txn(addr ethgo.Address, key ethgo.Key, input []byt return nil, err } } + // calculate the nonce + if opts.Nonce == 0 { + opts.Nonce, err = j.client.GetNonce(from, ethgo.Latest) + if err != nil { + return nil, fmt.Errorf("failed to calculate nonce: %v", err) + } + } chainID, err := j.client.ChainID() if err != nil { @@ -82,6 +89,7 @@ func (j *jsonRPCNodeProvider) Txn(addr ethgo.Address, key ethgo.Key, input []byt GasPrice: opts.GasPrice, Gas: opts.GasLimit, Value: opts.Value, + Nonce: opts.Nonce, } if addr != ethgo.ZeroAddress { rawTxn.To = &addr @@ -244,6 +252,7 @@ type TxnOpts struct { Value *big.Int GasPrice uint64 GasLimit uint64 + Nonce uint64 } func (a *Contract) Txn(method string, args ...interface{}) (Txn, error) { diff --git a/contract/contract_test.go b/contract/contract_test.go index 6098857c..073d4b3e 100644 --- a/contract/contract_test.go +++ b/contract/contract_test.go @@ -149,15 +149,18 @@ func TestContract_Transaction(t *testing.T) { abi, err := abi.NewABI(artifact.Abi) assert.NoError(t, err) - // create a transaction - i := NewContract(addr, abi, WithJsonRPCEndpoint(s.HTTPAddr()), WithSender(key)) - txn, err := i.Txn("setA") - assert.NoError(t, err) + // send multiple transactions + contract := NewContract(addr, abi, WithJsonRPCEndpoint(s.HTTPAddr()), WithSender(key)) - err = txn.Do() - assert.NoError(t, err) + for i := 0; i < 10; i++ { + txn, err := contract.Txn("setA") + assert.NoError(t, err) - receipt, err := txn.Wait() - assert.NoError(t, err) - assert.Len(t, receipt.Logs, 1) + err = txn.Do() + assert.NoError(t, err) + + receipt, err := txn.Wait() + assert.NoError(t, err) + assert.Len(t, receipt.Logs, 1) + } } diff --git a/wallet/signer.go b/wallet/signer.go index 323f21a7..135adcca 100644 --- a/wallet/signer.go +++ b/wallet/signer.go @@ -40,6 +40,16 @@ func (e *EIP1155Signer) RecoverSender(tx *ethgo.Transaction) (ethgo.Address, err return addr, nil } +func trimBytesZeros(b []byte) []byte { + var i int + for i = 0; i < len(b); i++ { + if b[i] != 0x0 { + break + } + } + return b[i:] +} + func (e *EIP1155Signer) SignTx(tx *ethgo.Transaction, key ethgo.Key) (*ethgo.Transaction, error) { hash := signHash(tx, e.chainID) @@ -50,8 +60,8 @@ func (e *EIP1155Signer) SignTx(tx *ethgo.Transaction, key ethgo.Key) (*ethgo.Tra vv := uint64(sig[64]) + 35 + e.chainID*2 - tx.R = sig[:32] - tx.S = sig[32:64] + tx.R = trimBytesZeros(sig[:32]) + tx.S = trimBytesZeros(sig[32:64]) tx.V = new(big.Int).SetUint64(vv).Bytes() return tx, nil } diff --git a/wallet/signer_test.go b/wallet/signer_test.go index c60502e1..3ac5a854 100644 --- a/wallet/signer_test.go +++ b/wallet/signer_test.go @@ -35,3 +35,9 @@ func TestSigner_EIP1155(t *testing.T) { assert.NotEqual(t, from, from2) */ } + +func TestTrimBytesZeros(t *testing.T) { + assert.Equal(t, trimBytesZeros([]byte{0x1, 0x2}), []byte{0x1, 0x2}) + assert.Equal(t, trimBytesZeros([]byte{0x0, 0x1}), []byte{0x1}) + assert.Equal(t, trimBytesZeros([]byte{0x0, 0x0}), []byte{}) +}