@@ -8,6 +8,8 @@ import "solady/src/utils/ECDSA.sol";
8
8
9
9
import { EntryPoint } from "account-abstraction/contracts/core/EntryPoint.sol " ;
10
10
import { IEntryPoint } from "account-abstraction/contracts/interfaces/IEntryPoint.sol " ;
11
+ import { IAccount } from "account-abstraction/contracts/interfaces/IAccount.sol " ;
12
+ import { Exec } from "account-abstraction/contracts/utils/Exec.sol " ;
11
13
import { IPaymaster } from "account-abstraction/contracts/interfaces/IPaymaster.sol " ;
12
14
import { PackedUserOperation } from "account-abstraction/contracts/interfaces/PackedUserOperation.sol " ;
13
15
@@ -20,7 +22,8 @@ import { Bootstrap, BootstrapConfig } from "nexus/contracts/utils/Bootstrap.sol"
20
22
import { CheatCodes } from "nexus/test/foundry/utils/CheatCodes.sol " ;
21
23
import { BaseEventsAndErrors } from "./BaseEventsAndErrors.sol " ;
22
24
23
- import { BiconomySponsorshipPaymaster } from "../../../contracts/sponsorship/SponsorshipPaymasterWithDynamicAdjustment.sol " ;
25
+ import { BiconomySponsorshipPaymaster } from
26
+ "../../../contracts/sponsorship/SponsorshipPaymasterWithDynamicAdjustment.sol " ;
24
27
25
28
abstract contract TestBase is CheatCodes , BaseEventsAndErrors {
26
29
// -----------------------------------------
@@ -59,9 +62,12 @@ abstract contract TestBase is CheatCodes, BaseEventsAndErrors {
59
62
BiconomyMetaFactory internal META_FACTORY;
60
63
MockValidator internal VALIDATOR_MODULE;
61
64
Nexus internal ACCOUNT_IMPLEMENTATION;
62
-
63
65
Bootstrap internal BOOTSTRAPPER;
64
66
67
+ // Used to buffer user op gas limits
68
+ // GAS_LIMIT = (ESTIMATED_GAS * GAS_BUFFER_RATIO) / 100
69
+ uint8 private constant GAS_BUFFER_RATIO = 110 ;
70
+
65
71
// -----------------------------------------
66
72
// Modifiers
67
73
// -----------------------------------------
@@ -332,23 +338,50 @@ abstract contract TestBase is CheatCodes, BaseEventsAndErrors {
332
338
assertTrue (res, "Pre-funding account should succeed " );
333
339
}
334
340
341
+ function estimateUserOpGasCosts (PackedUserOperation memory userOp )
342
+ internal
343
+ prankModifier (ENTRYPOINT_ADDRESS)
344
+ returns (uint256 verificationGasUsed , uint256 callGasUsed , uint256 verificationGasLimit , uint256 callGasLimit )
345
+ {
346
+ bytes32 userOpHash = ENTRYPOINT.getUserOpHash (userOp);
347
+ verificationGasUsed = gasleft ();
348
+ IAccount (userOp.sender).validateUserOp (userOp, userOpHash, 0 );
349
+ verificationGasUsed = verificationGasUsed - gasleft ();
350
+
351
+ callGasUsed = gasleft ();
352
+ bool success = Exec.call (userOp.sender, 0 , userOp.callData, 3e6 );
353
+ callGasUsed = callGasUsed - gasleft ();
354
+ assert (success);
355
+
356
+ verificationGasLimit = (verificationGasUsed * GAS_BUFFER_RATIO) / 100 ;
357
+ callGasLimit = (callGasUsed * GAS_BUFFER_RATIO) / 100 ;
358
+ }
359
+
335
360
function estimatePaymasterGasCosts (
336
361
BiconomySponsorshipPaymaster paymaster ,
337
362
PackedUserOperation memory userOp ,
338
- bytes32 userOpHash ,
339
363
uint256 requiredPreFund
340
364
)
341
365
internal
342
366
prankModifier (ENTRYPOINT_ADDRESS)
343
- returns (uint256 validationGasLimit , uint256 postopGasLimit )
367
+ returns (uint256 validationGasUsed , uint256 postopGasUsed , uint256 validationGasLimit , uint256 postopGasLimit )
344
368
{
345
- validationGasLimit = gasleft ();
369
+ bytes32 userOpHash = ENTRYPOINT.getUserOpHash (userOp);
370
+ // Warm up accounts to get more accurate gas estimations
346
371
(bytes memory context ,) = paymaster.validatePaymasterUserOp (userOp, userOpHash, requiredPreFund);
347
- validationGasLimit = validationGasLimit - gasleft ();
372
+ paymaster.postOp (IPaymaster.PostOpMode.opSucceeded, context, 1e12 , 3e6 );
373
+
374
+ // Estimate gas used
375
+ validationGasUsed = gasleft ();
376
+ (context,) = paymaster.validatePaymasterUserOp (userOp, userOpHash, requiredPreFund);
377
+ validationGasUsed = validationGasUsed - gasleft ();
348
378
349
- postopGasLimit = gasleft ();
379
+ postopGasUsed = gasleft ();
350
380
paymaster.postOp (IPaymaster.PostOpMode.opSucceeded, context, 1e12 , 3e6 );
351
- postopGasLimit = postopGasLimit - gasleft ();
381
+ postopGasUsed = (postopGasUsed - gasleft ());
382
+
383
+ validationGasLimit = (validationGasUsed * GAS_BUFFER_RATIO) / 100 ;
384
+ postopGasLimit = (postopGasUsed * GAS_BUFFER_RATIO) / 100 ;
352
385
}
353
386
354
387
function createUserOp (
@@ -359,24 +392,30 @@ abstract contract TestBase is CheatCodes, BaseEventsAndErrors {
359
392
internal
360
393
returns (PackedUserOperation memory userOp , bytes32 userOpHash )
361
394
{
362
- // Create userOp with no paymaster gas estimates
395
+ // Create userOp with no gas estimates
363
396
uint48 validUntil = uint48 (block .timestamp + 1 days);
364
397
uint48 validAfter = uint48 (block .timestamp );
365
398
366
399
userOp = buildUserOpWithCalldata (sender, "" , address (VALIDATOR_MODULE));
367
400
368
- (userOp.paymasterAndData, ) = generateAndSignPaymasterData (
401
+ (userOp.paymasterAndData,) = generateAndSignPaymasterData (
369
402
userOp, PAYMASTER_SIGNER, paymaster, 3e6 , 3e6 , DAPP_ACCOUNT.addr, validUntil, validAfter, dynamicAdjustment
370
403
);
371
404
userOp.signature = signUserOp (sender, userOp);
372
405
406
+ (,, uint256 verificationGasLimit , uint256 callGasLimit ) = estimateUserOpGasCosts (userOp);
373
407
// Estimate paymaster gas limits
374
- userOpHash = ENTRYPOINT.getUserOpHash (userOp);
375
- (uint256 validationGasLimit , uint256 postopGasLimit ) =
376
- estimatePaymasterGasCosts (paymaster, userOp, userOpHash, 5e4 );
408
+ (, uint256 postopGasUsed , uint256 validationGasLimit , uint256 postopGasLimit ) =
409
+ estimatePaymasterGasCosts (paymaster, userOp, 5e4 );
410
+
411
+ vm.startPrank (paymaster.owner ());
412
+ // Set unaccounted gas to be gas used in postop + 1000 for EP overhead and penalty
413
+ paymaster.setUnaccountedGas (uint48 (postopGasUsed + 1000 ));
414
+ vm.stopPrank ();
377
415
378
416
// Ammend the userop to have new gas limits and signature
379
- (userOp.paymasterAndData, ) = generateAndSignPaymasterData (
417
+ userOp.accountGasLimits = bytes32 (abi.encodePacked (uint128 (verificationGasLimit), uint128 (callGasLimit)));
418
+ (userOp.paymasterAndData,) = generateAndSignPaymasterData (
380
419
userOp,
381
420
PAYMASTER_SIGNER,
382
421
paymaster,
0 commit comments