Skip to content

Commit

Permalink
Merge branch 'main' into holic/wiresaw-demo
Browse files Browse the repository at this point in the history
  • Loading branch information
alvrs committed Sep 13, 2024
2 parents 2c9ab87 + 2f935cf commit ea6d7c4
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 8 deletions.
13 changes: 13 additions & 0 deletions .changeset/bright-rabbits-trade.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"@latticexyz/common": patch
---

To reset an account's nonce, the nonce manager uses the [`eth_getTransactionCount`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactioncount) RPC method,
which returns the number of transactions sent from the account.
When using the `pending` block tag, this includes transactions in the mempool that have not been included in a block yet.
If an account submits a transaction with a nonce higher than the next valid nonce, this transaction will stay in the mempool until the nonce gap is closed and the transactions nonce is the next valid nonce.
This means if an account has gapped transactions "stuck in the mempool", the `eth_getTransactionCount` method with `pending` block tag can't be used to get the next valid nonce
(since it includes the number of transactions stuck in the mempool).
Since the nonce manager only resets the nonce on reload or in case of a nonce error, using the `latest` block tag by default is the safer choice to be able to recover from nonce gaps.

Note that this change may reveal more "transaction underpriced" errors than before. These errors will now be retried automatically and should go through after the next block is mined.
2 changes: 1 addition & 1 deletion packages/common/src/createNonceManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export type CreateNonceManagerResult = {
export function createNonceManager({
client,
address, // TODO: rename to account?
blockTag = "pending",
blockTag = "latest",
broadcastChannelName,
queueConcurrency = 1,
}: CreateNonceManagerOptions): CreateNonceManagerResult {
Expand Down
2 changes: 1 addition & 1 deletion packages/common/src/getNonceManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const nonceManagers = new Map<string, CreateNonceManagerResult>();
export async function getNonceManager({
client,
address, // TODO: rename to account?
blockTag = "pending",
blockTag = "latest",
...opts
}: CreateNonceManagerOptions): Promise<CreateNonceManagerResult> {
const id = await getNonceManagerId({ client, address, blockTag });
Expand Down
11 changes: 8 additions & 3 deletions packages/common/src/sendTransaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,9 @@ export async function sendTransaction<
const account = parseAccount(rawAccount);
const chain = client.chain;

const blockTag = "pending";
const nonceManager = await getNonceManager({
client: opts.publicClient ?? client,
address: account.address,
blockTag,
queueConcurrency: opts.queueConcurrency,
});

Expand All @@ -74,7 +72,8 @@ export async function sendTransaction<
async () => {
const nonce = nonceManager.nextNonce();
const params = {
blockTag,
// viem_sendTransaction internally estimates gas, which we want to happen on the pending block
blockTag: "pending",
...request,
nonce,
...feeRef.fees,
Expand All @@ -94,6 +93,12 @@ export async function sendTransaction<
debug("got nonce error, retrying", error.message);
return;
}

if (String(error).includes("transaction underpriced")) {
debug("got transaction underpriced error, retrying", error.message);
return;
}

throw error;
},
},
Expand Down
11 changes: 8 additions & 3 deletions packages/common/src/writeContract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,9 @@ export async function writeContract<
const account = parseAccount(rawAccount);
const chain = client.chain;

const blockTag = "pending";
const nonceManager = await getNonceManager({
client: opts.publicClient ?? client,
address: account.address,
blockTag,
queueConcurrency: opts.queueConcurrency,
});

Expand All @@ -78,7 +76,8 @@ export async function writeContract<
async () => {
const nonce = nonceManager.nextNonce();
const params = {
blockTag,
// viem_writeContract internally estimates gas, which we want to happen on the pending block
blockTag: "pending",
...request,
nonce,
...feeRef.fees,
Expand All @@ -98,6 +97,12 @@ export async function writeContract<
debug("got nonce error, retrying", error.message);
return;
}

if (String(error).includes("transaction underpriced")) {
debug("got transaction underpriced error, retrying", error.message);
return;
}

throw error;
},
},
Expand Down

0 comments on commit ea6d7c4

Please sign in to comment.