Skip to content

Commit

Permalink
Increment nonce count when populating transaction (#54)
Browse files Browse the repository at this point in the history
Increment nonce count when populating transaction

Co-authored-by: markspanbroek <[email protected]>
  • Loading branch information
emizzle and markspanbroek authored Sep 14, 2023
1 parent 8fff631 commit f030347
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 5 deletions.
1 change: 1 addition & 0 deletions ethers/providers/jsonrpc.nim
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ method signMessage*(signer: JsonRpcSigner,
method sendTransaction*(signer: JsonRpcSigner,
transaction: Transaction): Future[TransactionResponse] {.async.} =
convertError:
signer.updateNonce(transaction.nonce)
let
client = await signer.provider.client
hash = await client.eth_sendTransaction(transaction)
Expand Down
27 changes: 25 additions & 2 deletions ethers/signer.nim
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ import ./provider

export basics

type Signer* = ref object of RootObj
type
Signer* = ref object of RootObj
lastSeenNonce: ?UInt256

type SignerError* = object of EthersError

template raiseSignerError(message: string) =
Expand Down Expand Up @@ -41,6 +44,26 @@ method estimateGas*(signer: Signer,
method getChainId*(signer: Signer): Future[UInt256] {.base, gcsafe.} =
signer.provider.getChainId()

method getNonce(signer: Signer): Future[UInt256] {.base, gcsafe, async.} =
var nonce = await signer.getTransactionCount(BlockTag.pending)

if lastSeen =? signer.lastSeenNonce and lastSeen >= nonce:
nonce = (lastSeen + 1.u256)
signer.lastSeenNonce = some nonce

return nonce

method updateNonce*(signer: Signer, nonce: ?UInt256) {.base, gcsafe.} =
without nonce =? nonce:
return

without lastSeen =? signer.lastSeenNonce:
signer.lastSeenNonce = some nonce
return

if nonce > lastSeen:
signer.lastSeenNonce = some nonce

method populateTransaction*(signer: Signer,
transaction: Transaction):
Future[Transaction] {.base, async.} =
Expand All @@ -55,7 +78,7 @@ method populateTransaction*(signer: Signer,
if transaction.sender.isNone:
populated.sender = some(await signer.getAddress())
if transaction.nonce.isNone:
populated.nonce = some(await signer.getTransactionCount(BlockTag.pending))
populated.nonce = some(await signer.getNonce())
if transaction.chainId.isNone:
populated.chainId = some(await signer.getChainId())
if transaction.gasPrice.isNone and (transaction.maxFee.isNone or transaction.maxPriorityFee.isNone):
Expand Down
6 changes: 3 additions & 3 deletions ethers/transaction.nim
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ func `$`*(transaction: Transaction): string =
result &= "value: " & $transaction.value & ", "
result &= "data: 0x" & $transaction.data.toHex
if nonce =? transaction.nonce:
result &= ", nonce: 0x" & $nonce.toHex
result &= ", nonce: " & $nonce
if chainId =? transaction.chainId:
result &= ", chainId: " & $chainId
if gasPrice =? transaction.gasPrice:
result &= ", gasPrice: 0x" & $gasPrice.toHex
result &= ", gasPrice: " & $gasPrice
if gasLimit =? transaction.gasLimit:
result &= ", gasLimit: 0x" & $gasLimit.toHex
result &= ", gasLimit: " & $gasLimit
result &= ")"
1 change: 1 addition & 0 deletions ethers/wallet.nim
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,5 @@ proc signTransaction*(wallet: Wallet,

method sendTransaction*(wallet: Wallet, transaction: Transaction): Future[TransactionResponse] {.async.} =
let signed = await signTransaction(wallet, transaction)
wallet.updateNonce(transaction.nonce)
return await provider(wallet).sendTransaction(signed)
21 changes: 21 additions & 0 deletions testmodule/providers/jsonrpc/testJsonRpcSigner.nim
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,24 @@ suite "JsonRpcSigner":
transaction.chainId = 0xdeadbeef.u256.some
expect SignerError:
discard await signer.populateTransaction(transaction)

test "concurrent populate calls increment nonce":
let signer = provider.getSigner()
let count = await signer.getTransactionCount(BlockTag.pending)
var transaction1 = Transaction.example
var transaction2 = Transaction.example
var transaction3 = Transaction.example

let populated = await allFinished(
signer.populateTransaction(transaction1),
signer.populateTransaction(transaction2),
signer.populateTransaction(transaction3)
)

transaction1 = await populated[0]
transaction2 = await populated[1]
transaction3 = await populated[2]

check !transaction1.nonce == count
check !transaction2.nonce == count + 1.u256
check !transaction3.nonce == count + 2.u256

0 comments on commit f030347

Please sign in to comment.