@@ -120,7 +120,22 @@ const _sendUserOp = async (
120
120
assert ( queuedTransaction . isUserOp ) ;
121
121
122
122
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
+
124
139
const userOpHash = await bundleUserOp ( {
125
140
userOp : signedUserOp ,
126
141
options : {
@@ -150,34 +165,17 @@ const _sendTransaction = async (
150
165
assert ( ! queuedTransaction . isUserOp ) ;
151
166
152
167
const { queueId, chainId, from } = queuedTransaction ;
153
- const chain = await getChain ( chainId ) ;
154
-
155
168
// Populate the transaction to resolve gas values.
156
169
// This call throws if the execution would be reverted.
157
170
// 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 ;
181
179
}
182
180
183
181
// Acquire an unused nonce for this transaction.
@@ -393,3 +391,39 @@ export const initSendTransactionWorker = () => {
393
391
}
394
392
} ) ;
395
393
} ;
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