Skip to content

Commit 6dc5008

Browse files
committed
better handle rpc error
1 parent 8a345cc commit 6dc5008

File tree

5 files changed

+34
-25
lines changed

5 files changed

+34
-25
lines changed

src/utils/error.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,13 @@ export const prettifyError = async (
2626

2727
return error.message;
2828
};
29+
30+
export const isNonceAlreadyUsedError = (error: unknown) =>
31+
(error instanceof Error &&
32+
error.message.toLowerCase().includes("nonce too low")) ||
33+
isEthersErrorCode(error, ethers.errors.NONCE_EXPIRED);
34+
35+
export const isReplacementGasFeeTooLow = (error: unknown) =>
36+
(error instanceof Error &&
37+
error.message.toLowerCase().includes("replacement fee too low")) ||
38+
isEthersErrorCode(error, ethers.errors.REPLACEMENT_UNDERPRICED);

src/worker/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
} from "./listeners/webhookListener";
1010

1111
// Init workers.
12-
import "./tasks/cancelUnusedNoncesWorker";
12+
import "./tasks/cancelRecycledNoncesWorker";
1313
import "./tasks/mineTransactionWorker";
1414
import "./tasks/processEventLogsWorker";
1515
import "./tasks/processTransactionReceiptsWorker";

src/worker/queues/cancelUnusedNoncesQueue.ts renamed to src/worker/queues/cancelRecycledNoncesQueue.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import { Queue } from "bullmq";
22
import { redis } from "../../utils/redis/redis";
33
import { defaultJobOptions } from "./queues";
44

5-
export const CANCEL_UNUSED_NONCES_QUEUE_NAME = "cancel-unused-nonces";
5+
export const CANCEL_RECYCLED_NONCES_QUEUE_NAME = "cancel-recycled-nonces";
66

