Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AA-216 Proposal: Packing UserOperation and paymaster gas limits #363

Merged
merged 28 commits into from
Jan 8, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 23 additions & 16 deletions contracts/core/EntryPoint.sol
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,10 @@ contract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard,
struct MemoryUserOp {
address sender;
uint256 nonce;
uint256 callGasLimit;
uint256 verificationGasLimit;
uint128 verificationGasLimit;
uint128 callGasLimit;
uint128 paymasterVerificationGasLimit;
uint128 paymasterPostOpGasLimit;
uint256 preVerificationGas;
address paymaster;
uint256 maxFeePerGas;
Expand Down Expand Up @@ -261,7 +263,10 @@ contract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard,
unchecked {
// handleOps was called with gas limit too low. abort entire bundle.
if (
gasleft() < callGasLimit + mUserOp.verificationGasLimit + 5000
gasleft() <
callGasLimit +
mUserOp.paymasterPostOpGasLimit +
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this point we already have a context, so if it is empty the postOp will not be called. I think it may make sense to allow the transaction to go on in this case, instead of always adding paymasterPostOpGasLimit to the required gas left?
Say, the UserOp have requested 1'000'000 gas for a postOp but it does not need it any more, why should this check fail?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why should we (entrypoint) waste gas to check it? it is the paymaster's job to put a valid postOpGasLimit, even if context is empty.
There is another edge case: validatePaymasterUserOp() returns a context, and the postOpGasLimit` is zero: in this case, we still execute the callData and revert the postOp (on OOG) - again, because it is not the EntryPoint's job to validate the userop fields.

5000
) {
assembly {
mstore(0, INNER_OUT_OF_GAS)
Expand Down Expand Up @@ -313,8 +318,7 @@ contract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard,
) internal pure {
mUserOp.sender = userOp.sender;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not have the entire UserOperation => MemoryUserOp conversion in the UserOperationLib library? Construction of a MemoryUserOp takes a lot of space and will call to the UserOperationLib at least twice.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This copy is an internal optimization of EntryPoint. we might even remove copying some fields if we find they are not needed (e.g. used exactly once)
UserOperationLib is for general-use functions, that are expected to be used even outside the EntryPoint itself.

mUserOp.nonce = userOp.nonce;
mUserOp.callGasLimit = userOp.callGasLimit;
mUserOp.verificationGasLimit = userOp.verificationGasLimit;
(mUserOp.verificationGasLimit, mUserOp.callGasLimit) = UserOperationLib.unpackAccountGasLimits(userOp.accountGasLimits);
mUserOp.preVerificationGas = userOp.preVerificationGas;
mUserOp.maxFeePerGas = userOp.maxFeePerGas;
mUserOp.maxPriorityFeePerGas = userOp.maxPriorityFeePerGas;
Expand All @@ -325,8 +329,12 @@ contract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard,
"AA93 invalid paymasterAndData"
);
mUserOp.paymaster = address(bytes20(paymasterAndData[:20]));
mUserOp.paymasterVerificationGasLimit = uint128(bytes16(paymasterAndData[20:36]));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. use decode helper
  2. need to check if need all those in mUserOp

mUserOp.paymasterPostOpGasLimit = uint128(bytes16(paymasterAndData[36:52]));
} else {
mUserOp.paymaster = address(0);
mUserOp.paymasterVerificationGasLimit = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solidity structs are pre-initialized to all-zeros.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Except when one does crazy stuff like recycling memory by using the free-pointer back - which we do :) So we can't assume zeros anywhere.

Copy link
Contributor

@drortirosh drortirosh Jan 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we can assume zeros
all storage variables in solidity are initialized to zero - either "stack" or memory variables (structs and arrays).
(there are Yul injected functions "allocate_and_zero_memory..." for that)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The paymaster initialization to address(0) was there, I only added the other fields. Do you want to remove all of them?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we can assume zeros all storage variables in solidity are initialized to zero - either "stack" or memory variables (structs and arrays). (there are Yul injected functions "allocate_and_zero_memory..." for that)

Interesting, I wonder why they do that. Solidity always allocates new memory (containing zeros) so why do they need to explicitly write zeros? (We do, due to our asm code, but normal solidity doesn't)

mUserOp.paymasterPostOpGasLimit = 0;
}
}

Expand All @@ -338,12 +346,10 @@ contract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard,
MemoryUserOp memory mUserOp
) internal pure returns (uint256 requiredPrefund) {
unchecked {
// When using a Paymaster, the verificationGasLimit is used also to as a limit for the postOp call.
// Our security model might call postOp eventually twice.
uint256 mul = mUserOp.paymaster != address(0) ? 2 : 1;
uint256 requiredGas = mUserOp.callGasLimit +
mUserOp.verificationGasLimit *
mul +
uint256 requiredGas = mUserOp.verificationGasLimit +
mUserOp.callGasLimit +
mUserOp.paymasterVerificationGasLimit +
mUserOp.paymasterPostOpGasLimit +
mUserOp.preVerificationGas;

requiredPrefund = requiredGas * mUserOp.maxFeePerGas;
Expand Down Expand Up @@ -472,13 +478,12 @@ contract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard,
) internal returns (bytes memory context, uint256 validationData) {
unchecked {
MemoryUserOp memory mUserOp = opInfo.mUserOp;
// TODO: Do we actually need that still?
uint256 verificationGasLimit = mUserOp.verificationGasLimit;
shahafn marked this conversation as resolved.
Show resolved Hide resolved
require(
verificationGasLimit > gasUsedByValidateAccountPrepayment,
"AA41 too little verificationGas"
);
uint256 gas = verificationGasLimit -
gasUsedByValidateAccountPrepayment;

address paymaster = mUserOp.paymaster;
DepositInfo storage paymasterInfo = deposits[paymaster];
Expand All @@ -488,7 +493,7 @@ contract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard,
}
paymasterInfo.deposit = uint112(deposit - requiredPreFund);
try
IPaymaster(paymaster).validatePaymasterUserOp{gas: gas}(
IPaymaster(paymaster).validatePaymasterUserOp{gas: mUserOp.paymasterVerificationGasLimit}(
shahafn marked this conversation as resolved.
Show resolved Hide resolved
op,
opInfo.userOpHash,
requiredPreFund
Expand Down Expand Up @@ -584,6 +589,8 @@ contract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard,
uint256 maxGasValues = mUserOp.preVerificationGas |
mUserOp.verificationGasLimit |
mUserOp.callGasLimit |
mUserOp.paymasterVerificationGasLimit |
mUserOp.paymasterPostOpGasLimit |
userOp.maxFeePerGas |
userOp.maxPriorityFeePerGas;
require(maxGasValues <= type(uint120).max, "AA94 gas values overflow");
Expand Down Expand Up @@ -621,7 +628,7 @@ contract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard,
unchecked {
uint256 gasUsed = preGas - gasleft();

if (userOp.verificationGasLimit < gasUsed) {
if (mUserOp.verificationGasLimit + mUserOp.paymasterVerificationGasLimit < gasUsed) {
revert FailedOp(opIndex, "AA40 over verificationGasLimit");
}
outOpInfo.prefund = requiredPreFund;
Expand Down Expand Up @@ -662,7 +669,7 @@ contract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard,
actualGasCost = actualGas * gasPrice;
if (mode != IPaymaster.PostOpMode.postOpReverted) {
IPaymaster(paymaster).postOp{
gas: mUserOp.verificationGasLimit
gas: mUserOp.paymasterPostOpGasLimit
}(mode, context, actualGasCost);
}
}
Expand Down
17 changes: 14 additions & 3 deletions contracts/core/UserOperationLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,7 @@ library UserOperationLib {
uint256 nonce = userOp.nonce;
bytes32 hashInitCode = calldataKeccak(userOp.initCode);
bytes32 hashCallData = calldataKeccak(userOp.callData);
uint256 callGasLimit = userOp.callGasLimit;
uint256 verificationGasLimit = userOp.verificationGasLimit;
bytes32 accountGasLimits = userOp.accountGasLimits;
uint256 preVerificationGas = userOp.preVerificationGas;
uint256 maxFeePerGas = userOp.maxFeePerGas;
uint256 maxPriorityFeePerGas = userOp.maxPriorityFeePerGas;
Expand All @@ -65,12 +64,24 @@ library UserOperationLib {
return abi.encode(
sender, nonce,
hashInitCode, hashCallData,
callGasLimit, verificationGasLimit, preVerificationGas,
accountGasLimits, preVerificationGas,
maxFeePerGas, maxPriorityFeePerGas,
hashPaymasterAndData
);
}

function unpackAccountGasLimits(
bytes32 accountGasLimits
) internal pure returns(uint128 validationGasLimit, uint128 callGasLimit) {
return (uint128(bytes16(accountGasLimits)), uint128(uint256(accountGasLimits)));
}

function unpackPaymasterStaticFields(
shahafn marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we ever decode the paymaster itself, only paymasterGaslimits
(the reason is that this method is expected to be used from within validatePaymasterUserOp itself)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do decode it..

bytes calldata paymasterAndData
) internal pure returns(address paymaster, uint128 validationGasLimit, uint128 postOp) {
return (address(bytes20(paymasterAndData[:20])), uint128(bytes16(paymasterAndData[20:36])), uint128(bytes16(paymasterAndData[36:52])));
shahafn marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Hash the user operation data.
* @param userOp - The user operation data.
Expand Down
8 changes: 3 additions & 5 deletions contracts/interfaces/UserOperation.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@ pragma solidity ^0.8.12;
* @param nonce - Unique value the sender uses to verify it is not a replay.
* @param initCode - If set, the account contract will be created by this constructor/
* @param callData - The method call to execute on this account.
* @param callGasLimit - The gas limit passed to the callData method call.
* @param verificationGasLimit - Gas used for validateUserOp and validatePaymasterUserOp.
* @param accountGasLimits - Packed gas limits for validateUserOp and gas limit passed to the callData method call.
* @param preVerificationGas - Gas not calculated by the handleOps method, but added to the gas paid.
* Covers batch overhead.
* @param maxFeePerGas - Same as EIP-1559 gas parameter.
* @param maxPriorityFeePerGas - Same as EIP-1559 gas parameter.
* @param paymasterAndData - If set, this field holds the paymaster address and paymaster-specific data.
* @param paymasterAndData - If set, this field holds the paymaster address, verification gas limit, postOp gas limit and paymaster-specific extra data
* The paymaster will pay for the transaction instead of the sender.
* @param signature - Sender-verified signature over the entire request, the EntryPoint address and the chain ID.
*/
shahafn marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -22,8 +21,7 @@ struct UserOperation {
uint256 nonce;
bytes initCode;
bytes callData;
uint256 callGasLimit;
uint256 verificationGasLimit;
bytes32 accountGasLimits;
uint256 preVerificationGas;
uint256 maxFeePerGas;
uint256 maxPriorityFeePerGas;
Expand Down
2 changes: 1 addition & 1 deletion contracts/samples/DepositPaymaster.sol
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ contract DepositPaymaster is BasePaymaster {

(userOpHash);
// verificationGasLimit is dual-purposed, as gas limit for postOp. make sure it is high enough
require(userOp.verificationGasLimit > COST_OF_POST, "DepositPaymaster: gas too low for postOp");
require(uint128(bytes16(userOp.paymasterAndData[36:52])) > COST_OF_POST, "DepositPaymaster: gas too low for postOp");
shahafn marked this conversation as resolved.
Show resolved Hide resolved

bytes calldata paymasterAndData = userOp.paymasterAndData;
require(paymasterAndData.length == 20+20, "DepositPaymaster: paymasterAndData must specify token");
Expand Down
3 changes: 2 additions & 1 deletion contracts/samples/LegacyTokenPaymaster.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pragma solidity ^0.8.12;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "../core/BasePaymaster.sol";
import "../core/UserOperationLib.sol";

/**
* A sample paymaster that defines itself as a token to pay for gas.
Expand Down Expand Up @@ -75,7 +76,7 @@ contract LegacyTokenPaymaster is BasePaymaster, ERC20 {

// verificationGasLimit is dual-purposed, as gas limit for postOp. make sure it is high enough
// make sure that verificationGasLimit is high enough to handle postOp
require(userOp.verificationGasLimit > COST_OF_POST, "TokenPaymaster: gas too low for postOp");
require(uint128(bytes16(userOp.paymasterAndData[36:52])) > COST_OF_POST, "TokenPaymaster: gas too low for postOp");

if (userOp.initCode.length != 0) {
_validateConstructor(userOp);
Expand Down
4 changes: 2 additions & 2 deletions contracts/samples/TokenPaymaster.sol
Original file line number Diff line number Diff line change
Expand Up @@ -123,15 +123,15 @@ contract TokenPaymaster is BasePaymaster, UniswapHelper, OracleHelper {
override
returns (bytes memory context, uint256 validationResult) {unchecked {
uint256 priceMarkup = tokenPaymasterConfig.priceMarkup;
uint256 paymasterAndDataLength = userOp.paymasterAndData.length - 20;
uint256 paymasterAndDataLength = userOp.paymasterAndData.length - 52;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need to define these as constants, in UserOpLib. its not good to have so many explicit numerics spread in our code.
e.g.
PAYMASTER_GASLIMIT_OFFSET (offset of (paymasterGasLimit,paymasterPostOpGasLimit))
PAYMASTER_DATA_OFFSET (offset of "rest of paymaster data")

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

require(paymasterAndDataLength == 0 || paymasterAndDataLength == 32,
"TPM: invalid data length"
);
uint256 preChargeNative = requiredPreFund + (tokenPaymasterConfig.refundPostopCost * userOp.maxFeePerGas);
// note: as price is in ether-per-token and we want more tokens increasing it means dividing it by markup
uint256 cachedPriceWithMarkup = cachedPrice * PRICE_DENOMINATOR / priceMarkup;
if (paymasterAndDataLength == 32) {
uint256 clientSuppliedPrice = uint256(bytes32(userOp.paymasterAndData[20 : 52]));
uint256 clientSuppliedPrice = uint256(bytes32(userOp.paymasterAndData[52 : 84]));
if (clientSuppliedPrice < cachedPriceWithMarkup) {
// note: smaller number means 'more ether per token'
cachedPriceWithMarkup = clientSuppliedPrice;
Expand Down
8 changes: 4 additions & 4 deletions contracts/samples/VerifyingPaymaster.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ contract VerifyingPaymaster is BasePaymaster {

address public immutable verifyingSigner;

uint256 private constant VALID_TIMESTAMP_OFFSET = 20;
uint256 private constant VALID_TIMESTAMP_OFFSET = 52;
shahafn marked this conversation as resolved.
Show resolved Hide resolved

uint256 private constant SIGNATURE_OFFSET = 84;
uint256 private constant SIGNATURE_OFFSET = 116;

constructor(IEntryPoint _entryPoint, address _verifyingSigner) BasePaymaster(_entryPoint) {
verifyingSigner = _verifyingSigner;
Expand All @@ -50,8 +50,8 @@ contract VerifyingPaymaster is BasePaymaster {
userOp.nonce,
keccak256(userOp.initCode),
keccak256(userOp.callData),
userOp.callGasLimit,
userOp.verificationGasLimit,
userOp.accountGasLimits,
uint256(bytes32(userOp.paymasterAndData[20:52])),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

afaik, bytes32 is enough (bytes32(userOp.paymasterAndData[PAYMASTER_GASLIMT_OFFSET]))

userOp.preVerificationGas,
userOp.maxFeePerGas,
userOp.maxPriorityFeePerGas,
Expand Down
3 changes: 1 addition & 2 deletions contracts/samples/bls/BLSSignatureAggregator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,7 @@ contract BLSSignatureAggregator is IAggregator {
userOp.nonce,
keccak256(userOp.initCode),
keccak256(userOp.callData),
userOp.callGasLimit,
userOp.verificationGasLimit,
userOp.accountGasLimits,
userOp.preVerificationGas,
userOp.maxFeePerGas,
userOp.maxPriorityFeePerGas,
Expand Down
6 changes: 3 additions & 3 deletions contracts/samples/gnosis/EIP4337Manager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,8 @@ contract EIP4337Manager is IAccount, GnosisSafeStorage, Executor {

/**
* Validate this gnosisSafe is callable through the EntryPoint.
* the test is might be incomplete: we check that we reach our validateUserOp and fail on signature.
* we don't test full transaction
* the test might be incomplete: we check that we reach our validateUserOp and fail on signature.
* we don't test a full transaction
*/
function validateEip4337(GnosisSafe safe, EIP4337Manager manager) public {

Expand All @@ -163,7 +163,7 @@ contract EIP4337Manager is IAccount, GnosisSafeStorage, Executor {
sig[2] = bytes1(uint8(1));
sig[35] = bytes1(uint8(1));
uint256 nonce = uint256(IEntryPoint(manager.entryPoint()).getNonce(address(safe), 0));
UserOperation memory userOp = UserOperation(address(safe), nonce, "", "", 0, 1000000, 0, 0, 0, "", sig);
UserOperation memory userOp = UserOperation(address(safe), nonce, "", "", bytes32(bytes16(uint128(0x0f4240))), 0, 0, 0, "", sig);
shahafn marked this conversation as resolved.
Show resolved Hide resolved
UserOperation[] memory userOps = new UserOperation[](1);
userOps[0] = userOp;
IEntryPoint _entryPoint = IEntryPoint(payable(manager.entryPoint()));
Expand Down
6 changes: 5 additions & 1 deletion contracts/test/MaliciousAccount.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pragma solidity ^0.8.12;
import "../interfaces/IAccount.sol";
import "../interfaces/IEntryPoint.sol";
import "../core/UserOperationLib.sol";

contract MaliciousAccount is IAccount {
IEntryPoint private ep;
Expand All @@ -13,7 +14,10 @@ contract MaliciousAccount is IAccount {
ep.depositTo{value : missingAccountFunds}(address(this));
// Now calculate basefee per EntryPoint.getUserOpGasPrice() and compare it to the basefe we pass off-chain in the signature
uint256 externalBaseFee = abi.decode(userOp.signature, (uint256));
uint256 requiredGas = userOp.callGasLimit + userOp.verificationGasLimit + userOp.preVerificationGas;
(uint128 verificationGasLimit, uint128 callGasLimit) = UserOperationLib.unpackAccountGasLimits(userOp.accountGasLimits);
uint256 requiredGas = verificationGasLimit +
callGasLimit +
userOp.preVerificationGas;
uint256 gasPrice = missingAccountFunds / requiredGas;
uint256 basefee = gasPrice - userOp.maxPriorityFeePerGas;
require (basefee == externalBaseFee, "Revert after first validation");
Expand Down
2 changes: 1 addition & 1 deletion contracts/test/TestExpirePaymaster.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ contract TestExpirePaymaster is BasePaymaster {
internal virtual override view
returns (bytes memory context, uint256 validationData) {
(userOp, userOpHash, maxCost);
(uint48 validAfter, uint48 validUntil) = abi.decode(userOp.paymasterAndData[20 :], (uint48, uint48));
(uint48 validAfter, uint48 validUntil) = abi.decode(userOp.paymasterAndData[52 :], (uint48, uint48));
validationData = _packValidationData(false, validUntil, validAfter);
context = "";
}
Expand Down
12 changes: 6 additions & 6 deletions gascalc/GasChecker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ import {
} from '../typechain'
import { BigNumberish, Wallet } from 'ethers'
import hre from 'hardhat'
import { fillAndSign, fillUserOp, signUserOp } from '../test/UserOp'
import { fillSignAndPack, fillUserOp, packUserOp, signUserOp } from '../test/UserOp'
import { TransactionReceipt } from '@ethersproject/abstract-provider'
import { table, TableUserConfig } from 'table'
import { Create2Factory } from '../src/Create2Factory'
import * as fs from 'fs'
import { SimpleAccountInterface } from '../typechain/contracts/samples/SimpleAccount'
import { UserOperation } from '../test/UserOperation'
import { PackedUserOperation } from '../test/UserOperation'

const gasCheckerLogFile = './reports/gas-checker.txt'

Expand Down Expand Up @@ -130,7 +130,7 @@ export class GasChecker {
console.log('factaddr', factoryAddress)
const fact = SimpleAccountFactory__factory.connect(factoryAddress, ethersSigner)
// create accounts
const creationOps: UserOperation[] = []
const creationOps: PackedUserOperation[] = []
for (const n of range(count)) {
const salt = n
// const initCode = this.accountInitCode(fact, salt)
Expand All @@ -149,7 +149,7 @@ export class GasChecker {
preVerificationGas: 1,
maxFeePerGas: 0
}), this.accountOwner, this.entryPoint().address, await provider.getNetwork().then(net => net.chainId))
creationOps.push(op)
creationOps.push(packUserOp(op))
this.createdAccounts.add(addr)
}

Expand Down Expand Up @@ -223,14 +223,14 @@ export class GasChecker {
}
// console.debug('== account est=', accountEst.toString())
accountEst = est.accountEst
const op = await fillAndSign({
const op = await fillSignAndPack({
sender: account,
callData: accountExecFromEntryPoint,
maxPriorityFeePerGas: info.gasPrice,
maxFeePerGas: info.gasPrice,
callGasLimit: accountEst,
verificationGasLimit: 1000000,
paymasterAndData: paymaster,
paymaster: paymaster,
preVerificationGas: 1
}, accountOwner, GasCheckCollector.inst.entryPoint)
// const packed = packUserOp(op, false)
Expand Down
Loading
Loading