Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 7 additions & 1 deletion crates/contracts/contracts/v0_8/foundry.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
"../../../../test/spec-tests/v0_7/bundler-spec-tests": {
"rev": "e641dcfd33ffd965ef90397a44f71eda4d90c6a7"
},
"../../../../test/spec-tests/v0_8/bundler-spec-tests": {
"rev": "7acb8bafec75be86a4be7e0336daf942a09c4660"
},
"../../../bindings/fastlz/fastlz": {
"rev": "344eb4025f9ae866ebf7a2ec48850f7113a97a42"
},
Expand All @@ -23,9 +26,12 @@
"../v0_7/lib/openzeppelin-contracts": {
"rev": "dbb6104ce834628e473d2173bbc9d47f81a9eec3"
},
"../v0_9/lib/account-abstraction": {
"rev": "b36a1ed52ae00da6f8a4c8d50181e2877e4fa410"
},
"lib/account-abstraction": {
"branch": {
"name": "releases/v0.6",
"name": "releases/v0.8",
"rev": "4cbc06072cdc19fd60f285c5997f4f7f57a588de"
}
}
Expand Down
5 changes: 3 additions & 2 deletions crates/contracts/contracts/v0_8/foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ out = 'out'
libs = ['lib']
test = 'test'
cache_path = 'cache'
solc_version = '0.8.28'
solc_version = '0.8.28+commit.7893614a'
optimizer = true
optimizer_runs = 200
optimizer_runs = 1000000
evm_version = 'cancun'
via_ir = true

