Skip to content

Commit 28df397

Browse files
authored
chore: toSerializableTransaction function for gas estimation (#652)
* chore: toSerializableTransaction function for gas estimation * chore: Refactor gas estimation in sendTransactionWorker * Revert "chore: Refactor gas estimation in sendTransactionWorker" This reverts commit 4b2170b. * make it simpler * chore: add getPopulatedTransactionOrErroredTransaction helper * chore: log on estimate error
1 parent 81ca850 commit 28df397

File tree

2 files changed

+67
-40
lines changed

2 files changed

+67
-40
lines changed

src/utils/transaction/userOperation.ts

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
getContract,
66
prepareContractCall,
77
readContract,
8+
toSerializableTransaction,
89
} from "thirdweb";
910
import {
1011
UserOperation,
@@ -19,6 +20,7 @@ import { QueuedTransaction } from "./types";
1920

2021
export const generateSignedUserOperation = async (
2122
queuedTransaction: QueuedTransaction,
23+
populatedTransaction: Awaited<ReturnType<typeof toSerializableTransaction>>,
2224
): Promise<UserOperation> => {
2325
const {
2426
chainId,
@@ -73,24 +75,15 @@ export const generateSignedUserOperation = async (
7375
address: accountFactoryAddress as Address,
7476
});
7577

76-
let toAddress: string | undefined;
77-
let txValue: bigint | undefined;
78-
let txData: Hex | undefined;
79-
80-
// Handle UserOp Requests
81-
if (data && target) {
82-
toAddress = target;
83-
txValue = value || 0n;
84-
txData = data;
85-
} else {
86-
throw new Error("Invalid UserOperation parameters");
87-
}
88-
8978
// Prepare UserOperation Call
9079
const userOpCall = prepareContractCall({
9180
contract: smartAccountContract,
9281
method: "function execute(address, uint256, bytes)",
93-
params: [toAddress || "", txValue || 0n, txData || "0x"],
82+
params: [
83+
populatedTransaction.to || "",
84+
populatedTransaction.value || 0n,
85+
populatedTransaction.data,
86+
],
9487
});
9588

9689
// Create Unsigned UserOperation

src/worker/tasks/sendTransactionWorker.ts

Lines changed: 60 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,22 @@ const _sendUserOp = async (
120120
assert(queuedTransaction.isUserOp);
121121

122122
const chain = await getChain(queuedTransaction.chainId);
123-
const signedUserOp = await generateSignedUserOperation(queuedTransaction);
123+
124+
const [populatedTransaction, erroredTransaction] =
125+
await getPopulatedOrErroredTransaction(queuedTransaction);
126+
127+
if (erroredTransaction) {
128+
job.log(
129+
`Failed to validate transaction: ${erroredTransaction.errorMessage}`,
130+
);
131+
return erroredTransaction;
132+
}
133+
134+
const signedUserOp = await generateSignedUserOperation(
135+
queuedTransaction,
136+
populatedTransaction,
137+
);
138+
124139
const userOpHash = await bundleUserOp({
125140
userOp: signedUserOp,
126141
options: {
@@ -150,34 +165,17 @@ const _sendTransaction = async (
150165
assert(!queuedTransaction.isUserOp);
151166

152167
const { queueId, chainId, from } = queuedTransaction;
153-
const chain = await getChain(chainId);
154-
155168
// Populate the transaction to resolve gas values.
156169
// This call throws if the execution would be reverted.
157170
// The nonce is _not_ set yet.
158-
let populatedTransaction: Awaited<
159-
ReturnType<typeof toSerializableTransaction>
160-
>;
161-
try {
162-
populatedTransaction = await toSerializableTransaction({
163-
from: getChecksumAddress(from),
164-
transaction: {
165-
client: thirdwebClient,
166-
chain,
167-
...queuedTransaction,
168-
// Stub the nonce because it will be overridden later.
169-
nonce: 1,
170-
},
171-
});
172-
} catch (e: unknown) {
173-
// If the transaction will revert, error.message contains the human-readable error.
174-
const errorMessage = (e as Error)?.message ?? `${e}`;
175-
job.log(`Failed to estimate gas: ${errorMessage}`);
176-
return {
177-
...queuedTransaction,
178-
status: "errored",
179-
errorMessage,
180-
};
171+
const [populatedTransaction, erroredTransaction] =
172+
await getPopulatedOrErroredTransaction(queuedTransaction);
173+
174+
if (erroredTransaction) {
175+
job.log(
176+
`Failed to validate transaction: ${erroredTransaction.errorMessage}`,
177+
);
178+
return erroredTransaction;
181179
}
182180

183181
// Acquire an unused nonce for this transaction.
@@ -393,3 +391,39 @@ export const initSendTransactionWorker = () => {
393391
}
394392
});
395393
};
394+
395+
export const getPopulatedOrErroredTransaction = async (
396+
queuedTransaction: QueuedTransaction,
397+
): Promise<
398+
| [Awaited<ReturnType<typeof toSerializableTransaction>>, undefined]
399+
| [undefined, ErroredTransaction]
400+
> => {
401+
try {
402+
const from = queuedTransaction.isUserOp
403+
? queuedTransaction.accountAddress
404+
: queuedTransaction.from;
405+
406+
if (!from) throw new Error("Invalid transaction parameters: from");
407+
408+
const populatedTransaction = await toSerializableTransaction({
409+
from: getChecksumAddress(from),
410+
transaction: {
411+
client: thirdwebClient,
412+
chain: await getChain(queuedTransaction.chainId),
413+
...queuedTransaction,
414+
// if transaction is EOA, we stub the nonce to reduce RPC calls
415+
nonce: queuedTransaction.isUserOp ? undefined : 1,
416+
},
417+
});
418+
419+
return [populatedTransaction, undefined];
420+
} catch (e: unknown) {
421+
const erroredTransaction: ErroredTransaction = {
422+
...queuedTransaction,
423+
status: "errored",
424+
errorMessage: (e as Error)?.message ?? `${e}`,
425+
};
426+
427+
return [undefined, erroredTransaction];
428+
}
429+
};

0 commit comments

Comments
 (0)