@@ -155,7 +155,14 @@ internal async Task<RpcResponseMessage> Request(RpcRequestMessage requestMessage
155
155
{
156
156
ThirdwebDebug . Log ( "Requesting: " + requestMessage . Method + "..." ) ;
157
157
158
- if ( requestMessage . Method == "eth_sendTransaction" )
158
+ if ( requestMessage . Method == "eth_signTransaction" )
159
+ {
160
+ var parameters = JsonConvert . DeserializeObject < object [ ] > ( JsonConvert . SerializeObject ( requestMessage . RawParameters ) ) ;
161
+ var txInput = JsonConvert . DeserializeObject < TransactionInput > ( JsonConvert . SerializeObject ( parameters [ 0 ] ) ) ;
162
+ var partialUserOp = await SignTransactionAsUserOp ( txInput , requestMessage . Id ) ;
163
+ return new RpcResponseMessage ( requestMessage . Id , JsonConvert . SerializeObject ( partialUserOp . EncodeUserOperation ( ) ) ) ;
164
+ }
165
+ else if ( requestMessage . Method == "eth_sendTransaction" )
159
166
{
160
167
return await CreateUserOpAndSend ( requestMessage ) ;
161
168
}
@@ -185,23 +192,13 @@ internal async Task<RpcResponseMessage> Request(RpcRequestMessage requestMessage
185
192
}
186
193
}
187
194
188
- private async Task < RpcResponseMessage > CreateUserOpAndSend ( RpcRequestMessage requestMessage )
195
+ private async Task < EntryPointContract . UserOperation > SignTransactionAsUserOp ( TransactionInput transactionInput , object requestId = null )
189
196
{
190
- await new WaitUntil ( ( ) => ! _deploying ) ;
191
-
192
- await UpdateDeploymentStatus ( ) ;
193
- if ( ! _deployed )
194
- {
195
- _deploying = true ;
196
- }
197
+ requestId ??= SmartWalletClient . GenerateRpcId ( ) ;
197
198
198
199
string apiKey = ThirdwebManager . Instance . SDK . session . Options . clientId ;
199
200
200
- // Deserialize the transaction input from the request message
201
-
202
- var paramList = JsonConvert . DeserializeObject < List < object > > ( JsonConvert . SerializeObject ( requestMessage . RawParameters ) ) ;
203
- var transactionInput = JsonConvert . DeserializeObject < TransactionInput > ( JsonConvert . SerializeObject ( paramList [ 0 ] ) ) ;
204
- var dummySig = Constants . DUMMY_SIG ;
201
+ // Create the user operation and its safe (hexified) version
205
202
206
203
var executeFn = new AccountContract . ExecuteFunction
207
204
{
@@ -212,35 +209,6 @@ private async Task<RpcResponseMessage> CreateUserOpAndSend(RpcRequestMessage req
212
209
} ;
213
210
var executeInput = executeFn . CreateTransactionInput ( Accounts [ 0 ] ) ;
214
211
215
- // Approve ERC20 tokens if any
216
-
217
- if ( ! string . IsNullOrEmpty ( Config . erc20PaymasterAddress ) && ! _approved && ! _approving )
218
- {
219
- try
220
- {
221
- _approving = true ;
222
- var tokenContract = ThirdwebManager . Instance . SDK . GetContract ( Config . erc20TokenAddress ) ;
223
- var approvedAmount = await tokenContract . ERC20 . AllowanceOf ( Accounts [ 0 ] , Config . erc20PaymasterAddress ) ;
224
- if ( BigInteger . Parse ( approvedAmount . value ) == 0 )
225
- {
226
- ThirdwebDebug . Log ( $ "Approving tokens for ERC20Paymaster spending") ;
227
- _deploying = false ;
228
- await tokenContract . ERC20 . SetAllowance ( Config . erc20PaymasterAddress , ( BigInteger . Pow ( 2 , 96 ) - 1 ) . ToString ( ) . ToEth ( ) ) ;
229
- }
230
- _approved = true ;
231
- _approving = false ;
232
- await UpdateDeploymentStatus ( ) ;
233
- }
234
- catch ( Exception e )
235
- {
236
- _approving = false ;
237
- _approved = false ;
238
- throw new Exception ( $ "Approving tokens for ERC20Paymaster spending failed: { e . Message } ") ;
239
- }
240
- }
241
-
242
- // Create the user operation and its safe (hexified) version
243
-
244
212
var ( initCode , gas ) = await GetInitCode ( ) ;
245
213
246
214
var gasPrices = await Utils . GetGasPriceAsync ( ThirdwebManager . Instance . SDK . session . ChainId ) ;
@@ -257,16 +225,16 @@ private async Task<RpcResponseMessage> CreateUserOpAndSend(RpcRequestMessage req
257
225
MaxFeePerGas = gasPrices . MaxFeePerGas ,
258
226
MaxPriorityFeePerGas = gasPrices . MaxPriorityFeePerGas ,
259
227
PaymasterAndData = new byte [ ] { } ,
260
- Signature = dummySig . HexStringToByteArray ( ) ,
228
+ Signature = Constants . DUMMY_SIG . HexStringToByteArray ( ) ,
261
229
} ;
262
230
263
231
// Update paymaster data if any
264
232
265
- partialUserOp . PaymasterAndData = await GetPaymasterAndData ( requestMessage . Id , partialUserOp . EncodeUserOperation ( ) , apiKey ) ;
233
+ partialUserOp . PaymasterAndData = await GetPaymasterAndData ( requestId , partialUserOp . EncodeUserOperation ( ) , apiKey ) ;
266
234
267
235
// Estimate gas
268
236
269
- var gasEstimates = await BundlerClient . EthEstimateUserOperationGas ( Config . bundlerUrl , apiKey , requestMessage . Id , partialUserOp . EncodeUserOperation ( ) , Config . entryPointAddress ) ;
237
+ var gasEstimates = await BundlerClient . EthEstimateUserOperationGas ( Config . bundlerUrl , apiKey , requestId , partialUserOp . EncodeUserOperation ( ) , Config . entryPointAddress ) ;
270
238
partialUserOp . CallGasLimit = 50000 + new HexBigInteger ( gasEstimates . CallGasLimit ) . Value ;
271
239
partialUserOp . VerificationGasLimit = string . IsNullOrEmpty ( Config . erc20PaymasterAddress )
272
240
? new HexBigInteger ( gasEstimates . VerificationGas ) . Value
@@ -275,12 +243,63 @@ private async Task<RpcResponseMessage> CreateUserOpAndSend(RpcRequestMessage req
275
243
276
244
// Update paymaster data if any
277
245
278
- partialUserOp . PaymasterAndData = await GetPaymasterAndData ( requestMessage . Id , partialUserOp . EncodeUserOperation ( ) , apiKey ) ;
246
+ partialUserOp . PaymasterAndData = await GetPaymasterAndData ( requestId , partialUserOp . EncodeUserOperation ( ) , apiKey ) ;
279
247
280
248
// Hash, sign and encode the user operation
281
249
282
250
partialUserOp . Signature = await partialUserOp . HashAndSignUserOp ( Config . entryPointAddress ) ;
283
251
252
+ return partialUserOp ;
253
+ }
254
+
255
+ private async Task < RpcResponseMessage > CreateUserOpAndSend ( RpcRequestMessage requestMessage )
256
+ {
257
+ await new WaitUntil ( ( ) => ! _deploying ) ;
258
+
259
+ await UpdateDeploymentStatus ( ) ;
260
+ if ( ! _deployed )
261
+ {
262
+ _deploying = true ;
263
+ }
264
+
265
+ string apiKey = ThirdwebManager . Instance . SDK . session . Options . clientId ;
266
+
267
+ // Deserialize the transaction input from the request message
268
+
269
+ var paramList = JsonConvert . DeserializeObject < List < object > > ( JsonConvert . SerializeObject ( requestMessage . RawParameters ) ) ;
270
+ var transactionInput = JsonConvert . DeserializeObject < TransactionInput > ( JsonConvert . SerializeObject ( paramList [ 0 ] ) ) ;
271
+
272
+ // Approve ERC20 tokens if any
273
+
274
+ if ( ! string . IsNullOrEmpty ( Config . erc20PaymasterAddress ) && ! _approved && ! _approving )
275
+ {
276
+ try
277
+ {
278
+ _approving = true ;
279
+ var tokenContract = ThirdwebManager . Instance . SDK . GetContract ( Config . erc20TokenAddress ) ;
280
+ var approvedAmount = await tokenContract . ERC20 . AllowanceOf ( Accounts [ 0 ] , Config . erc20PaymasterAddress ) ;
281
+ if ( BigInteger . Parse ( approvedAmount . value ) == 0 )
282
+ {
283
+ ThirdwebDebug . Log ( $ "Approving tokens for ERC20Paymaster spending") ;
284
+ _deploying = false ;
285
+ await tokenContract . ERC20 . SetAllowance ( Config . erc20PaymasterAddress , ( BigInteger . Pow ( 2 , 96 ) - 1 ) . ToString ( ) . ToEth ( ) ) ;
286
+ }
287
+ _approved = true ;
288
+ _approving = false ;
289
+ await UpdateDeploymentStatus ( ) ;
290
+ }
291
+ catch ( Exception e )
292
+ {
293
+ _approving = false ;
294
+ _approved = false ;
295
+ throw new Exception ( $ "Approving tokens for ERC20Paymaster spending failed: { e . Message } ") ;
296
+ }
297
+ }
298
+
299
+ // Create and sign the user operation
300
+
301
+ var partialUserOp = await SignTransactionAsUserOp ( transactionInput , requestMessage . Id ) ;
302
+
284
303
// Send the user operation
285
304
286
305
ThirdwebDebug . Log ( "Valid UserOp: " + JsonConvert . SerializeObject ( partialUserOp ) ) ;
0 commit comments