remappings = [
'@account-abstraction=lib/account-abstraction/contracts/',
Expand Down
68 changes: 52 additions & 16 deletions crates/contracts/contracts/v0_8/src/EntryPointSimulations.sol
Original file line number Diff line number Diff line change
@@ -1,28 +1,26 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.23;
pragma solidity ^0.8.28;

/* solhint-disable avoid-low-level-calls */
/* solhint-disable no-inline-assembly */

// Adapted from https://github.com/eth-infinitism/account-abstraction/blob/v0.7.0/contracts/core/EntryPointSimulations.sol

import "@account-abstraction/core/EntryPoint.sol";
import "@account-abstraction/interfaces/IEntryPointSimulations.sol";

// Adapted from https://github.com/eth-infinitism/account-abstraction/blob/v0.7.0/contracts/core/EntryPointSimulations.sol

/*
* This contract inherits the EntryPoint and extends it with the view-only methods that are executed by
* the bundler in order to check UserOperation validity and estimate its gas consumption.
* This contract should never be deployed on-chain and is only used as a parameter for the "eth_call" request.
*/
contract EntryPointSimulations is EntryPoint, IEntryPointSimulations {
// solhint-disable-next-line var-name-mixedcase
AggregatorStakeInfo private NOT_AGGREGATED =
AggregatorStakeInfo(address(0), StakeInfo(0, 0));

SenderCreator private _senderCreator;

bytes32 private __domainSeparatorV4;

function initSenderCreator() internal virtual {
//this is the address of the first contract created with CREATE by this address.
// This is the address of the first contract created with CREATE by this address.
address createdObj = address(
uint160(
uint256(
Expand All @@ -33,12 +31,14 @@ contract EntryPointSimulations is EntryPoint, IEntryPointSimulations {
)
);
_senderCreator = SenderCreator(createdObj);

_initDomainSeparator();
}

/// @inheritdoc IEntryPoint
function senderCreator()
public
view
virtual
override(EntryPoint, IEntryPoint)
returns (ISenderCreator)
{
Expand All @@ -52,7 +52,7 @@ contract EntryPointSimulations is EntryPoint, IEntryPointSimulations {
* it as entrypoint, since the simulation functions don't check the signatures
*/
constructor() {
require(block.number < 100, "should not be deployed");
require(block.number < 1000, "should not be deployed");
}

/// @inheritdoc IEntryPointSimulations
Expand Down Expand Up @@ -88,7 +88,7 @@ contract EntryPointSimulations is EntryPoint, IEntryPointSimulations {
_getMemoryBytesFromOffset(outOpInfo.contextOffset)
);

AggregatorStakeInfo memory aggregatorInfo = NOT_AGGREGATED;
AggregatorStakeInfo memory aggregatorInfo; // = NOT_AGGREGATED;
if (
uint160(aggregator) != SIG_VALIDATION_SUCCESS &&
uint160(aggregator) != SIG_VALIDATION_FAILED
Expand Down Expand Up @@ -179,11 +179,11 @@ contract EntryPointSimulations is EntryPoint, IEntryPointSimulations {
function _simulationOnlyValidations(
PackedUserOperation calldata userOp
) internal {
//initialize senderCreator(). we can't rely on constructor
// Initialize senderCreator(). we can't rely on constructor
initSenderCreator();

try
this._validateSenderAndPaymaster(
this.validateSenderAndPaymaster(
userOp.initCode,
userOp.sender,
userOp.paymasterAndData
Expand All @@ -197,13 +197,13 @@ contract EntryPointSimulations is EntryPoint, IEntryPointSimulations {
}

/**
* Called only during simulation.
* Called only during simulation by the EntryPointSimulation contract itself and is not meant to be called by external contracts.
* This function always reverts to prevent warm/cold storage differentiation in simulation vs execution.
* @param initCode - The smart account constructor code.
* @param sender - The sender address.
* @param paymasterAndData - The paymaster address (followed by other params, ignored by this method)
*/
function _validateSenderAndPaymaster(
function validateSenderAndPaymaster(
bytes calldata initCode,
address sender,
bytes calldata paymasterAndData
Expand All @@ -223,7 +223,7 @@ contract EntryPointSimulations is EntryPoint, IEntryPointSimulations {
revert("");
}

//make sure depositTo cost is more than normal EntryPoint's cost,
// Make sure depositTo cost is more than normal EntryPoint's cost,
// to mitigate DoS vector on the bundler
// empiric test showed that without this wrapper, simulation depositTo costs less..
function depositTo(
Expand All @@ -239,4 +239,40 @@ contract EntryPointSimulations is EntryPoint, IEntryPointSimulations {
StakeManager.depositTo(account);
}
}

// Copied from EIP712.sol
bytes32 private constant TYPE_HASH =
keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
);

function __buildDomainSeparator() private view returns (bytes32) {
bytes32 _hashedName = keccak256(bytes(DOMAIN_NAME));
bytes32 _hashedVersion = keccak256(bytes(DOMAIN_VERSION));
return
keccak256(
abi.encode(
TYPE_HASH,
_hashedName,
_hashedVersion,
block.chainid,
address(this)
)
);
}

// Can't rely on "immutable" (constructor-initialized) variables" in simulation
function _initDomainSeparator() internal {
__domainSeparatorV4 = __buildDomainSeparator();
}

function getDomainSeparatorV4() public view override returns (bytes32) {
return __domainSeparatorV4;
}

function supportsInterface(
bytes4
) public view virtual override returns (bool) {
return false;
}
}
4 changes: 2 additions & 2 deletions crates/contracts/contracts/v0_9/foundry.lock
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@
},
"lib/account-abstraction": {
"branch": {
"name": "releases/v0.6",
"rev": "4cbc06072cdc19fd60f285c5997f4f7f57a588de"
"name": "releases/v0.9",
"rev": "b36a1ed52ae00da6f8a4c8d50181e2877e4fa410"
}
}
}
5 changes: 3 additions & 2 deletions crates/contracts/contracts/v0_9/foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ out = 'out'
libs = ['lib']
test = 'test'
cache_path = 'cache'
solc_version = '0.8.28'
solc_version = '0.8.28+commit.7893614a'
optimizer = true
optimizer_runs = 200
optimizer_runs = 1000000
evm_version = 'cancun'
via_ir = true

remappings = [
'@account-abstraction=lib/account-abstraction/contracts/',
Expand Down
88 changes: 64 additions & 24 deletions crates/contracts/contracts/v0_9/src/EntryPointSimulations.sol
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.23;
pragma solidity ^0.8.28;

/* solhint-disable avoid-low-level-calls */
/* solhint-disable no-inline-assembly */

// Adapted from https://github.com/eth-infinitism/account-abstraction/blob/v0.7.0/contracts/core/EntryPointSimulations.sol

import "@account-abstraction/core/EntryPoint.sol";
import "@account-abstraction/interfaces/IEntryPointSimulations.sol";

// Adapted from https://github.com/eth-infinitism/account-abstraction/blob/v0.7.0/contracts/core/EntryPointSimulations.sol

/*
* This contract inherits the EntryPoint and extends it with the view-only methods that are executed by
* the bundler in order to check UserOperation validity and estimate its gas consumption.
* This contract should never be deployed on-chain and is only used as a parameter for the "eth_call" request.
*/
contract EntryPointSimulations is EntryPoint, IEntryPointSimulations {
// solhint-disable-next-line var-name-mixedcase
AggregatorStakeInfo private NOT_AGGREGATED =
AggregatorStakeInfo(address(0), StakeInfo(0, 0));
error NotImplemented();
error PaymasterNotDeployed(address paymaster);

SenderCreator private _senderCreator;

bytes32 private __domainSeparatorV4;

function initSenderCreator() internal virtual {
//this is the address of the first contract created with CREATE by this address.
// This is the address of the first contract created with CREATE by this address.
address createdObj = address(
uint160(
uint256(
Expand All @@ -33,12 +34,14 @@ contract EntryPointSimulations is EntryPoint, IEntryPointSimulations {
)
);
_senderCreator = SenderCreator(createdObj);

_initDomainSeparator();
}

/// @inheritdoc IEntryPoint
function senderCreator()
public
view
virtual
override(EntryPoint, IEntryPoint)
returns (ISenderCreator)
{
Expand All @@ -47,14 +50,6 @@ contract EntryPointSimulations is EntryPoint, IEntryPointSimulations {
return _senderCreator;
}

/**
* simulation contract should not be deployed, and specifically, accounts should not trust
* it as entrypoint, since the simulation functions don't check the signatures
*/
constructor() {
require(block.number < 100, "should not be deployed");
}

/// @inheritdoc IEntryPointSimulations
function simulateValidation(
PackedUserOperation calldata userOp
Expand Down Expand Up @@ -88,7 +83,7 @@ contract EntryPointSimulations is EntryPoint, IEntryPointSimulations {
_getMemoryBytesFromOffset(outOpInfo.contextOffset)
);

AggregatorStakeInfo memory aggregatorInfo = NOT_AGGREGATED;
AggregatorStakeInfo memory aggregatorInfo; // = NOT_AGGREGATED;
if (
uint160(aggregator) != SIG_VALIDATION_SUCCESS &&
uint160(aggregator) != SIG_VALIDATION_FAILED
Expand Down Expand Up @@ -179,11 +174,11 @@ contract EntryPointSimulations is EntryPoint, IEntryPointSimulations {
function _simulationOnlyValidations(
PackedUserOperation calldata userOp
) internal {
//initialize senderCreator(). we can't rely on constructor
// Initialize senderCreator(). we can't rely on constructor
initSenderCreator();

try
this._validateSenderAndPaymaster(
this.validateSenderAndPaymaster(
userOp.initCode,
userOp.sender,
userOp.paymasterAndData
Expand All @@ -197,33 +192,34 @@ contract EntryPointSimulations is EntryPoint, IEntryPointSimulations {
}

/**
* Called only during simulation.
* Called only during simulation by the EntryPointSimulation contract itself and is not meant to be called by external contracts.
* This function always reverts to prevent warm/cold storage differentiation in simulation vs execution.
* @param initCode - The smart account constructor code.
* @param sender - The sender address.
* @param paymasterAndData - The paymaster address (followed by other params, ignored by this method)
*/
function _validateSenderAndPaymaster(
function validateSenderAndPaymaster(
bytes calldata initCode,
address sender,
bytes calldata paymasterAndData
) external view {
if (initCode.length == 0 && sender.code.length == 0) {
// it would revert anyway. but give a meaningful message
revert("AA20 account not deployed");
revert FailedOp(0, "AA20 account not deployed");
}
if (paymasterAndData.length >= 20) {
address paymaster = address(bytes20(paymasterAndData[0:20]));
if (paymaster.code.length == 0) {
// It would revert anyway. but give a meaningful message.
revert("AA30 paymaster not deployed");
revert PaymasterNotDeployed(paymaster);
}
}
// always revert
// solhint-disable-next-line gas-custom-errors
revert("");
}

//make sure depositTo cost is more than normal EntryPoint's cost,
// Make sure depositTo cost is more than normal EntryPoint's cost,
// to mitigate DoS vector on the bundler
// empiric test showed that without this wrapper, simulation depositTo costs less..
function depositTo(
Expand All @@ -239,4 +235,48 @@ contract EntryPointSimulations is EntryPoint, IEntryPointSimulations {
StakeManager.depositTo(account);
}
}

// Copied from EIP712.sol
bytes32 private constant TYPE_HASH =
// solhint-disable-next-line gas-small-strings
keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
);

function __buildDomainSeparator() private view returns (bytes32) {
bytes32 _hashedName = keccak256(bytes(DOMAIN_NAME));
bytes32 _hashedVersion = keccak256(bytes(DOMAIN_VERSION));
return
keccak256(
abi.encode(
TYPE_HASH,
_hashedName,
_hashedVersion,
block.chainid,
address(this)
)
);
}

// Can't rely on "immutable" (constructor-initialized) variables" in simulation
function _initDomainSeparator() internal {
__domainSeparatorV4 = __buildDomainSeparator();
}

function getDomainSeparatorV4() public view override returns (bytes32) {
return __domainSeparatorV4;
}

function supportsInterface(
bytes4
) public view virtual override returns (bool) {
return false;
}

function handleAggregatedOps(
UserOpsPerAggregator[] calldata,
address payable
) external pure override(EntryPoint, IEntryPoint) {
revert NotImplemented();
}
}
Loading
Loading