7-
const _queue = new Queue<string>(CANCEL_UNUSED_NONCES_QUEUE_NAME, {
7+
const _queue = new Queue<string>(CANCEL_RECYCLED_NONCES_QUEUE_NAME, {
88
connection: redis,
99
defaultJobOptions,
1010
});
@@ -13,5 +13,5 @@ _queue.setGlobalConcurrency(1);
1313
_queue.add("hourly-cron", "", {
1414
repeat: { pattern: "* * * * *" },
1515
// Use a constant jobId to not insert multiple repeatable jobs.
16-
jobId: "billing-reporter-hourly-cron",
16+
jobId: "cancel-recycled-nonces-cron",
1717
});

src/worker/tasks/cancelUnusedNoncesWorker.ts renamed to src/worker/tasks/cancelRecycledNoncesWorker.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
import { Job, Processor, Worker } from "bullmq";
2-
import { ethers } from "ethers";
32
import { Address } from "thirdweb";
43
import { recycleNonce } from "../../db/wallets/walletNonce";
5-
import { isEthersErrorCode } from "../../utils/ethers";
4+
import { isNonceAlreadyUsedError } from "../../utils/error";
65
import { logger } from "../../utils/logger";
76
import { redis } from "../../utils/redis/redis";
87
import { sendCancellationTransaction } from "../../utils/transaction/cancelTransaction";
9-
import { CANCEL_UNUSED_NONCES_QUEUE_NAME } from "../queues/cancelUnusedNoncesQueue";
8+
import { CANCEL_RECYCLED_NONCES_QUEUE_NAME } from "../queues/cancelRecycledNoncesQueue";
109
import { logWorkerExceptions } from "../queues/queues";
1110

1211
/**
@@ -33,9 +32,9 @@ const handler: Processor<any, void, string> = async (job: Job<string>) => {
3332
nonce,
3433
});
3534
success.push(nonce);
36-
} catch (e: unknown) {
35+
} catch (error: unknown) {
3736
// Release the nonce if it has not expired.
38-
if (isEthersErrorCode(e, ethers.errors.NONCE_EXPIRED)) {
37+
if (isNonceAlreadyUsedError(error)) {
3938
ignore.push(nonce);
4039
} else {
4140
job.log(`Recycling nonce: ${nonce}`);
@@ -73,7 +72,7 @@ const getAndDeleteUnusedNonces = async (key: string) => {
7372
};
7473

7574
// Worker
76-
const _worker = new Worker(CANCEL_UNUSED_NONCES_QUEUE_NAME, handler, {
75+
const _worker = new Worker(CANCEL_RECYCLED_NONCES_QUEUE_NAME, handler, {
7776
concurrency: 1,
7877
connection: redis,
7978
});

src/worker/tasks/sendTransactionWorker.ts

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import assert from "assert";
22
import { Job, Processor, Worker } from "bullmq";
3-
import { ethers } from "ethers";
43
import superjson from "superjson";
54
import { Hex, toSerializableTransaction } from "thirdweb";
65
import { stringify } from "thirdweb/utils";
@@ -14,8 +13,11 @@ import { getBlockNumberish } from "../../utils/block";
1413
import { getChain } from "../../utils/chain";
1514
import { msSince } from "../../utils/date";
1615
import { env } from "../../utils/env";
17-
import { prettifyError } from "../../utils/error";
18-
import { isEthersErrorCode } from "../../utils/ethers";
16+
import {
17+
isNonceAlreadyUsedError,
18+
isReplacementGasFeeTooLow,
19+
prettifyError,
20+
} from "../../utils/error";
1921
import { redis } from "../../utils/redis/redis";
2022
import { thirdwebClient } from "../../utils/sdk";
2123
import {
@@ -75,7 +77,11 @@ const handler: Processor<any, void, string> = async (job: Job<string>) => {
7577
if (resultTransaction.status === "sent") {
7678
job.log(`Transaction sent: ${stringify(resultTransaction)}.`);
7779
await MineTransactionQueue.add({ queueId: resultTransaction.queueId });
78-
await _reportUsageSuccess(resultTransaction);
80+
81+
// Report usage only on the first transaction send.
82+
if (transaction.status === "queued") {
83+
await _reportUsageSuccess(resultTransaction);
84+
}
7985
} else if (resultTransaction.status === "errored") {
8086
_reportUsageError(resultTransaction);
8187
}
@@ -161,8 +167,7 @@ const _sendTransaction = async (
161167
transactionHash = sendTransactionResult.transactionHash;
162168
job.log(`Sent transaction: ${transactionHash}`);
163169
} catch (error: unknown) {
164-
// NONCE_EXPIRED indicates the nonce was already used onchain. Do not recycle it.
165-
if (!isEthersErrorCode(error, ethers.errors.NONCE_EXPIRED)) {
170+
if (!isNonceAlreadyUsedError(error)) {
166171
job.log(`Recycling nonce: ${nonce}`);
167172
await recycleNonce(chainId, from, nonce);
168173
}
@@ -234,19 +239,14 @@ const _resendTransaction = async (
234239
);
235240
transactionHash = sendTransactionResult.transactionHash;
236241
job.log(`Sent transaction: ${transactionHash}`);
237-
} catch (error: unknown) {
238-
// NONCE_EXPIRED indicates that this transaction was already mined.
239-
// This is not an error.
240-
if (!isEthersErrorCode(error, ethers.errors.NONCE_EXPIRED)) {
242+
} catch (error) {
243+
if (isNonceAlreadyUsedError(error)) {
241244
job.log(
242-
`Nonce used. This transaction was likely already mined. Do not resend.`,
245+
"Nonce used. This transaction was likely already mined. Do not resend.",
243246
);
244247
return null;
245248
}
246-
// REPLACEMENT_UNDERPRICED indicates the mempool is already aware of this transaction
247-
// with >= gas fees. Wait for that one to be mined instead.
248-
// This is not an error.
249-
if (!isEthersErrorCode(error, ethers.errors.REPLACEMENT_UNDERPRICED)) {
249+
if (isReplacementGasFeeTooLow(error)) {
250250
job.log("A pending transaction exists with >= gas fees. Do not resend.");
251251
return null;
252252
}

0 commit comments

Comments
 (0)