├── EIP4337TestCase ├── cache │ └── solidity-files-cache.json ├── contracts │ ├── core │ │ ├── BaseAccount.sol │ │ ├── BasePaymaster.sol │ │ ├── EntryPoint.sol │ │ ├── Helpers.sol │ │ ├── NonceManager.sol │ │ ├── SenderCreator.sol │ │ └── StakeManager.sol │ ├── interfaces │ │ ├── IAccount.sol │ │ ├── IAggregator.sol │ │ ├── IEntryPoint.sol │ │ ├── INonceManager.sol │ │ ├── IPaymaster.sol │ │ ├── IStakeManager.sol │ │ └── UserOperation.sol │ ├── package.json │ ├── samples │ │ ├── LegacyTokenPaymaster.sol │ │ ├── SimpleAccount.sol │ │ ├── SimpleAccountFactory.sol │ │ └── callback │ │ │ └── TokenCallbackHandler.sol │ └── utils │ │ └── Exec.sol ├── foundry.toml ├── lib │ └── forge-std │ │ ├── LICENSE-APACHE │ │ ├── LICENSE-MIT │ │ ├── README.md │ │ ├── foundry.toml │ │ ├── lib │ │ └── ds-test │ │ │ ├── LICENSE │ │ │ ├── Makefile │ │ │ ├── default.nix │ │ │ ├── demo │ │ │ └── demo.sol │ │ │ ├── package.json │ │ │ └── src │ │ │ ├── test.sol │ │ │ └── test.t.sol │ │ ├── package.json │ │ ├── src │ │ ├── Base.sol │ │ ├── Script.sol │ │ ├── StdAssertions.sol │ │ ├── StdChains.sol │ │ ├── StdCheats.sol │ │ ├── StdError.sol │ │ ├── StdInvariant.sol │ │ ├── StdJson.sol │ │ ├── StdMath.sol │ │ ├── StdStorage.sol │ │ ├── StdStyle.sol │ │ ├── StdUtils.sol │ │ ├── Test.sol │ │ ├── Vm.sol │ │ ├── console.sol │ │ ├── console2.sol │ │ ├── interfaces │ │ │ ├── IERC20.sol │ │ │ └── IMulticall3.sol │ │ └── safeconsole.sol │ │ └── test │ │ ├── StdAssertions.t.sol │ │ ├── StdChains.t.sol │ │ ├── StdCheats.t.sol │ │ ├── StdError.t.sol │ │ ├── StdMath.t.sol │ │ ├── StdStorage.t.sol │ │ ├── StdStyle.t.sol │ │ ├── StdUtils.t.sol │ │ ├── compilation │ │ ├── CompilationScript.sol │ │ ├── CompilationScriptBase.sol │ │ ├── CompilationTest.sol │ │ └── CompilationTestBase.sol │ │ └── fixtures │ │ └── broadcast.log.json ├── node_modules.zip ├── out │ ├── BaseTest.sol │ │ └── BaseTest.json │ ├── ERC20.sol │ │ └── ERC20.json │ ├── IAccount.sol │ │ └── IAccount.json │ ├── IAggregator.sol │ │ └── IAggregator.json │ ├── IBeacon.sol │ │ └── IBeacon.json │ ├── IERC1155Receiver.sol │ │ └── IERC1155Receiver.json │ ├── IERC20.sol │ │ └── IERC20.json │ ├── IERC721Receiver.sol │ │ └── IERC721Receiver.json │ ├── IERC777Recipient.sol │ │ └── IERC777Recipient.json │ ├── IEntryPoint.sol │ │ └── IEntryPoint.json │ ├── IMulticall3.sol │ │ └── IMulticall3.json │ ├── IPaymaster.sol │ │ └── IPaymaster.json │ ├── IStakeManager.sol │ │ └── IStakeManager.json │ ├── IUniswapV3SwapCallback.sol │ │ └── IUniswapV3SwapCallback.json │ ├── Initializable.sol │ │ └── Initializable.json │ ├── OracleHelper.sol │ │ └── OracleHelper.json │ ├── Ownable.sol │ │ └── Ownable.json │ ├── ReentrancyGuard.sol │ │ └── ReentrancyGuard.json │ ├── SafeERC20.sol │ │ └── SafeERC20.json │ ├── SimpleAccountFactory.sol │ │ └── SimpleAccountFactory.json │ ├── StdInvariant.sol │ │ └── StdInvariant.json │ ├── StdJson.sol │ │ └── stdJson.json │ ├── StdStorage.sol │ │ └── stdStorage.json │ ├── TokenCallbackHandler.sol │ │ └── TokenCallbackHandler.json │ ├── VerifyingPaymaster.sol │ │ └── VerifyingPaymaster.json │ ├── Vm.sol │ │ ├── Vm.json │ │ └── VmSafe.json │ ├── draft-IERC1822.sol │ │ └── IERC1822Proxiable.json │ └── draft-IERC20Permit.sol │ │ └── IERC20Permit.json ├── package-lock.json ├── package.json ├── remappings.txt └── test │ ├── BaseTest.sol │ ├── Paymaster.t.sol │ └── Wallet.t.sol ├── README.md └── pic ├── 1.png └── 2.png /EIP4337TestCase/contracts/core/BaseAccount.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity ^0.8.12; 3 | 4 | /* solhint-disable avoid-low-level-calls */ 5 | /* solhint-disable no-empty-blocks */ 6 | 7 | import "../interfaces/IAccount.sol"; 8 | import "../interfaces/IEntryPoint.sol"; 9 | import "./Helpers.sol"; 10 | 11 | /** 12 | * Basic account implementation. 13 | * This contract provides the basic logic for implementing the IAccount interface - validateUserOp 14 | * Specific account implementation should inherit it and provide the account-specific logic. 15 | */ 16 | abstract contract BaseAccount is IAccount { 17 | using UserOperationLib for UserOperation; 18 | 19 | /** 20 | * Return value in case of signature failure, with no time-range. 21 | * Equivalent to _packValidationData(true,0,0). 22 | */ 23 | uint256 internal constant SIG_VALIDATION_FAILED = 1; 24 | 25 | /** 26 | * Return the account nonce. 27 | * This method returns the next sequential nonce. 28 | * For a nonce of a specific key, use `entrypoint.getNonce(account, key)` 29 | */ 30 | function getNonce() public view virtual returns (uint256) { 31 | return entryPoint().getNonce(address(this), 0); 32 | } 33 | 34 | /** 35 | * Return the entryPoint used by this account. 36 | * Subclass should return the current entryPoint used by this account. 37 | */ 38 | function entryPoint() public view virtual returns (IEntryPoint); 39 | 40 | /** 41 | * Validate user's signature and nonce. 42 | * Subclass doesn't need to override this method. Instead, 43 | * it should override the specific internal validation methods. 44 | * @param userOp - The user operation to validate. 45 | * @param userOpHash - The hash of the user operation. 46 | * @param missingAccountFunds - The amount of funds missing from the account 47 | * to pay for the user operation. 48 | */ 49 | function validateUserOp( 50 | UserOperation calldata userOp, 51 | bytes32 userOpHash, 52 | uint256 missingAccountFunds 53 | ) external virtual override returns (uint256 validationData) { 54 | _requireFromEntryPoint(); 55 | validationData = _validateSignature(userOp, userOpHash); 56 | _validateNonce(userOp.nonce); 57 | _payPrefund(missingAccountFunds); 58 | } 59 | 60 | /** 61 | * Ensure the request comes from the known entrypoint. 62 | */ 63 | function _requireFromEntryPoint() internal view virtual { 64 | require( 65 | msg.sender == address(entryPoint()), 66 | "account: not from EntryPoint" 67 | ); 68 | } 69 | 70 | /** 71 | * Validate the signature is valid for this message. 72 | * @param userOp - Validate the userOp.signature field. 73 | * @param userOpHash - Convenient field: the hash of the request, to check the signature against. 74 | * (also hashes the entrypoint and chain id) 75 | * @return validationData - Signature and time-range of this operation. 76 | * <20-byte> sigAuthorizer - 0 for valid signature, 1 to mark signature failure, 77 | * otherwise, an address of an "authorizer" contract. 78 | * <6-byte> validUntil - last timestamp this operation is valid. 0 for "indefinite" 79 | * <6-byte> validAfter - first timestamp this operation is valid 80 | * If the account doesn't use time-range, it is enough to return 81 | * SIG_VALIDATION_FAILED value (1) for signature failure. 82 | * Note that the validation code cannot use block.timestamp (or block.number) directly. 83 | */ 84 | function _validateSignature( 85 | UserOperation calldata userOp, 86 | bytes32 userOpHash 87 | ) internal virtual returns (uint256 validationData); 88 | 89 | /** 90 | * Validate the nonce of the UserOperation. 91 | * This method may validate the nonce requirement of this account. 92 | * e.g. 93 | * To limit the nonce to use sequenced UserOps only (no "out of order" UserOps): 94 | * `require(nonce < type(uint64).max)` 95 | * For a hypothetical account that *requires* the nonce to be out-of-order: 96 | * `require(nonce & type(uint64).max == 0)` 97 | * 98 | * The actual nonce uniqueness is managed by the EntryPoint, and thus no other 99 | * action is needed by the account itself. 100 | * 101 | * @param nonce to validate 102 | * 103 | * solhint-disable-next-line no-empty-blocks 104 | */ 105 | function _validateNonce(uint256 nonce) internal view virtual { 106 | } 107 | 108 | /** 109 | * Sends to the entrypoint (msg.sender) the missing funds for this transaction. 110 | * SubClass MAY override this method for better funds management 111 | * (e.g. send to the entryPoint more than the minimum required, so that in future transactions 112 | * it will not be required to send again). 113 | * @param missingAccountFunds - The minimum value this method should send the entrypoint. 114 | * This value MAY be zero, in case there is enough deposit, 115 | * or the userOp has a paymaster. 116 | */ 117 | function _payPrefund(uint256 missingAccountFunds) internal virtual { 118 | if (missingAccountFunds != 0) { 119 | (bool success, ) = payable(msg.sender).call{ 120 | value: missingAccountFunds, 121 | gas: type(uint256).max 122 | }(""); 123 | (success); 124 | //ignore failure (its EntryPoint's job to verify, not account.) 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /EIP4337TestCase/contracts/core/BasePaymaster.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity ^0.8.12; 3 | 4 | /* solhint-disable reason-string */ 5 | 6 | import "@openzeppelin/contracts/access/Ownable.sol"; 7 | import "../interfaces/IPaymaster.sol"; 8 | import "../interfaces/IEntryPoint.sol"; 9 | import "./Helpers.sol"; 10 | 11 | /** 12 | * Helper class for creating a paymaster. 13 | * provides helper methods for staking. 14 | * Validates that the postOp is called only by the entryPoint. 15 | */ 16 | abstract contract BasePaymaster is IPaymaster, Ownable { 17 | IEntryPoint public immutable entryPoint; 18 | 19 | constructor(IEntryPoint _entryPoint) { 20 | entryPoint = _entryPoint; 21 | } 22 | 23 | /// @inheritdoc IPaymaster 24 | function validatePaymasterUserOp( 25 | UserOperation calldata userOp, 26 | bytes32 userOpHash, 27 | uint256 maxCost 28 | ) external override returns (bytes memory context, uint256 validationData) { 29 | _requireFromEntryPoint(); 30 | return _validatePaymasterUserOp(userOp, userOpHash, maxCost); 31 | } 32 | 33 | /** 34 | * Validate a user operation. 35 | * @param userOp - The user operation. 36 | * @param userOpHash - The hash of the user operation. 37 | * @param maxCost - The maximum cost of the user operation. 38 | */ 39 | function _validatePaymasterUserOp( 40 | UserOperation calldata userOp, 41 | bytes32 userOpHash, 42 | uint256 maxCost 43 | ) internal virtual returns (bytes memory context, uint256 validationData); 44 | 45 | /// @inheritdoc IPaymaster 46 | function postOp( 47 | PostOpMode mode, 48 | bytes calldata context, 49 | uint256 actualGasCost 50 | ) external override { 51 | _requireFromEntryPoint(); 52 | _postOp(mode, context, actualGasCost); 53 | } 54 | 55 | /** 56 | * Post-operation handler. 57 | * (verified to be called only through the entryPoint) 58 | * @dev If subclass returns a non-empty context from validatePaymasterUserOp, 59 | * it must also implement this method. 60 | * @param mode - Enum with the following options: 61 | * opSucceeded - User operation succeeded. 62 | * opReverted - User op reverted. still has to pay for gas. 63 | * postOpReverted - User op succeeded, but caused postOp (in mode=opSucceeded) to revert. 64 | * Now this is the 2nd call, after user's op was deliberately reverted. 65 | * @param context - The context value returned by validatePaymasterUserOp 66 | * @param actualGasCost - Actual gas used so far (without this postOp call). 67 | */ 68 | function _postOp( 69 | PostOpMode mode, 70 | bytes calldata context, 71 | uint256 actualGasCost 72 | ) internal virtual { 73 | (mode, context, actualGasCost); // unused params 74 | // subclass must override this method if validatePaymasterUserOp returns a context 75 | revert("must override"); 76 | } 77 | 78 | /** 79 | * Add a deposit for this paymaster, used for paying for transaction fees. 80 | */ 81 | function deposit() public payable { 82 | entryPoint.depositTo{value: msg.value}(address(this)); 83 | } 84 | 85 | /** 86 | * Withdraw value from the deposit. 87 | * @param withdrawAddress - Target to send to. 88 | * @param amount - Amount to withdraw. 89 | */ 90 | function withdrawTo( 91 | address payable withdrawAddress, 92 | uint256 amount 93 | ) public onlyOwner { 94 | entryPoint.withdrawTo(withdrawAddress, amount); 95 | } 96 | 97 | /** 98 | * Add stake for this paymaster. 99 | * This method can also carry eth value to add to the current stake. 100 | * @param unstakeDelaySec - The unstake delay for this paymaster. Can only be increased. 101 | */ 102 | function addStake(uint32 unstakeDelaySec) external payable onlyOwner { 103 | entryPoint.addStake{value: msg.value}(unstakeDelaySec); 104 | } 105 | 106 | /** 107 | * Return current paymaster's deposit on the entryPoint. 108 | */ 109 | function getDeposit() public view returns (uint256) { 110 | return entryPoint.balanceOf(address(this)); 111 | } 112 | 113 | /** 114 | * Unlock the stake, in order to withdraw it. 115 | * The paymaster can't serve requests once unlocked, until it calls addStake again 116 | */ 117 | function unlockStake() external onlyOwner { 118 | entryPoint.unlockStake(); 119 | } 120 | 121 | /** 122 | * Withdraw the entire paymaster's stake. 123 | * stake must be unlocked first (and then wait for the unstakeDelay to be over) 124 | * @param withdrawAddress - The address to send withdrawn value. 125 | */ 126 | function withdrawStake(address payable withdrawAddress) external onlyOwner { 127 | entryPoint.withdrawStake(withdrawAddress); 128 | } 129 | 130 | /** 131 | * Validate the call is made from a valid entrypoint 132 | */ 133 | function _requireFromEntryPoint() internal virtual { 134 | require(msg.sender == address(entryPoint), "Sender not EntryPoint"); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /EIP4337TestCase/contracts/core/Helpers.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity ^0.8.12; 3 | 4 | /* solhint-disable no-inline-assembly */ 5 | 6 | /** 7 | * Returned data from validateUserOp. 8 | * validateUserOp returns a uint256, with is created by `_packedValidationData` and 9 | * parsed by `_parseValidationData`. 10 | * @param aggregator - address(0) - The account validated the signature by itself. 11 | * address(1) - The account failed to validate the signature. 12 | * otherwise - This is an address of a signature aggregator that must 13 | * be used to validate the signature. 14 | * @param validAfter - This UserOp is valid only after this timestamp. 15 | * @param validaUntil - This UserOp is valid only up to this timestamp. 16 | */ 17 | struct ValidationData { 18 | address aggregator; 19 | uint48 validAfter; 20 | uint48 validUntil; 21 | } 22 | 23 | /** 24 | * Extract sigFailed, validAfter, validUntil. 25 | * Also convert zero validUntil to type(uint48).max. 26 | * @param validationData - The packed validation data. 27 | */ 28 | function _parseValidationData( 29 | uint validationData 30 | ) pure returns (ValidationData memory data) { 31 | address aggregator = address(uint160(validationData)); 32 | uint48 validUntil = uint48(validationData >> 160); 33 | if (validUntil == 0) { 34 | validUntil = type(uint48).max; 35 | } 36 | uint48 validAfter = uint48(validationData >> (48 + 160)); 37 | return ValidationData(aggregator, validAfter, validUntil); 38 | } 39 | 40 | /** 41 | * Intersect account and paymaster ranges. 42 | * @param validationData - The packed validation data of the account. 43 | * @param paymasterValidationData - The packed validation data of the paymaster. 44 | */ 45 | function _intersectTimeRange( 46 | uint256 validationData, 47 | uint256 paymasterValidationData 48 | ) pure returns (ValidationData memory) { 49 | ValidationData memory accountValidationData = _parseValidationData( 50 | validationData 51 | ); 52 | ValidationData memory pmValidationData = _parseValidationData( 53 | paymasterValidationData 54 | ); 55 | address aggregator = accountValidationData.aggregator; 56 | if (aggregator == address(0)) { 57 | aggregator = pmValidationData.aggregator; 58 | } 59 | uint48 validAfter = accountValidationData.validAfter; 60 | uint48 validUntil = accountValidationData.validUntil; 61 | uint48 pmValidAfter = pmValidationData.validAfter; 62 | uint48 pmValidUntil = pmValidationData.validUntil; 63 | 64 | if (validAfter < pmValidAfter) validAfter = pmValidAfter; 65 | if (validUntil > pmValidUntil) validUntil = pmValidUntil; 66 | return ValidationData(aggregator, validAfter, validUntil); 67 | } 68 | 69 | /** 70 | * Helper to pack the return value for validateUserOp. 71 | * @param data - The ValidationData to pack. 72 | */ 73 | function _packValidationData( 74 | ValidationData memory data 75 | ) pure returns (uint256) { 76 | return 77 | uint160(data.aggregator) | 78 | (uint256(data.validUntil) << 160) | 79 | (uint256(data.validAfter) << (160 + 48)); 80 | } 81 | 82 | /** 83 | * Helper to pack the return value for validateUserOp, when not using an aggregator. 84 | * @param sigFailed - True for signature failure, false for success. 85 | * @param validUntil - Last timestamp this UserOperation is valid (or zero for infinite). 86 | * @param validAfter - First timestamp this UserOperation is valid. 87 | */ 88 | function _packValidationData( 89 | bool sigFailed, 90 | uint48 validUntil, 91 | uint48 validAfter 92 | ) pure returns (uint256) { 93 | return 94 | (sigFailed ? 1 : 0) | 95 | (uint256(validUntil) << 160) | 96 | (uint256(validAfter) << (160 + 48)); 97 | } 98 | 99 | /** 100 | * keccak function over calldata. 101 | * @dev copy calldata into memory, do keccak and drop allocated memory. Strangely, this is more efficient than letting solidity do it. 102 | */ 103 | function calldataKeccak(bytes calldata data) pure returns (bytes32 ret) { 104 | assembly { 105 | let mem := mload(0x40) 106 | let len := data.length 107 | calldatacopy(mem, data.offset, len) 108 | ret := keccak256(mem, len) 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /EIP4337TestCase/contracts/core/NonceManager.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity ^0.8.12; 3 | 4 | import "../interfaces/IEntryPoint.sol"; 5 | 6 | /** 7 | * nonce management functionality 8 | */ 9 | contract NonceManager is INonceManager { 10 | 11 | /** 12 | * The next valid sequence number for a given nonce key. 13 | */ 14 | mapping(address => mapping(uint192 => uint256)) public nonceSequenceNumber; 15 | 16 | function getNonce(address sender, uint192 key) 17 | public view override returns (uint256 nonce) { 18 | return nonceSequenceNumber[sender][key] | (uint256(key) << 64); 19 | } 20 | 21 | // allow an account to manually increment its own nonce. 22 | // (mainly so that during construction nonce can be made non-zero, 23 | // to "absorb" the gas cost of first nonce increment to 1st transaction (construction), 24 | // not to 2nd transaction) 25 | function incrementNonce(uint192 key) public override { 26 | nonceSequenceNumber[msg.sender][key]++; 27 | } 28 | 29 | /** 30 | * validate nonce uniqueness for this account. 31 | * called just after validateUserOp() 32 | */ 33 | function _validateAndUpdateNonce(address sender, uint256 nonce) internal returns (bool) { 34 | 35 | uint192 key = uint192(nonce >> 64); 36 | uint64 seq = uint64(nonce); 37 | return nonceSequenceNumber[sender][key]++ == seq; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /EIP4337TestCase/contracts/core/SenderCreator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity ^0.8.12; 3 | 4 | /** 5 | * Helper contract for EntryPoint, to call userOp.initCode from a "neutral" address, 6 | * which is explicitly not the entryPoint itself. 7 | */ 8 | contract SenderCreator { 9 | /** 10 | * Call the "initCode" factory to create and return the sender account address. 11 | * @param initCode - The initCode value from a UserOp. contains 20 bytes of factory address, 12 | * followed by calldata. 13 | * @return sender - The returned address of the created account, or zero address on failure. 14 | */ 15 | function createSender( 16 | bytes calldata initCode 17 | ) external returns (address sender) { 18 | address factory = address(bytes20(initCode[0:20])); 19 | bytes memory initCallData = initCode[20:]; 20 | bool success; 21 | /* solhint-disable no-inline-assembly */ 22 | assembly { 23 | success := call( 24 | gas(), 25 | factory, 26 | 0, 27 | add(initCallData, 0x20), 28 | mload(initCallData), 29 | 0, 30 | 32 31 | ) 32 | sender := mload(0) 33 | } 34 | if (!success) { 35 | sender = address(0); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /EIP4337TestCase/contracts/core/StakeManager.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity ^0.8.12; 3 | 4 | import "../interfaces/IStakeManager.sol"; 5 | 6 | /* solhint-disable avoid-low-level-calls */ 7 | /* solhint-disable not-rely-on-time */ 8 | 9 | /** 10 | * Manage deposits and stakes. 11 | * Deposit is just a balance used to pay for UserOperations (either by a paymaster or an account). 12 | * Stake is value locked for at least "unstakeDelay" by a paymaster. 13 | */ 14 | abstract contract StakeManager is IStakeManager { 15 | /// maps paymaster to their deposits and stakes 16 | mapping(address => DepositInfo) public deposits; 17 | 18 | /// @inheritdoc IStakeManager 19 | function getDepositInfo( 20 | address account 21 | ) public view returns (DepositInfo memory info) { 22 | return deposits[account]; 23 | } 24 | 25 | /** 26 | * Internal method to return just the stake info. 27 | * @param addr - The account to query. 28 | */ 29 | function _getStakeInfo( 30 | address addr 31 | ) internal view returns (StakeInfo memory info) { 32 | DepositInfo storage depositInfo = deposits[addr]; 33 | info.stake = depositInfo.stake; 34 | info.unstakeDelaySec = depositInfo.unstakeDelaySec; 35 | } 36 | 37 | /** 38 | * Return the deposit (for gas payment) of the account. 39 | * @param account - The account to query. 40 | */ 41 | function balanceOf(address account) public view returns (uint256) { 42 | return deposits[account].deposit; 43 | } 44 | 45 | receive() external payable { 46 | depositTo(msg.sender); 47 | } 48 | 49 | /** 50 | * Increments an account's deposit. 51 | * @param account - The account to increment. 52 | * @param amount - The amount to increment by. 53 | */ 54 | function _incrementDeposit(address account, uint256 amount) internal { 55 | DepositInfo storage info = deposits[account]; 56 | uint256 newAmount = info.deposit + amount; 57 | require(newAmount <= type(uint112).max, "deposit overflow"); 58 | info.deposit = uint112(newAmount); 59 | } 60 | 61 | /** 62 | * Add to the deposit of the given account. 63 | * @param account - The account to add to. 64 | */ 65 | function depositTo(address account) public payable { 66 | _incrementDeposit(account, msg.value); 67 | DepositInfo storage info = deposits[account]; 68 | emit Deposited(account, info.deposit); 69 | } 70 | 71 | /** 72 | * Add to the account's stake - amount and delay 73 | * any pending unstake is first cancelled. 74 | * @param unstakeDelaySec The new lock duration before the deposit can be withdrawn. 75 | */ 76 | function addStake(uint32 unstakeDelaySec) public payable { 77 | DepositInfo storage info = deposits[msg.sender]; 78 | require(unstakeDelaySec > 0, "must specify unstake delay"); 79 | require( 80 | unstakeDelaySec >= info.unstakeDelaySec, 81 | "cannot decrease unstake time" 82 | ); 83 | uint256 stake = info.stake + msg.value; 84 | require(stake > 0, "no stake specified"); 85 | require(stake <= type(uint112).max, "stake overflow"); 86 | deposits[msg.sender] = DepositInfo( 87 | info.deposit, 88 | true, 89 | uint112(stake), 90 | unstakeDelaySec, 91 | 0 92 | ); 93 | emit StakeLocked(msg.sender, stake, unstakeDelaySec); 94 | } 95 | 96 | /** 97 | * Attempt to unlock the stake. 98 | * The value can be withdrawn (using withdrawStake) after the unstake delay. 99 | */ 100 | function unlockStake() external { 101 | DepositInfo storage info = deposits[msg.sender]; 102 | require(info.unstakeDelaySec != 0, "not staked"); 103 | require(info.staked, "already unstaking"); 104 | uint48 withdrawTime = uint48(block.timestamp) + info.unstakeDelaySec; 105 | info.withdrawTime = withdrawTime; 106 | info.staked = false; 107 | emit StakeUnlocked(msg.sender, withdrawTime); 108 | } 109 | 110 | /** 111 | * Withdraw from the (unlocked) stake. 112 | * Must first call unlockStake and wait for the unstakeDelay to pass. 113 | * @param withdrawAddress - The address to send withdrawn value. 114 | */ 115 | function withdrawStake(address payable withdrawAddress) external { 116 | DepositInfo storage info = deposits[msg.sender]; 117 | uint256 stake = info.stake; 118 | require(stake > 0, "No stake to withdraw"); 119 | require(info.withdrawTime > 0, "must call unlockStake() first"); 120 | require( 121 | info.withdrawTime <= block.timestamp, 122 | "Stake withdrawal is not due" 123 | ); 124 | info.unstakeDelaySec = 0; 125 | info.withdrawTime = 0; 126 | info.stake = 0; 127 | emit StakeWithdrawn(msg.sender, withdrawAddress, stake); 128 | (bool success, ) = withdrawAddress.call{value: stake}(""); 129 | require(success, "failed to withdraw stake"); 130 | } 131 | 132 | /** 133 | * Withdraw from the deposit. 134 | * @param withdrawAddress - The address to send withdrawn value. 135 | * @param withdrawAmount - The amount to withdraw. 136 | */ 137 | function withdrawTo( 138 | address payable withdrawAddress, 139 | uint256 withdrawAmount 140 | ) external { 141 | DepositInfo storage info = deposits[msg.sender]; 142 | require(withdrawAmount <= info.deposit, "Withdraw amount too large"); 143 | info.deposit = uint112(info.deposit - withdrawAmount); 144 | emit Withdrawn(msg.sender, withdrawAddress, withdrawAmount); 145 | (bool success, ) = withdrawAddress.call{value: withdrawAmount}(""); 146 | require(success, "failed to withdraw"); 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /EIP4337TestCase/contracts/interfaces/IAccount.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity ^0.8.12; 3 | 4 | import "./UserOperation.sol"; 5 | 6 | interface IAccount { 7 | /** 8 | * Validate user's signature and nonce 9 | * the entryPoint will make the call to the recipient only if this validation call returns successfully. 10 | * signature failure should be reported by returning SIG_VALIDATION_FAILED (1). 11 | * This allows making a "simulation call" without a valid signature 12 | * Other failures (e.g. nonce mismatch, or invalid signature format) should still revert to signal failure. 13 | * 14 | * @dev Must validate caller is the entryPoint. 15 | * Must validate the signature and nonce 16 | * @param userOp - The operation that is about to be executed. 17 | * @param userOpHash - Hash of the user's request data. can be used as the basis for signature. 18 | * @param missingAccountFunds - Missing funds on the account's deposit in the entrypoint. 19 | * This is the minimum amount to transfer to the sender(entryPoint) to be 20 | * able to make the call. The excess is left as a deposit in the entrypoint 21 | * for future calls. Can be withdrawn anytime using "entryPoint.withdrawTo()". 22 | * In case there is a paymaster in the request (or the current deposit is high 23 | * enough), this value will be zero. 24 | * @return validationData - Packaged ValidationData structure. use `_packValidationData` and 25 | * `_unpackValidationData` to encode and decode. 26 | * <20-byte> sigAuthorizer - 0 for valid signature, 1 to mark signature failure, 27 | * otherwise, an address of an "authorizer" contract. 28 | * <6-byte> validUntil - Last timestamp this operation is valid. 0 for "indefinite" 29 | * <6-byte> validAfter - First timestamp this operation is valid 30 | * If an account doesn't use time-range, it is enough to 31 | * return SIG_VALIDATION_FAILED value (1) for signature failure. 32 | * Note that the validation code cannot use block.timestamp (or block.number) directly. 33 | */ 34 | function validateUserOp( 35 | UserOperation calldata userOp, 36 | bytes32 userOpHash, 37 | uint256 missingAccountFunds 38 | ) external returns (uint256 validationData); 39 | } 40 | -------------------------------------------------------------------------------- /EIP4337TestCase/contracts/interfaces/IAggregator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity ^0.8.12; 3 | 4 | import "./UserOperation.sol"; 5 | 6 | /** 7 | * Aggregated Signatures validator. 8 | */ 9 | interface IAggregator { 10 | /** 11 | * Validate aggregated signature. 12 | * Revert if the aggregated signature does not match the given list of operations. 13 | * @param userOps - Array of UserOperations to validate the signature for. 14 | * @param signature - The aggregated signature. 15 | */ 16 | function validateSignatures( 17 | UserOperation[] calldata userOps, 18 | bytes calldata signature 19 | ) external view; 20 | 21 | /** 22 | * Validate signature of a single userOp. 23 | * This method is should be called by bundler after EntryPoint.simulateValidation() returns (reverts) with ValidationResultWithAggregation 24 | * First it validates the signature over the userOp. Then it returns data to be used when creating the handleOps. 25 | * @param userOp - The userOperation received from the user. 26 | * @return sigForUserOp - The value to put into the signature field of the userOp when calling handleOps. 27 | * (usually empty, unless account and aggregator support some kind of "multisig". 28 | */ 29 | function validateUserOpSignature( 30 | UserOperation calldata userOp 31 | ) external view returns (bytes memory sigForUserOp); 32 | 33 | /** 34 | * Aggregate multiple signatures into a single value. 35 | * This method is called off-chain to calculate the signature to pass with handleOps() 36 | * bundler MAY use optimized custom code perform this aggregation. 37 | * @param userOps - Array of UserOperations to collect the signatures from. 38 | * @return aggregatedSignature - The aggregated signature. 39 | */ 40 | function aggregateSignatures( 41 | UserOperation[] calldata userOps 42 | ) external view returns (bytes memory aggregatedSignature); 43 | } 44 | -------------------------------------------------------------------------------- /EIP4337TestCase/contracts/interfaces/IEntryPoint.sol: -------------------------------------------------------------------------------- 1 | /** 2 | ** Account-Abstraction (EIP-4337) singleton EntryPoint implementation. 3 | ** Only one instance required on each chain. 4 | **/ 5 | // SPDX-License-Identifier: GPL-3.0 6 | pragma solidity ^0.8.12; 7 | 8 | /* solhint-disable avoid-low-level-calls */ 9 | /* solhint-disable no-inline-assembly */ 10 | /* solhint-disable reason-string */ 11 | 12 | import "./UserOperation.sol"; 13 | import "./IStakeManager.sol"; 14 | import "./IAggregator.sol"; 15 | import "./INonceManager.sol"; 16 | 17 | interface IEntryPoint is IStakeManager, INonceManager { 18 | /*** 19 | * An event emitted after each successful request. 20 | * @param userOpHash - Unique identifier for the request (hash its entire content, except signature). 21 | * @param sender - The account that generates this request. 22 | * @param paymaster - If non-null, the paymaster that pays for this request. 23 | * @param nonce - The nonce value from the request. 24 | * @param success - True if the sender transaction succeeded, false if reverted. 25 | * @param actualGasCost - Actual amount paid (by account or paymaster) for this UserOperation. 26 | * @param actualGasUsed - Total gas used by this UserOperation (including preVerification, creation, 27 | * validation and execution). 28 | */ 29 | event UserOperationEvent( 30 | bytes32 indexed userOpHash, 31 | address indexed sender, 32 | address indexed paymaster, 33 | uint256 nonce, 34 | bool success, 35 | uint256 actualGasCost, 36 | uint256 actualGasUsed 37 | ); 38 | 39 | /** 40 | * Account "sender" was deployed. 41 | * @param userOpHash - The userOp that deployed this account. UserOperationEvent will follow. 42 | * @param sender - The account that is deployed 43 | * @param factory - The factory used to deploy this account (in the initCode) 44 | * @param paymaster - The paymaster used by this UserOp 45 | */ 46 | event AccountDeployed( 47 | bytes32 indexed userOpHash, 48 | address indexed sender, 49 | address factory, 50 | address paymaster 51 | ); 52 | 53 | /** 54 | * An event emitted if the UserOperation "callData" reverted with non-zero length. 55 | * @param userOpHash - The request unique identifier. 56 | * @param sender - The sender of this request. 57 | * @param nonce - The nonce used in the request. 58 | * @param revertReason - The return bytes from the (reverted) call to "callData". 59 | */ 60 | event UserOperationRevertReason( 61 | bytes32 indexed userOpHash, 62 | address indexed sender, 63 | uint256 nonce, 64 | bytes revertReason 65 | ); 66 | 67 | /** 68 | * An event emitted by handleOps(), before starting the execution loop. 69 | * Any event emitted before this event, is part of the validation. 70 | */ 71 | event BeforeExecution(); 72 | 73 | /** 74 | * Signature aggregator used by the following UserOperationEvents within this bundle. 75 | * @param aggregator - The aggregator used for the following UserOperationEvents. 76 | */ 77 | event SignatureAggregatorChanged(address indexed aggregator); 78 | 79 | /** 80 | * A custom revert error of handleOps, to identify the offending op. 81 | * Should be caught in off-chain handleOps simulation and not happen on-chain. 82 | * Useful for mitigating DoS attempts against batchers or for troubleshooting of factory/account/paymaster reverts. 83 | * NOTE: If simulateValidation passes successfully, there should be no reason for handleOps to fail on it. 84 | * @param opIndex - Index into the array of ops to the failed one (in simulateValidation, this is always zero). 85 | * @param reason - Revert reason. The string starts with a unique code "AAmn", 86 | * where "m" is "1" for factory, "2" for account and "3" for paymaster issues, 87 | * so a failure can be attributed to the correct entity. 88 | */ 89 | error FailedOp(uint256 opIndex, string reason); 90 | 91 | /** 92 | * Error case when a signature aggregator fails to verify the aggregated signature it had created. 93 | * @param aggregator The aggregator that failed to verify the signature 94 | */ 95 | error SignatureValidationFailed(address aggregator); 96 | 97 | /** 98 | * Successful result from simulateValidation. 99 | * @param returnInfo - Gas and time-range returned values. 100 | * @param senderInfo - Stake information about the sender. 101 | * @param factoryInfo - Stake information about the factory (if any). 102 | * @param paymasterInfo - Stake information about the paymaster (if any). 103 | */ 104 | error ValidationResult( 105 | ReturnInfo returnInfo, 106 | StakeInfo senderInfo, 107 | StakeInfo factoryInfo, 108 | StakeInfo paymasterInfo 109 | ); 110 | 111 | /** 112 | * Successful result from simulateValidation, if the account returns a signature aggregator. 113 | * @param returnInfo Gas and time-range returned values 114 | * @param senderInfo Stake information about the sender 115 | * @param factoryInfo Stake information about the factory (if any) 116 | * @param paymasterInfo Stake information about the paymaster (if any) 117 | * @param aggregatorInfo Signature aggregation info (if the account requires signature aggregator) 118 | * Bundler MUST use it to verify the signature, or reject the UserOperation. 119 | */ 120 | error ValidationResultWithAggregation( 121 | ReturnInfo returnInfo, 122 | StakeInfo senderInfo, 123 | StakeInfo factoryInfo, 124 | StakeInfo paymasterInfo, 125 | AggregatorStakeInfo aggregatorInfo 126 | ); 127 | 128 | // Return value of getSenderAddress. 129 | error SenderAddressResult(address sender); 130 | 131 | // Return value of simulateHandleOp. 132 | error ExecutionResult( 133 | uint256 preOpGas, 134 | uint256 paid, 135 | uint48 validAfter, 136 | uint48 validUntil, 137 | bool targetSuccess, 138 | bytes targetResult 139 | ); 140 | 141 | // UserOps handled, per aggregator. 142 | struct UserOpsPerAggregator { 143 | UserOperation[] userOps; 144 | // Aggregator address 145 | IAggregator aggregator; 146 | // Aggregated signature 147 | bytes signature; 148 | } 149 | 150 | /** 151 | * Execute a batch of UserOperations. 152 | * No signature aggregator is used. 153 | * If any account requires an aggregator (that is, it returned an aggregator when 154 | * performing simulateValidation), then handleAggregatedOps() must be used instead. 155 | * @param ops - The operations to execute. 156 | * @param beneficiary - The address to receive the fees. 157 | */ 158 | function handleOps( 159 | UserOperation[] calldata ops, 160 | address payable beneficiary 161 | ) external; 162 | 163 | /** 164 | * Execute a batch of UserOperation with Aggregators 165 | * @param opsPerAggregator - The operations to execute, grouped by aggregator (or address(0) for no-aggregator accounts). 166 | * @param beneficiary - The address to receive the fees. 167 | */ 168 | function handleAggregatedOps( 169 | UserOpsPerAggregator[] calldata opsPerAggregator, 170 | address payable beneficiary 171 | ) external; 172 | 173 | /** 174 | * Generate a request Id - unique identifier for this request. 175 | * The request ID is a hash over the content of the userOp (except the signature), the entrypoint and the chainid. 176 | * @param userOp - The user operation to generate the request ID for. 177 | */ 178 | function getUserOpHash( 179 | UserOperation calldata userOp 180 | ) external view returns (bytes32); 181 | 182 | /** 183 | * Simulate a call to account.validateUserOp and paymaster.validatePaymasterUserOp. 184 | * @dev This method always reverts. Successful result is ValidationResult error. other errors are failures. 185 | * @dev The node must also verify it doesn't use banned opcodes, and that it doesn't reference storage 186 | * outside the account's data. 187 | * @param userOp - The user operation to validate. 188 | */ 189 | function simulateValidation(UserOperation calldata userOp) external; 190 | 191 | /** 192 | * Gas and return values during simulation. 193 | * @param preOpGas - The gas used for validation (including preValidationGas) 194 | * @param prefund - The required prefund for this operation 195 | * @param sigFailed - ValidateUserOp's (or paymaster's) signature check failed 196 | * @param validAfter - First timestamp this UserOp is valid (merging account and paymaster time-range) 197 | * @param validUntil - Last timestamp this UserOp is valid (merging account and paymaster time-range) 198 | * @param paymasterContext - Returned by validatePaymasterUserOp (to be passed into postOp) 199 | */ 200 | struct ReturnInfo { 201 | uint256 preOpGas; 202 | uint256 prefund; 203 | bool sigFailed; 204 | uint48 validAfter; 205 | uint48 validUntil; 206 | bytes paymasterContext; 207 | } 208 | 209 | /** 210 | * Returned aggregated signature info: 211 | * The aggregator returned by the account, and its current stake. 212 | */ 213 | struct AggregatorStakeInfo { 214 | address aggregator; 215 | StakeInfo stakeInfo; 216 | } 217 | 218 | /** 219 | * Get counterfactual sender address. 220 | * Calculate the sender contract address that will be generated by the initCode and salt in the UserOperation. 221 | * This method always revert, and returns the address in SenderAddressResult error 222 | * @param initCode - The constructor code to be passed into the UserOperation. 223 | */ 224 | function getSenderAddress(bytes memory initCode) external; 225 | 226 | /** 227 | * Simulate full execution of a UserOperation (including both validation and target execution) 228 | * This method will always revert with "ExecutionResult". 229 | * It performs full validation of the UserOperation, but ignores signature error. 230 | * An optional target address is called after the userop succeeds, 231 | * and its value is returned (before the entire call is reverted). 232 | * Note that in order to collect the the success/failure of the target call, it must be executed 233 | * with trace enabled to track the emitted events. 234 | * @param op The UserOperation to simulate. 235 | * @param target - If nonzero, a target address to call after userop simulation. If called, 236 | * the targetSuccess and targetResult are set to the return from that call. 237 | * @param targetCallData - CallData to pass to target address. 238 | */ 239 | function simulateHandleOp( 240 | UserOperation calldata op, 241 | address target, 242 | bytes calldata targetCallData 243 | ) external; 244 | } 245 | -------------------------------------------------------------------------------- /EIP4337TestCase/contracts/interfaces/INonceManager.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity ^0.8.12; 3 | 4 | interface INonceManager { 5 | 6 | /** 7 | * Return the next nonce for this sender. 8 | * Within a given key, the nonce values are sequenced (starting with zero, and incremented by one on each userop) 9 | * But UserOp with different keys can come with arbitrary order. 10 | * 11 | * @param sender the account address 12 | * @param key the high 192 bit of the nonce 13 | * @return nonce a full nonce to pass for next UserOp with this sender. 14 | */ 15 | function getNonce(address sender, uint192 key) 16 | external view returns (uint256 nonce); 17 | 18 | /** 19 | * Manually increment the nonce of the sender. 20 | * This method is exposed just for completeness.. 21 | * Account does NOT need to call it, neither during validation, nor elsewhere, 22 | * as the EntryPoint will update the nonce regardless. 23 | * Possible use-case is call it with various keys to "initialize" their nonces to one, so that future 24 | * UserOperations will not pay extra for the first transaction with a given key. 25 | */ 26 | function incrementNonce(uint192 key) external; 27 | } 28 | -------------------------------------------------------------------------------- /EIP4337TestCase/contracts/interfaces/IPaymaster.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity ^0.8.12; 3 | 4 | import "./UserOperation.sol"; 5 | 6 | /** 7 | * The interface exposed by a paymaster contract, who agrees to pay the gas for user's operations. 8 | * A paymaster must hold a stake to cover the required entrypoint stake and also the gas for the transaction. 9 | */ 10 | interface IPaymaster { 11 | enum PostOpMode { 12 | // User op succeeded. 13 | opSucceeded, 14 | // User op reverted. Still has to pay for gas. 15 | opReverted, 16 | // User op succeeded, but caused postOp to revert. 17 | // Now it's a 2nd call, after user's op was deliberately reverted. 18 | postOpReverted 19 | } 20 | 21 | /** 22 | * Payment validation: check if paymaster agrees to pay. 23 | * Must verify sender is the entryPoint. 24 | * Revert to reject this request. 25 | * Note that bundlers will reject this method if it changes the state, unless the paymaster is trusted (whitelisted). 26 | * The paymaster pre-pays using its deposit, and receive back a refund after the postOp method returns. 27 | * @param userOp - The user operation. 28 | * @param userOpHash - Hash of the user's request data. 29 | * @param maxCost - The maximum cost of this transaction (based on maximum gas and gas price from userOp). 30 | * @return context - Value to send to a postOp. Zero length to signify postOp is not required. 31 | * @return validationData - Signature and time-range of this operation, encoded the same as the return 32 | * value of validateUserOperation. 33 | * <20-byte> sigAuthorizer - 0 for valid signature, 1 to mark signature failure, 34 | * otherwise, an address of an "authorizer" contract. 35 | * <6-byte> validUntil - last timestamp this operation is valid. 0 for "indefinite" 36 | * <6-byte> validAfter - first timestamp this operation is valid 37 | * Note that the validation code cannot use block.timestamp (or block.number) directly. 38 | */ 39 | function validatePaymasterUserOp( 40 | UserOperation calldata userOp, 41 | bytes32 userOpHash, 42 | uint256 maxCost 43 | ) external returns (bytes memory context, uint256 validationData); 44 | 45 | /** 46 | * Post-operation handler. 47 | * Must verify sender is the entryPoint. 48 | * @param mode - Enum with the following options: 49 | * opSucceeded - User operation succeeded. 50 | * opReverted - User op reverted. still has to pay for gas. 51 | * postOpReverted - User op succeeded, but caused postOp (in mode=opSucceeded) to revert. 52 | * Now this is the 2nd call, after user's op was deliberately reverted. 53 | * @param context - The context value returned by validatePaymasterUserOp 54 | * @param actualGasCost - Actual gas used so far (without this postOp call). 55 | */ 56 | function postOp( 57 | PostOpMode mode, 58 | bytes calldata context, 59 | uint256 actualGasCost 60 | ) external; 61 | } 62 | -------------------------------------------------------------------------------- /EIP4337TestCase/contracts/interfaces/IStakeManager.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity ^0.8.12; 3 | 4 | /** 5 | * Manage deposits and stakes. 6 | * Deposit is just a balance used to pay for UserOperations (either by a paymaster or an account). 7 | * Stake is value locked for at least "unstakeDelay" by the staked entity. 8 | */ 9 | interface IStakeManager { 10 | event Deposited(address indexed account, uint256 totalDeposit); 11 | 12 | event Withdrawn( 13 | address indexed account, 14 | address withdrawAddress, 15 | uint256 amount 16 | ); 17 | 18 | // Emitted when stake or unstake delay are modified. 19 | event StakeLocked( 20 | address indexed account, 21 | uint256 totalStaked, 22 | uint256 unstakeDelaySec 23 | ); 24 | 25 | // Emitted once a stake is scheduled for withdrawal. 26 | event StakeUnlocked(address indexed account, uint256 withdrawTime); 27 | 28 | event StakeWithdrawn( 29 | address indexed account, 30 | address withdrawAddress, 31 | uint256 amount 32 | ); 33 | 34 | /** 35 | * @param deposit - The entity's deposit. 36 | * @param staked - True if this entity is staked. 37 | * @param stake - Actual amount of ether staked for this entity. 38 | * @param unstakeDelaySec - Minimum delay to withdraw the stake. 39 | * @param withdrawTime - First block timestamp where 'withdrawStake' will be callable, or zero if already locked. 40 | * @dev Sizes were chosen so that (deposit,staked, stake) fit into one cell (used during handleOps) 41 | * and the rest fit into a 2nd cell. 42 | * - 112 bit allows for 10^15 eth 43 | * - 48 bit for full timestamp 44 | * - 32 bit allows 150 years for unstake delay 45 | */ 46 | struct DepositInfo { 47 | uint112 deposit; 48 | bool staked; 49 | uint112 stake; 50 | uint32 unstakeDelaySec; 51 | uint48 withdrawTime; 52 | } 53 | 54 | // API struct used by getStakeInfo and simulateValidation. 55 | struct StakeInfo { 56 | uint256 stake; 57 | uint256 unstakeDelaySec; 58 | } 59 | 60 | /** 61 | * Get deposit info. 62 | * @param account - The account to query. 63 | * @return info - Full deposit information of given account. 64 | */ 65 | function getDepositInfo( 66 | address account 67 | ) external view returns (DepositInfo memory info); 68 | 69 | /** 70 | * Get account balance. 71 | * @param account - The account to query. 72 | * @return - The deposit (for gas payment) of the account. 73 | */ 74 | function balanceOf(address account) external view returns (uint256); 75 | 76 | /** 77 | * Add to the deposit of the given account. 78 | * @param account - The account to add to. 79 | */ 80 | function depositTo(address account) external payable; 81 | 82 | /** 83 | * Add to the account's stake - amount and delay 84 | * any pending unstake is first cancelled. 85 | * @param _unstakeDelaySec - The new lock duration before the deposit can be withdrawn. 86 | */ 87 | function addStake(uint32 _unstakeDelaySec) external payable; 88 | 89 | /** 90 | * Attempt to unlock the stake. 91 | * The value can be withdrawn (using withdrawStake) after the unstake delay. 92 | */ 93 | function unlockStake() external; 94 | 95 | /** 96 | * Withdraw from the (unlocked) stake. 97 | * Must first call unlockStake and wait for the unstakeDelay to pass. 98 | * @param withdrawAddress - The address to send withdrawn value. 99 | */ 100 | function withdrawStake(address payable withdrawAddress) external; 101 | 102 | /** 103 | * Withdraw from the deposit. 104 | * @param withdrawAddress - The address to send withdrawn value. 105 | * @param withdrawAmount - The amount to withdraw. 106 | */ 107 | function withdrawTo( 108 | address payable withdrawAddress, 109 | uint256 withdrawAmount 110 | ) external; 111 | } 112 | -------------------------------------------------------------------------------- /EIP4337TestCase/contracts/interfaces/UserOperation.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity ^0.8.12; 3 | 4 | /* solhint-disable no-inline-assembly */ 5 | 6 | import {calldataKeccak} from "../core/Helpers.sol"; 7 | 8 | /** 9 | * User Operation struct 10 | * @param sender - The sender account of this request. 11 | * @param nonce - Unique value the sender uses to verify it is not a replay. 12 | * @param initCode - If set, the account contract will be created by this constructor/ 13 | * @param callData - The method call to execute on this account. 14 | * @param callGasLimit - The gas limit passed to the callData method call. 15 | * @param verificationGasLimit - Gas used for validateUserOp and validatePaymasterUserOp. 16 | * @param preVerificationGas - Gas not calculated by the handleOps method, but added to the gas paid. 17 | * Covers batch overhead. 18 | * @param maxFeePerGas - Same as EIP-1559 gas parameter. 19 | * @param maxPriorityFeePerGas - Same as EIP-1559 gas parameter. 20 | * @param paymasterAndData - If set, this field holds the paymaster address and paymaster-specific data. 21 | * The paymaster will pay for the transaction instead of the sender. 22 | * @param signature - Sender-verified signature over the entire request, the EntryPoint address and the chain ID. 23 | */ 24 | struct UserOperation { 25 | address sender; 26 | uint256 nonce; 27 | bytes initCode; 28 | bytes callData; 29 | uint256 callGasLimit; 30 | uint256 verificationGasLimit; 31 | uint256 preVerificationGas; 32 | uint256 maxFeePerGas; 33 | uint256 maxPriorityFeePerGas; 34 | bytes paymasterAndData; 35 | bytes signature; 36 | } 37 | 38 | /** 39 | * Utility functions helpful when working with UserOperation structs. 40 | */ 41 | library UserOperationLib { 42 | /** 43 | * Get sender from user operation data. 44 | * @param userOp - The user operation data. 45 | */ 46 | function getSender( 47 | UserOperation calldata userOp 48 | ) internal pure returns (address) { 49 | address data; 50 | //read sender from userOp, which is first userOp member (saves 800 gas...) 51 | assembly { 52 | data := calldataload(userOp) 53 | } 54 | return address(uint160(data)); 55 | } 56 | 57 | /** 58 | * Relayer/block builder might submit the TX with higher priorityFee, 59 | * but the user should not pay above what he signed for. 60 | * @param userOp - The user operation data. 61 | */ 62 | function gasPrice( 63 | UserOperation calldata userOp 64 | ) internal view returns (uint256) { 65 | unchecked { 66 | uint256 maxFeePerGas = userOp.maxFeePerGas; 67 | uint256 maxPriorityFeePerGas = userOp.maxPriorityFeePerGas; 68 | if (maxFeePerGas == maxPriorityFeePerGas) { 69 | //legacy mode (for networks that don't support basefee opcode) 70 | return maxFeePerGas; 71 | } 72 | return min(maxFeePerGas, maxPriorityFeePerGas + block.basefee); 73 | } 74 | } 75 | 76 | /** 77 | * Pack the user operation data into bytes for hashing. 78 | * @param userOp - The user operation data. 79 | */ 80 | function pack( 81 | UserOperation calldata userOp 82 | ) internal pure returns (bytes memory ret) { 83 | address sender = getSender(userOp); 84 | uint256 nonce = userOp.nonce; 85 | bytes32 hashInitCode = calldataKeccak(userOp.initCode); 86 | bytes32 hashCallData = calldataKeccak(userOp.callData); 87 | uint256 callGasLimit = userOp.callGasLimit; 88 | uint256 verificationGasLimit = userOp.verificationGasLimit; 89 | uint256 preVerificationGas = userOp.preVerificationGas; 90 | uint256 maxFeePerGas = userOp.maxFeePerGas; 91 | uint256 maxPriorityFeePerGas = userOp.maxPriorityFeePerGas; 92 | bytes32 hashPaymasterAndData = calldataKeccak(userOp.paymasterAndData); 93 | 94 | return abi.encode( 95 | sender, nonce, 96 | hashInitCode, hashCallData, 97 | callGasLimit, verificationGasLimit, preVerificationGas, 98 | maxFeePerGas, maxPriorityFeePerGas, 99 | hashPaymasterAndData 100 | ); 101 | } 102 | 103 | /** 104 | * Hash the user operation data. 105 | * @param userOp - The user operation data. 106 | */ 107 | function hash( 108 | UserOperation calldata userOp 109 | ) internal pure returns (bytes32) { 110 | return keccak256(pack(userOp)); 111 | } 112 | 113 | /** 114 | * The minimum of two numbers. 115 | * @param a - First number. 116 | * @param b - Second number. 117 | */ 118 | function min(uint256 a, uint256 b) internal pure returns (uint256) { 119 | return a < b ? a : b; 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /EIP4337TestCase/contracts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@account-abstraction/contracts", 3 | "description": "Account Abstraction (EIP 4337) contracts", 4 | "version": "0.6.0", 5 | "main": "./dist/index.js", 6 | "scripts": { 7 | "prepack": "../scripts/prepack-contracts-package.sh", 8 | "postpack": "../scripts/postpack-contracts-package.sh" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/eth-infinitism/account-abstraction" 13 | }, 14 | "keywords": [ 15 | "solidity", 16 | "ethereum", 17 | "smart", 18 | "contracts", 19 | "accipt-abstraction", 20 | "eip-4337" 21 | ], 22 | "license": "MIT", 23 | "bugs": { 24 | "url": "https://github.com/eth-infinitism/account-abstraction/issues" 25 | }, 26 | "devDependencies": { 27 | "@gnosis.pm/safe-contracts": "^1.3.0", 28 | "@nomiclabs/hardhat-ethers": "^2.0.2", 29 | "@nomiclabs/hardhat-waffle": "^2.0.1", 30 | "@uniswap/v3-periphery": "^1.4.3" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /EIP4337TestCase/contracts/samples/LegacyTokenPaymaster.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity ^0.8.12; 3 | 4 | /* solhint-disable reason-string */ 5 | 6 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 7 | import "../core/BasePaymaster.sol"; 8 | 9 | /** 10 | * A sample paymaster that defines itself as a token to pay for gas. 11 | * The paymaster IS the token to use, since a paymaster cannot use an external contract. 12 | * Also, the exchange rate has to be fixed, since it can't reference an external Uniswap or other exchange contract. 13 | * subclass should override "getTokenValueOfEth" to provide actual token exchange rate, settable by the owner. 14 | * Known Limitation: this paymaster is exploitable when put into a batch with multiple ops (of different accounts): 15 | * - while a single op can't exploit the paymaster (if postOp fails to withdraw the tokens, the user's op is reverted, 16 | * and then we know we can withdraw the tokens), multiple ops with different senders (all using this paymaster) 17 | * in a batch can withdraw funds from 2nd and further ops, forcing the paymaster itself to pay (from its deposit) 18 | * - Possible workarounds are either use a more complex paymaster scheme (e.g. the DepositPaymaster) or 19 | * to whitelist the account and the called method ids. 20 | */ 21 | contract LegacyTokenPaymaster is BasePaymaster, ERC20 { 22 | 23 | //calculated cost of the postOp 24 | uint256 constant public COST_OF_POST = 15000; 25 | 26 | address public immutable theFactory; 27 | 28 | constructor(address accountFactory, string memory _symbol, IEntryPoint _entryPoint) ERC20(_symbol, _symbol) BasePaymaster(_entryPoint) { 29 | theFactory = accountFactory; 30 | //make it non-empty 31 | _mint(address(this), 1); 32 | 33 | //owner is allowed to withdraw tokens from the paymaster's balance 34 | _approve(address(this), msg.sender, type(uint).max); 35 | } 36 | 37 | 38 | /** 39 | * helpers for owner, to mint and withdraw tokens. 40 | * @param recipient - the address that will receive the minted tokens. 41 | * @param amount - the amount it will receive. 42 | */ 43 | function mintTokens(address recipient, uint256 amount) external onlyOwner { 44 | _mint(recipient, amount); 45 | } 46 | 47 | /** 48 | * transfer paymaster ownership. 49 | * owner of this paymaster is allowed to withdraw funds (tokens transferred to this paymaster's balance) 50 | * when changing owner, the old owner's withdrawal rights are revoked. 51 | */ 52 | function transferOwnership(address newOwner) public override virtual onlyOwner { 53 | // remove allowance of current owner 54 | _approve(address(this), owner(), 0); 55 | super.transferOwnership(newOwner); 56 | // new owner is allowed to withdraw tokens from the paymaster's balance 57 | _approve(address(this), newOwner, type(uint).max); 58 | } 59 | 60 | //Note: this method assumes a fixed ratio of token-to-eth. subclass should override to supply oracle 61 | // or a setter. 62 | function getTokenValueOfEth(uint256 valueEth) internal view virtual returns (uint256 valueToken) { 63 | return valueEth / 100; 64 | } 65 | 66 | /** 67 | * validate the request: 68 | * if this is a constructor call, make sure it is a known account. 69 | * verify the sender has enough tokens. 70 | * (since the paymaster is also the token, there is no notion of "approval") 71 | */ 72 | function _validatePaymasterUserOp(UserOperation calldata userOp, bytes32 /*userOpHash*/, uint256 requiredPreFund) 73 | internal view override returns (bytes memory context, uint256 validationData) { 74 | uint256 tokenPrefund = getTokenValueOfEth(requiredPreFund); 75 | 76 | // verificationGasLimit is dual-purposed, as gas limit for postOp. make sure it is high enough 77 | // make sure that verificationGasLimit is high enough to handle postOp 78 | require(userOp.verificationGasLimit > COST_OF_POST, "TokenPaymaster: gas too low for postOp"); 79 | 80 | if (userOp.initCode.length != 0) { 81 | _validateConstructor(userOp); 82 | require(balanceOf(userOp.sender) >= tokenPrefund, "TokenPaymaster: no balance (pre-create)"); 83 | } else { 84 | 85 | require(balanceOf(userOp.sender) >= tokenPrefund, "TokenPaymaster: no balance"); 86 | } 87 | 88 | return (abi.encode(userOp.sender), 0); 89 | } 90 | 91 | // when constructing an account, validate constructor code and parameters 92 | // we trust our factory (and that it doesn't have any other public methods) 93 | function _validateConstructor(UserOperation calldata userOp) internal virtual view { 94 | address factory = address(bytes20(userOp.initCode[0 : 20])); 95 | require(factory == theFactory, "TokenPaymaster: wrong account factory"); 96 | } 97 | 98 | /** 99 | * actual charge of user. 100 | * this method will be called just after the user's TX with mode==OpSucceeded|OpReverted (account pays in both cases) 101 | * BUT: if the user changed its balance in a way that will cause postOp to revert, then it gets called again, after reverting 102 | * the user's TX , back to the state it was before the transaction started (before the validatePaymasterUserOp), 103 | * and the transaction should succeed there. 104 | */ 105 | function _postOp(PostOpMode mode, bytes calldata context, uint256 actualGasCost) internal override { 106 | //we don't really care about the mode, we just pay the gas with the user's tokens. 107 | (mode); 108 | address sender = abi.decode(context, (address)); 109 | uint256 charge = getTokenValueOfEth(actualGasCost + COST_OF_POST); 110 | //actualGasCost is known to be no larger than the above requiredPreFund, so the transfer should succeed. 111 | _transfer(sender, address(this), charge); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /EIP4337TestCase/contracts/samples/SimpleAccount.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity ^0.8.12; 3 | 4 | /* solhint-disable avoid-low-level-calls */ 5 | /* solhint-disable no-inline-assembly */ 6 | /* solhint-disable reason-string */ 7 | 8 | import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; 9 | import "@openzeppelin/contracts/proxy/utils/Initializable.sol"; 10 | import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol"; 11 | 12 | import "../core/BaseAccount.sol"; 13 | import "./callback/TokenCallbackHandler.sol"; 14 | 15 | /** 16 | * minimal account. 17 | * this is sample minimal account. 18 | * has execute, eth handling methods 19 | * has a single signer that can send requests through the entryPoint. 20 | */ 21 | contract SimpleAccount is BaseAccount, TokenCallbackHandler, UUPSUpgradeable, Initializable { 22 | using ECDSA for bytes32; 23 | 24 | address public owner; 25 | 26 | IEntryPoint private immutable _entryPoint; 27 | 28 | event SimpleAccountInitialized(IEntryPoint indexed entryPoint, address indexed owner); 29 | 30 | modifier onlyOwner() { 31 | _onlyOwner(); 32 | _; 33 | } 34 | 35 | /// @inheritdoc BaseAccount 36 | function entryPoint() public view virtual override returns (IEntryPoint) { 37 | return _entryPoint; 38 | } 39 | 40 | 41 | // solhint-disable-next-line no-empty-blocks 42 | receive() external payable {} 43 | 44 | constructor(IEntryPoint anEntryPoint) { 45 | _entryPoint = anEntryPoint; 46 | _disableInitializers(); 47 | } 48 | 49 | function _onlyOwner() internal view { 50 | //directly from EOA owner, or through the account itself (which gets redirected through execute()) 51 | require(msg.sender == owner || msg.sender == address(this), "only owner"); 52 | } 53 | 54 | /** 55 | * execute a transaction (called directly from owner, or by entryPoint) 56 | */ 57 | function execute(address dest, uint256 value, bytes calldata func) external { 58 | _requireFromEntryPointOrOwner(); 59 | _call(dest, value, func); 60 | } 61 | 62 | /** 63 | * execute a sequence of transactions 64 | * @dev to reduce gas consumption for trivial case (no value), use a zero-length array to mean zero value 65 | */ 66 | function executeBatch(address[] calldata dest, uint256[] calldata value, bytes[] calldata func) external { 67 | _requireFromEntryPointOrOwner(); 68 | require(dest.length == func.length && (value.length == 0 || value.length == func.length), "wrong array lengths"); 69 | if (value.length == 0) { 70 | for (uint256 i = 0; i < dest.length; i++) { 71 | _call(dest[i], 0, func[i]); 72 | } 73 | } else { 74 | for (uint256 i = 0; i < dest.length; i++) { 75 | _call(dest[i], value[i], func[i]); 76 | } 77 | } 78 | } 79 | 80 | /** 81 | * @dev The _entryPoint member is immutable, to reduce gas consumption. To upgrade EntryPoint, 82 | * a new implementation of SimpleAccount must be deployed with the new EntryPoint address, then upgrading 83 | * the implementation by calling `upgradeTo()` 84 | */ 85 | function initialize(address anOwner) public virtual initializer { 86 | _initialize(anOwner); 87 | } 88 | 89 | function _initialize(address anOwner) internal virtual { 90 | owner = anOwner; 91 | emit SimpleAccountInitialized(_entryPoint, owner); 92 | } 93 | 94 | // Require the function call went through EntryPoint or owner 95 | function _requireFromEntryPointOrOwner() internal view { 96 | require(msg.sender == address(entryPoint()) || msg.sender == owner, "account: not Owner or EntryPoint"); 97 | } 98 | 99 | /// implement template method of BaseAccount 100 | function _validateSignature(UserOperation calldata userOp, bytes32 userOpHash) 101 | internal override virtual returns (uint256 validationData) { 102 | bytes32 hash = userOpHash.toEthSignedMessageHash(); 103 | if (owner != hash.recover(userOp.signature)) 104 | return SIG_VALIDATION_FAILED; 105 | return 0; 106 | } 107 | 108 | function _call(address target, uint256 value, bytes memory data) internal { 109 | (bool success, bytes memory result) = target.call{value : value}(data); 110 | if (!success) { 111 | assembly { 112 | revert(add(result, 32), mload(result)) 113 | } 114 | } 115 | } 116 | 117 | /** 118 | * check current account deposit in the entryPoint 119 | */ 120 | function getDeposit() public view returns (uint256) { 121 | return entryPoint().balanceOf(address(this)); 122 | } 123 | 124 | /** 125 | * deposit more funds for this account in the entryPoint 126 | */ 127 | function addDeposit() public payable { 128 | entryPoint().depositTo{value : msg.value}(address(this)); 129 | } 130 | 131 | /** 132 | * withdraw value from the account's deposit 133 | * @param withdrawAddress target to send to 134 | * @param amount to withdraw 135 | */ 136 | function withdrawDepositTo(address payable withdrawAddress, uint256 amount) public onlyOwner { 137 | entryPoint().withdrawTo(withdrawAddress, amount); 138 | } 139 | 140 | function _authorizeUpgrade(address newImplementation) internal view override { 141 | (newImplementation); 142 | _onlyOwner(); 143 | } 144 | } 145 | 146 | -------------------------------------------------------------------------------- /EIP4337TestCase/contracts/samples/SimpleAccountFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity ^0.8.12; 3 | 4 | import "@openzeppelin/contracts/utils/Create2.sol"; 5 | import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; 6 | 7 | import "./SimpleAccount.sol"; 8 | 9 | /** 10 | * A sample factory contract for SimpleAccount 11 | * A UserOperations "initCode" holds the address of the factory, and a method call (to createAccount, in this sample factory). 12 | * The factory's createAccount returns the target account address even if it is already installed. 13 | * This way, the entryPoint.getSenderAddress() can be called either before or after the account is created. 14 | */ 15 | contract SimpleAccountFactory { 16 | SimpleAccount public immutable accountImplementation; 17 | 18 | constructor(IEntryPoint _entryPoint) { 19 | accountImplementation = new SimpleAccount(_entryPoint); 20 | } 21 | 22 | /** 23 | * create an account, and return its address. 24 | * returns the address even if the account is already deployed. 25 | * Note that during UserOperation execution, this method is called only if the account is not deployed. 26 | * This method returns an existing account address so that entryPoint.getSenderAddress() would work even after account creation 27 | */ 28 | function createAccount(address owner,uint256 salt) public returns (SimpleAccount ret) { 29 | address addr = getAddress(owner, salt); 30 | uint codeSize = addr.code.length; 31 | if (codeSize > 0) { 32 | return SimpleAccount(payable(addr)); 33 | } 34 | ret = SimpleAccount(payable(new ERC1967Proxy{salt : bytes32(salt)}( 35 | address(accountImplementation), 36 | abi.encodeCall(SimpleAccount.initialize, (owner)) 37 | ))); 38 | } 39 | 40 | /** 41 | * calculate the counterfactual address of this account as it would be returned by createAccount() 42 | */ 43 | function getAddress(address owner,uint256 salt) public view returns (address) { 44 | return Create2.computeAddress(bytes32(salt), keccak256(abi.encodePacked( 45 | type(ERC1967Proxy).creationCode, 46 | abi.encode( 47 | address(accountImplementation), 48 | abi.encodeCall(SimpleAccount.initialize, (owner)) 49 | ) 50 | ))); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /EIP4337TestCase/contracts/samples/callback/TokenCallbackHandler.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity ^0.8.12; 3 | 4 | /* solhint-disable no-empty-blocks */ 5 | 6 | import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; 7 | import "@openzeppelin/contracts/token/ERC777/IERC777Recipient.sol"; 8 | import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; 9 | import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol"; 10 | 11 | /** 12 | * Token callback handler. 13 | * Handles supported tokens' callbacks, allowing account receiving these tokens. 14 | */ 15 | contract TokenCallbackHandler is IERC777Recipient, IERC721Receiver, IERC1155Receiver { 16 | function tokensReceived( 17 | address, 18 | address, 19 | address, 20 | uint256, 21 | bytes calldata, 22 | bytes calldata 23 | ) external pure override { 24 | } 25 | 26 | function onERC721Received( 27 | address, 28 | address, 29 | uint256, 30 | bytes calldata 31 | ) external pure override returns (bytes4) { 32 | return IERC721Receiver.onERC721Received.selector; 33 | } 34 | 35 | function onERC1155Received( 36 | address, 37 | address, 38 | uint256, 39 | uint256, 40 | bytes calldata 41 | ) external pure override returns (bytes4) { 42 | return IERC1155Receiver.onERC1155Received.selector; 43 | } 44 | 45 | function onERC1155BatchReceived( 46 | address, 47 | address, 48 | uint256[] calldata, 49 | uint256[] calldata, 50 | bytes calldata 51 | ) external pure override returns (bytes4) { 52 | return IERC1155Receiver.onERC1155BatchReceived.selector; 53 | } 54 | 55 | function supportsInterface(bytes4 interfaceId) external view virtual override returns (bool) { 56 | return 57 | interfaceId == type(IERC721Receiver).interfaceId || 58 | interfaceId == type(IERC1155Receiver).interfaceId || 59 | interfaceId == type(IERC165).interfaceId; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /EIP4337TestCase/contracts/utils/Exec.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity >=0.7.5 <0.9.0; 3 | 4 | // solhint-disable no-inline-assembly 5 | 6 | /** 7 | * Utility functions helpful when making different kinds of contract calls in Solidity. 8 | */ 9 | library Exec { 10 | 11 | function call( 12 | address to, 13 | uint256 value, 14 | bytes memory data, 15 | uint256 txGas 16 | ) internal returns (bool success) { 17 | assembly { 18 | success := call(txGas, to, value, add(data, 0x20), mload(data), 0, 0) 19 | } 20 | } 21 | 22 | function staticcall( 23 | address to, 24 | bytes memory data, 25 | uint256 txGas 26 | ) internal view returns (bool success) { 27 | assembly { 28 | success := staticcall(txGas, to, add(data, 0x20), mload(data), 0, 0) 29 | } 30 | } 31 | 32 | function delegateCall( 33 | address to, 34 | bytes memory data, 35 | uint256 txGas 36 | ) internal returns (bool success) { 37 | assembly { 38 | success := delegatecall(txGas, to, add(data, 0x20), mload(data), 0, 0) 39 | } 40 | } 41 | 42 | // get returned data from last call or calldelegate 43 | function getReturnData(uint256 maxLen) internal pure returns (bytes memory returnData) { 44 | assembly { 45 | let len := returndatasize() 46 | if gt(len, maxLen) { 47 | len := maxLen 48 | } 49 | let ptr := mload(0x40) 50 | mstore(0x40, add(ptr, add(len, 0x20))) 51 | mstore(ptr, len) 52 | returndatacopy(add(ptr, 0x20), 0, len) 53 | returnData := ptr 54 | } 55 | } 56 | 57 | // revert with explicit byte array (probably reverted info from call) 58 | function revertWithData(bytes memory returnData) internal pure { 59 | assembly { 60 | revert(add(returnData, 32), mload(returnData)) 61 | } 62 | } 63 | 64 | function callAndRevert(address to, bytes memory data, uint256 maxLen) internal { 65 | bool success = call(to,0,data,gasleft()); 66 | if (!success) { 67 | revertWithData(getReturnData(maxLen)); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /EIP4337TestCase/foundry.toml: -------------------------------------------------------------------------------- 1 | [profile.default] 2 | src = 'contracts' 3 | out = 'out' 4 | libs = ['node_modules', 'lib'] 5 | solc_version = "0.8.17" 6 | 7 | # See more config options https://github.com/foundry-rs/foundry/tree/master/config -------------------------------------------------------------------------------- /EIP4337TestCase/lib/forge-std/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Copyright Contributors to Forge Standard Library 2 | 3 | Apache License 4 | Version 2.0, January 2004 5 | http://www.apache.org/licenses/ 6 | 7 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 8 | 9 | 1. Definitions. 10 | 11 | "License" shall mean the terms and conditions for use, reproduction, 12 | and distribution as defined by Sections 1 through 9 of this document. 13 | 14 | "Licensor" shall mean the copyright owner or entity authorized by 15 | the copyright owner that is granting the License. 16 | 17 | "Legal Entity" shall mean the union of the acting entity and all 18 | other entities that control, are controlled by, or are under common 19 | control with that entity. For the purposes of this definition, 20 | "control" means (i) the power, direct or indirect, to cause the 21 | direction or management of such entity, whether by contract or 22 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 23 | outstanding shares, or (iii) beneficial ownership of such entity. 24 | 25 | "You" (or "Your") shall mean an individual or Legal Entity 26 | exercising permissions granted by this License. 27 | 28 | "Source" form shall mean the preferred form for making modifications, 29 | including but not limited to software source code, documentation 30 | source, and configuration files. 31 | 32 | "Object" form shall mean any form resulting from mechanical 33 | transformation or translation of a Source form, including but 34 | not limited to compiled object code, generated documentation, 35 | and conversions to other media types. 36 | 37 | "Work" shall mean the work of authorship, whether in Source or 38 | Object form, made available under the License, as indicated by a 39 | copyright notice that is included in or attached to the work 40 | (an example is provided in the Appendix below). 41 | 42 | "Derivative Works" shall mean any work, whether in Source or Object 43 | form, that is based on (or derived from) the Work and for which the 44 | editorial revisions, annotations, elaborations, or other modifications 45 | represent, as a whole, an original work of authorship. For the purposes 46 | of this License, Derivative Works shall not include works that remain 47 | separable from, or merely link (or bind by name) to the interfaces of, 48 | the Work and Derivative Works thereof. 49 | 50 | "Contribution" shall mean any work of authorship, including 51 | the original version of the Work and any modifications or additions 52 | to that Work or Derivative Works thereof, that is intentionally 53 | submitted to Licensor for inclusion in the Work by the copyright owner 54 | or by an individual or Legal Entity authorized to submit on behalf of 55 | the copyright owner. For the purposes of this definition, "submitted" 56 | means any form of electronic, verbal, or written communication sent 57 | to the Licensor or its representatives, including but not limited to 58 | communication on electronic mailing lists, source code control systems, 59 | and issue tracking systems that are managed by, or on behalf of, the 60 | Licensor for the purpose of discussing and improving the Work, but 61 | excluding communication that is conspicuously marked or otherwise 62 | designated in writing by the copyright owner as "Not a Contribution." 63 | 64 | "Contributor" shall mean Licensor and any individual or Legal Entity 65 | on behalf of whom a Contribution has been received by Licensor and 66 | subsequently incorporated within the Work. 67 | 68 | 2. Grant of Copyright License. Subject to the terms and conditions of 69 | this License, each Contributor hereby grants to You a perpetual, 70 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 71 | copyright license to reproduce, prepare Derivative Works of, 72 | publicly display, publicly perform, sublicense, and distribute the 73 | Work and such Derivative Works in Source or Object form. 74 | 75 | 3. Grant of Patent License. Subject to the terms and conditions of 76 | this License, each Contributor hereby grants to You a perpetual, 77 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 78 | (except as stated in this section) patent license to make, have made, 79 | use, offer to sell, sell, import, and otherwise transfer the Work, 80 | where such license applies only to those patent claims licensable 81 | by such Contributor that are necessarily infringed by their 82 | Contribution(s) alone or by combination of their Contribution(s) 83 | with the Work to which such Contribution(s) was submitted. If You 84 | institute patent litigation against any entity (including a 85 | cross-claim or counterclaim in a lawsuit) alleging that the Work 86 | or a Contribution incorporated within the Work constitutes direct 87 | or contributory patent infringement, then any patent licenses 88 | granted to You under this License for that Work shall terminate 89 | as of the date such litigation is filed. 90 | 91 | 4. Redistribution. You may reproduce and distribute copies of the 92 | Work or Derivative Works thereof in any medium, with or without 93 | modifications, and in Source or Object form, provided that You 94 | meet the following conditions: 95 | 96 | (a) You must give any other recipients of the Work or 97 | Derivative Works a copy of this License; and 98 | 99 | (b) You must cause any modified files to carry prominent notices 100 | stating that You changed the files; and 101 | 102 | (c) You must retain, in the Source form of any Derivative Works 103 | that You distribute, all copyright, patent, trademark, and 104 | attribution notices from the Source form of the Work, 105 | excluding those notices that do not pertain to any part of 106 | the Derivative Works; and 107 | 108 | (d) If the Work includes a "NOTICE" text file as part of its 109 | distribution, then any Derivative Works that You distribute must 110 | include a readable copy of the attribution notices contained 111 | within such NOTICE file, excluding those notices that do not 112 | pertain to any part of the Derivative Works, in at least one 113 | of the following places: within a NOTICE text file distributed 114 | as part of the Derivative Works; within the Source form or 115 | documentation, if provided along with the Derivative Works; or, 116 | within a display generated by the Derivative Works, if and 117 | wherever such third-party notices normally appear. The contents 118 | of the NOTICE file are for informational purposes only and 119 | do not modify the License. You may add Your own attribution 120 | notices within Derivative Works that You distribute, alongside 121 | or as an addendum to the NOTICE text from the Work, provided 122 | that such additional attribution notices cannot be construed 123 | as modifying the License. 124 | 125 | You may add Your own copyright statement to Your modifications and 126 | may provide additional or different license terms and conditions 127 | for use, reproduction, or distribution of Your modifications, or 128 | for any such Derivative Works as a whole, provided Your use, 129 | reproduction, and distribution of the Work otherwise complies with 130 | the conditions stated in this License. 131 | 132 | 5. Submission of Contributions. Unless You explicitly state otherwise, 133 | any Contribution intentionally submitted for inclusion in the Work 134 | by You to the Licensor shall be under the terms and conditions of 135 | this License, without any additional terms or conditions. 136 | Notwithstanding the above, nothing herein shall supersede or modify 137 | the terms of any separate license agreement you may have executed 138 | with Licensor regarding such Contributions. 139 | 140 | 6. Trademarks. This License does not grant permission to use the trade 141 | names, trademarks, service marks, or product names of the Licensor, 142 | except as required for reasonable and customary use in describing the 143 | origin of the Work and reproducing the content of the NOTICE file. 144 | 145 | 7. Disclaimer of Warranty. Unless required by applicable law or 146 | agreed to in writing, Licensor provides the Work (and each 147 | Contributor provides its Contributions) on an "AS IS" BASIS, 148 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 149 | implied, including, without limitation, any warranties or conditions 150 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 151 | PARTICULAR PURPOSE. You are solely responsible for determining the 152 | appropriateness of using or redistributing the Work and assume any 153 | risks associated with Your exercise of permissions under this License. 154 | 155 | 8. Limitation of Liability. In no event and under no legal theory, 156 | whether in tort (including negligence), contract, or otherwise, 157 | unless required by applicable law (such as deliberate and grossly 158 | negligent acts) or agreed to in writing, shall any Contributor be 159 | liable to You for damages, including any direct, indirect, special, 160 | incidental, or consequential damages of any character arising as a 161 | result of this License or out of the use or inability to use the 162 | Work (including but not limited to damages for loss of goodwill, 163 | work stoppage, computer failure or malfunction, or any and all 164 | other commercial damages or losses), even if such Contributor 165 | has been advised of the possibility of such damages. 166 | 167 | 9. Accepting Warranty or Additional Liability. While redistributing 168 | the Work or Derivative Works thereof, You may choose to offer, 169 | and charge a fee for, acceptance of support, warranty, indemnity, 170 | or other liability obligations and/or rights consistent with this 171 | License. However, in accepting such obligations, You may act only 172 | on Your own behalf and on Your sole responsibility, not on behalf 173 | of any other Contributor, and only if You agree to indemnify, 174 | defend, and hold each Contributor harmless for any liability 175 | incurred by, or claims asserted against, such Contributor by reason 176 | of your accepting any such warranty or additional liability. 177 | 178 | END OF TERMS AND CONDITIONS 179 | 180 | APPENDIX: How to apply the Apache License to your work. 181 | 182 | To apply the Apache License to your work, attach the following 183 | boilerplate notice, with the fields enclosed by brackets "[]" 184 | replaced with your own identifying information. (Don't include 185 | the brackets!) The text should be enclosed in the appropriate 186 | comment syntax for the file format. We also recommend that a 187 | file or class name and description of purpose be included on the 188 | same "printed page" as the copyright notice for easier 189 | identification within third-party archives. 190 | 191 | Copyright [yyyy] [name of copyright owner] 192 | 193 | Licensed under the Apache License, Version 2.0 (the "License"); 194 | you may not use this file except in compliance with the License. 195 | You may obtain a copy of the License at 196 | 197 | http://www.apache.org/licenses/LICENSE-2.0 198 | 199 | Unless required by applicable law or agreed to in writing, software 200 | distributed under the License is distributed on an "AS IS" BASIS, 201 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 202 | See the License for the specific language governing permissions and 203 | limitations under the License. 204 | -------------------------------------------------------------------------------- /EIP4337TestCase/lib/forge-std/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright Contributors to Forge Standard Library 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE O THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE.R 26 | -------------------------------------------------------------------------------- /EIP4337TestCase/lib/forge-std/README.md: -------------------------------------------------------------------------------- 1 | # Forge Standard Library • [![CI status](https://github.com/foundry-rs/forge-std/actions/workflows/ci.yml/badge.svg)](https://github.com/foundry-rs/forge-std/actions/workflows/ci.yml) 2 | 3 | Forge Standard Library is a collection of helpful contracts and libraries for use with [Forge and Foundry](https://github.com/foundry-rs/foundry). It leverages Forge's cheatcodes to make writing tests easier and faster, while improving the UX of cheatcodes. 4 | 5 | **Learn how to use Forge-Std with the [📖 Foundry Book (Forge-Std Guide)](https://book.getfoundry.sh/forge/forge-std.html).** 6 | 7 | ## Install 8 | 9 | ```bash 10 | forge install foundry-rs/forge-std 11 | ``` 12 | 13 | ## Contracts 14 | ### stdError 15 | 16 | This is a helper contract for errors and reverts. In Forge, this contract is particularly helpful for the `expectRevert` cheatcode, as it provides all compiler builtin errors. 17 | 18 | See the contract itself for all error codes. 19 | 20 | #### Example usage 21 | 22 | ```solidity 23 | 24 | import "forge-std/Test.sol"; 25 | 26 | contract TestContract is Test { 27 | ErrorsTest test; 28 | 29 | function setUp() public { 30 | test = new ErrorsTest(); 31 | } 32 | 33 | function testExpectArithmetic() public { 34 | vm.expectRevert(stdError.arithmeticError); 35 | test.arithmeticError(10); 36 | } 37 | } 38 | 39 | contract ErrorsTest { 40 | function arithmeticError(uint256 a) public { 41 | uint256 a = a - 100; 42 | } 43 | } 44 | ``` 45 | 46 | ### stdStorage 47 | 48 | This is a rather large contract due to all of the overloading to make the UX decent. Primarily, it is a wrapper around the `record` and `accesses` cheatcodes. It can *always* find and write the storage slot(s) associated with a particular variable without knowing the storage layout. The one _major_ caveat to this is while a slot can be found for packed storage variables, we can't write to that variable safely. If a user tries to write to a packed slot, the execution throws an error, unless it is uninitialized (`bytes32(0)`). 49 | 50 | This works by recording all `SLOAD`s and `SSTORE`s during a function call. If there is a single slot read or written to, it immediately returns the slot. Otherwise, behind the scenes, we iterate through and check each one (assuming the user passed in a `depth` parameter). If the variable is a struct, you can pass in a `depth` parameter which is basically the field depth. 51 | 52 | I.e.: 53 | ```solidity 54 | struct T { 55 | // depth 0 56 | uint256 a; 57 | // depth 1 58 | uint256 b; 59 | } 60 | ``` 61 | 62 | #### Example usage 63 | 64 | ```solidity 65 | import "forge-std/Test.sol"; 66 | 67 | contract TestContract is Test { 68 | using stdStorage for StdStorage; 69 | 70 | Storage test; 71 | 72 | function setUp() public { 73 | test = new Storage(); 74 | } 75 | 76 | function testFindExists() public { 77 | // Lets say we want to find the slot for the public 78 | // variable `exists`. We just pass in the function selector 79 | // to the `find` command 80 | uint256 slot = stdstore.target(address(test)).sig("exists()").find(); 81 | assertEq(slot, 0); 82 | } 83 | 84 | function testWriteExists() public { 85 | // Lets say we want to write to the slot for the public 86 | // variable `exists`. We just pass in the function selector 87 | // to the `checked_write` command 88 | stdstore.target(address(test)).sig("exists()").checked_write(100); 89 | assertEq(test.exists(), 100); 90 | } 91 | 92 | // It supports arbitrary storage layouts, like assembly based storage locations 93 | function testFindHidden() public { 94 | // `hidden` is a random hash of a bytes, iteration through slots would 95 | // not find it. Our mechanism does 96 | // Also, you can use the selector instead of a string 97 | uint256 slot = stdstore.target(address(test)).sig(test.hidden.selector).find(); 98 | assertEq(slot, uint256(keccak256("my.random.var"))); 99 | } 100 | 101 | // If targeting a mapping, you have to pass in the keys necessary to perform the find 102 | // i.e.: 103 | function testFindMapping() public { 104 | uint256 slot = stdstore 105 | .target(address(test)) 106 | .sig(test.map_addr.selector) 107 | .with_key(address(this)) 108 | .find(); 109 | // in the `Storage` constructor, we wrote that this address' value was 1 in the map 110 | // so when we load the slot, we expect it to be 1 111 | assertEq(uint(vm.load(address(test), bytes32(slot))), 1); 112 | } 113 | 114 | // If the target is a struct, you can specify the field depth: 115 | function testFindStruct() public { 116 | // NOTE: see the depth parameter - 0 means 0th field, 1 means 1st field, etc. 117 | uint256 slot_for_a_field = stdstore 118 | .target(address(test)) 119 | .sig(test.basicStruct.selector) 120 | .depth(0) 121 | .find(); 122 | 123 | uint256 slot_for_b_field = stdstore 124 | .target(address(test)) 125 | .sig(test.basicStruct.selector) 126 | .depth(1) 127 | .find(); 128 | 129 | assertEq(uint(vm.load(address(test), bytes32(slot_for_a_field))), 1); 130 | assertEq(uint(vm.load(address(test), bytes32(slot_for_b_field))), 2); 131 | } 132 | } 133 | 134 | // A complex storage contract 135 | contract Storage { 136 | struct UnpackedStruct { 137 | uint256 a; 138 | uint256 b; 139 | } 140 | 141 | constructor() { 142 | map_addr[msg.sender] = 1; 143 | } 144 | 145 | uint256 public exists = 1; 146 | mapping(address => uint256) public map_addr; 147 | // mapping(address => Packed) public map_packed; 148 | mapping(address => UnpackedStruct) public map_struct; 149 | mapping(address => mapping(address => uint256)) public deep_map; 150 | mapping(address => mapping(address => UnpackedStruct)) public deep_map_struct; 151 | UnpackedStruct public basicStruct = UnpackedStruct({ 152 | a: 1, 153 | b: 2 154 | }); 155 | 156 | function hidden() public view returns (bytes32 t) { 157 | // an extremely hidden storage slot 158 | bytes32 slot = keccak256("my.random.var"); 159 | assembly { 160 | t := sload(slot) 161 | } 162 | } 163 | } 164 | ``` 165 | 166 | ### stdCheats 167 | 168 | This is a wrapper over miscellaneous cheatcodes that need wrappers to be more dev friendly. Currently there are only functions related to `prank`. In general, users may expect ETH to be put into an address on `prank`, but this is not the case for safety reasons. Explicitly this `hoax` function should only be used for address that have expected balances as it will get overwritten. If an address already has ETH, you should just use `prank`. If you want to change that balance explicitly, just use `deal`. If you want to do both, `hoax` is also right for you. 169 | 170 | 171 | #### Example usage: 172 | ```solidity 173 | 174 | // SPDX-License-Identifier: MIT 175 | pragma solidity ^0.8.0; 176 | 177 | import "forge-std/Test.sol"; 178 | 179 | // Inherit the stdCheats 180 | contract StdCheatsTest is Test { 181 | Bar test; 182 | function setUp() public { 183 | test = new Bar(); 184 | } 185 | 186 | function testHoax() public { 187 | // we call `hoax`, which gives the target address 188 | // eth and then calls `prank` 189 | hoax(address(1337)); 190 | test.bar{value: 100}(address(1337)); 191 | 192 | // overloaded to allow you to specify how much eth to 193 | // initialize the address with 194 | hoax(address(1337), 1); 195 | test.bar{value: 1}(address(1337)); 196 | } 197 | 198 | function testStartHoax() public { 199 | // we call `startHoax`, which gives the target address 200 | // eth and then calls `startPrank` 201 | // 202 | // it is also overloaded so that you can specify an eth amount 203 | startHoax(address(1337)); 204 | test.bar{value: 100}(address(1337)); 205 | test.bar{value: 100}(address(1337)); 206 | vm.stopPrank(); 207 | test.bar(address(this)); 208 | } 209 | } 210 | 211 | contract Bar { 212 | function bar(address expectedSender) public payable { 213 | require(msg.sender == expectedSender, "!prank"); 214 | } 215 | } 216 | ``` 217 | 218 | ### Std Assertions 219 | 220 | Expand upon the assertion functions from the `DSTest` library. 221 | 222 | ### `console.log` 223 | 224 | Usage follows the same format as [Hardhat](https://hardhat.org/hardhat-network/reference/#console-log). 225 | It's recommended to use `console2.sol` as shown below, as this will show the decoded logs in Forge traces. 226 | 227 | ```solidity 228 | // import it indirectly via Test.sol 229 | import "forge-std/Test.sol"; 230 | // or directly import it 231 | import "forge-std/console2.sol"; 232 | ... 233 | console2.log(someValue); 234 | ``` 235 | 236 | If you need compatibility with Hardhat, you must use the standard `console.sol` instead. 237 | Due to a bug in `console.sol`, logs that use `uint256` or `int256` types will not be properly decoded in Forge traces. 238 | 239 | ```solidity 240 | // import it indirectly via Test.sol 241 | import "forge-std/Test.sol"; 242 | // or directly import it 243 | import "forge-std/console.sol"; 244 | ... 245 | console.log(someValue); 246 | ``` 247 | 248 | ## License 249 | 250 | Forge Standard Library is offered under either [MIT](LICENSE-MIT) or [Apache 2.0](LICENSE-APACHE) license. 251 | -------------------------------------------------------------------------------- /EIP4337TestCase/lib/forge-std/foundry.toml: -------------------------------------------------------------------------------- 1 | [profile.default] 2 | fs_permissions = [{ access = "read-write", path = "./"}] 3 | 4 | [rpc_endpoints] 5 | # The RPC URLs are modified versions of the default for testing initialization. 6 | mainnet = "https://mainnet.infura.io/v3/b1d3925804e74152b316ca7da97060d3" # Different API key. 7 | optimism_goerli = "https://goerli.optimism.io/" # Adds a trailing slash. 8 | arbitrum_one_goerli = "https://goerli-rollup.arbitrum.io/rpc/" # Adds a trailing slash. 9 | needs_undefined_env_var = "${UNDEFINED_RPC_URL_PLACEHOLDER}" 10 | 11 | [fmt] 12 | # These are all the `forge fmt` defaults. 13 | line_length = 120 14 | tab_width = 4 15 | bracket_spacing = false 16 | int_types = 'long' 17 | multiline_func_header = 'attributes_first' 18 | quote_style = 'double' 19 | number_underscore = 'preserve' 20 | single_line_statement_blocks = 'preserve' 21 | ignore = ["src/console.sol", "src/console2.sol"] -------------------------------------------------------------------------------- /EIP4337TestCase/lib/forge-std/lib/ds-test/Makefile: -------------------------------------------------------------------------------- 1 | all:; dapp build 2 | 3 | test: 4 | -dapp --use solc:0.4.23 build 5 | -dapp --use solc:0.4.26 build 6 | -dapp --use solc:0.5.17 build 7 | -dapp --use solc:0.6.12 build 8 | -dapp --use solc:0.7.5 build 9 | 10 | demo: 11 | DAPP_SRC=demo dapp --use solc:0.7.5 build 12 | -hevm dapp-test --verbose 3 13 | 14 | .PHONY: test demo 15 | -------------------------------------------------------------------------------- /EIP4337TestCase/lib/forge-std/lib/ds-test/default.nix: -------------------------------------------------------------------------------- 1 | { solidityPackage, dappsys }: solidityPackage { 2 | name = "ds-test"; 3 | src = ./src; 4 | } 5 | -------------------------------------------------------------------------------- /EIP4337TestCase/lib/forge-std/lib/ds-test/demo/demo.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity >=0.5.0; 3 | 4 | import "../src/test.sol"; 5 | 6 | contract DemoTest is DSTest { 7 | function test_this() public pure { 8 | require(true); 9 | } 10 | function test_logs() public { 11 | emit log("-- log(string)"); 12 | emit log("a string"); 13 | 14 | emit log("-- log_named_uint(string, uint)"); 15 | emit log_named_uint("uint", 512); 16 | 17 | emit log("-- log_named_int(string, int)"); 18 | emit log_named_int("int", -512); 19 | 20 | emit log("-- log_named_address(string, address)"); 21 | emit log_named_address("address", address(this)); 22 | 23 | emit log("-- log_named_bytes32(string, bytes32)"); 24 | emit log_named_bytes32("bytes32", "a string"); 25 | 26 | emit log("-- log_named_bytes(string, bytes)"); 27 | emit log_named_bytes("bytes", hex"cafefe"); 28 | 29 | emit log("-- log_named_string(string, string)"); 30 | emit log_named_string("string", "a string"); 31 | 32 | emit log("-- log_named_decimal_uint(string, uint, uint)"); 33 | emit log_named_decimal_uint("decimal uint", 1.0e18, 18); 34 | 35 | emit log("-- log_named_decimal_int(string, int, uint)"); 36 | emit log_named_decimal_int("decimal int", -1.0e18, 18); 37 | } 38 | event log_old_named_uint(bytes32,uint); 39 | function test_old_logs() public { 40 | emit log_old_named_uint("key", 500); 41 | emit log_named_bytes32("bkey", "val"); 42 | } 43 | function test_trace() public view { 44 | this.echo("string 1", "string 2"); 45 | } 46 | function test_multiline() public { 47 | emit log("a multiline\\nstring"); 48 | emit log("a multiline string"); 49 | emit log_bytes("a string"); 50 | emit log_bytes("a multiline\nstring"); 51 | emit log_bytes("a multiline\\nstring"); 52 | emit logs(hex"0000"); 53 | emit log_named_bytes("0x0000", hex"0000"); 54 | emit logs(hex"ff"); 55 | } 56 | function echo(string memory s1, string memory s2) public pure 57 | returns (string memory, string memory) 58 | { 59 | return (s1, s2); 60 | } 61 | 62 | function prove_this(uint x) public { 63 | emit log_named_uint("sym x", x); 64 | assertGt(x + 1, 0); 65 | } 66 | 67 | function test_logn() public { 68 | assembly { 69 | log0(0x01, 0x02) 70 | log1(0x01, 0x02, 0x03) 71 | log2(0x01, 0x02, 0x03, 0x04) 72 | log3(0x01, 0x02, 0x03, 0x04, 0x05) 73 | } 74 | } 75 | 76 | event MyEvent(uint, uint indexed, uint, uint indexed); 77 | function test_events() public { 78 | emit MyEvent(1, 2, 3, 4); 79 | } 80 | 81 | function test_asserts() public { 82 | string memory err = "this test has failed!"; 83 | emit log("## assertTrue(bool)\n"); 84 | assertTrue(false); 85 | emit log("\n"); 86 | assertTrue(false, err); 87 | 88 | emit log("\n## assertEq(address,address)\n"); 89 | assertEq(address(this), msg.sender); 90 | emit log("\n"); 91 | assertEq(address(this), msg.sender, err); 92 | 93 | emit log("\n## assertEq32(bytes32,bytes32)\n"); 94 | assertEq32("bytes 1", "bytes 2"); 95 | emit log("\n"); 96 | assertEq32("bytes 1", "bytes 2", err); 97 | 98 | emit log("\n## assertEq(bytes32,bytes32)\n"); 99 | assertEq32("bytes 1", "bytes 2"); 100 | emit log("\n"); 101 | assertEq32("bytes 1", "bytes 2", err); 102 | 103 | emit log("\n## assertEq(uint,uint)\n"); 104 | assertEq(uint(0), 1); 105 | emit log("\n"); 106 | assertEq(uint(0), 1, err); 107 | 108 | emit log("\n## assertEq(int,int)\n"); 109 | assertEq(-1, -2); 110 | emit log("\n"); 111 | assertEq(-1, -2, err); 112 | 113 | emit log("\n## assertEqDecimal(int,int,uint)\n"); 114 | assertEqDecimal(-1.0e18, -1.1e18, 18); 115 | emit log("\n"); 116 | assertEqDecimal(-1.0e18, -1.1e18, 18, err); 117 | 118 | emit log("\n## assertEqDecimal(uint,uint,uint)\n"); 119 | assertEqDecimal(uint(1.0e18), 1.1e18, 18); 120 | emit log("\n"); 121 | assertEqDecimal(uint(1.0e18), 1.1e18, 18, err); 122 | 123 | emit log("\n## assertGt(uint,uint)\n"); 124 | assertGt(uint(0), 0); 125 | emit log("\n"); 126 | assertGt(uint(0), 0, err); 127 | 128 | emit log("\n## assertGt(int,int)\n"); 129 | assertGt(-1, -1); 130 | emit log("\n"); 131 | assertGt(-1, -1, err); 132 | 133 | emit log("\n## assertGtDecimal(int,int,uint)\n"); 134 | assertGtDecimal(-2.0e18, -1.1e18, 18); 135 | emit log("\n"); 136 | assertGtDecimal(-2.0e18, -1.1e18, 18, err); 137 | 138 | emit log("\n## assertGtDecimal(uint,uint,uint)\n"); 139 | assertGtDecimal(uint(1.0e18), 1.1e18, 18); 140 | emit log("\n"); 141 | assertGtDecimal(uint(1.0e18), 1.1e18, 18, err); 142 | 143 | emit log("\n## assertGe(uint,uint)\n"); 144 | assertGe(uint(0), 1); 145 | emit log("\n"); 146 | assertGe(uint(0), 1, err); 147 | 148 | emit log("\n## assertGe(int,int)\n"); 149 | assertGe(-1, 0); 150 | emit log("\n"); 151 | assertGe(-1, 0, err); 152 | 153 | emit log("\n## assertGeDecimal(int,int,uint)\n"); 154 | assertGeDecimal(-2.0e18, -1.1e18, 18); 155 | emit log("\n"); 156 | assertGeDecimal(-2.0e18, -1.1e18, 18, err); 157 | 158 | emit log("\n## assertGeDecimal(uint,uint,uint)\n"); 159 | assertGeDecimal(uint(1.0e18), 1.1e18, 18); 160 | emit log("\n"); 161 | assertGeDecimal(uint(1.0e18), 1.1e18, 18, err); 162 | 163 | emit log("\n## assertLt(uint,uint)\n"); 164 | assertLt(uint(0), 0); 165 | emit log("\n"); 166 | assertLt(uint(0), 0, err); 167 | 168 | emit log("\n## assertLt(int,int)\n"); 169 | assertLt(-1, -1); 170 | emit log("\n"); 171 | assertLt(-1, -1, err); 172 | 173 | emit log("\n## assertLtDecimal(int,int,uint)\n"); 174 | assertLtDecimal(-1.0e18, -1.1e18, 18); 175 | emit log("\n"); 176 | assertLtDecimal(-1.0e18, -1.1e18, 18, err); 177 | 178 | emit log("\n## assertLtDecimal(uint,uint,uint)\n"); 179 | assertLtDecimal(uint(2.0e18), 1.1e18, 18); 180 | emit log("\n"); 181 | assertLtDecimal(uint(2.0e18), 1.1e18, 18, err); 182 | 183 | emit log("\n## assertLe(uint,uint)\n"); 184 | assertLe(uint(1), 0); 185 | emit log("\n"); 186 | assertLe(uint(1), 0, err); 187 | 188 | emit log("\n## assertLe(int,int)\n"); 189 | assertLe(0, -1); 190 | emit log("\n"); 191 | assertLe(0, -1, err); 192 | 193 | emit log("\n## assertLeDecimal(int,int,uint)\n"); 194 | assertLeDecimal(-1.0e18, -1.1e18, 18); 195 | emit log("\n"); 196 | assertLeDecimal(-1.0e18, -1.1e18, 18, err); 197 | 198 | emit log("\n## assertLeDecimal(uint,uint,uint)\n"); 199 | assertLeDecimal(uint(2.0e18), 1.1e18, 18); 200 | emit log("\n"); 201 | assertLeDecimal(uint(2.0e18), 1.1e18, 18, err); 202 | 203 | emit log("\n## assertEq(string,string)\n"); 204 | string memory s1 = "string 1"; 205 | string memory s2 = "string 2"; 206 | assertEq(s1, s2); 207 | emit log("\n"); 208 | assertEq(s1, s2, err); 209 | 210 | emit log("\n## assertEq0(bytes,bytes)\n"); 211 | assertEq0(hex"abcdef01", hex"abcdef02"); 212 | emit log("\n"); 213 | assertEq0(hex"abcdef01", hex"abcdef02", err); 214 | } 215 | } 216 | 217 | contract DemoTestWithSetUp { 218 | function setUp() public { 219 | } 220 | function test_pass() public pure { 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /EIP4337TestCase/lib/forge-std/lib/ds-test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ds-test", 3 | "version": "1.0.0", 4 | "description": "Assertions, equality checks and other test helpers ", 5 | "bugs": "https://github.com/dapphub/ds-test/issues", 6 | "license": "GPL-3.0", 7 | "author": "Contributors to ds-test", 8 | "files": [ 9 | "src/*" 10 | ], 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/dapphub/ds-test.git" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /EIP4337TestCase/lib/forge-std/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "forge-std", 3 | "version": "1.5.6", 4 | "description": "Forge Standard Library is a collection of helpful contracts and libraries for use with Forge and Foundry.", 5 | "homepage": "https://book.getfoundry.sh/forge/forge-std", 6 | "bugs": "https://github.com/foundry-rs/forge-std/issues", 7 | "license": "(Apache-2.0 OR MIT)", 8 | "author": "Contributors to Forge Standard Library", 9 | "files": [ 10 | "src/**/*" 11 | ], 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/foundry-rs/forge-std.git" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /EIP4337TestCase/lib/forge-std/src/Base.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2 <0.9.0; 3 | 4 | import {StdStorage} from "./StdStorage.sol"; 5 | import {Vm, VmSafe} from "./Vm.sol"; 6 | 7 | abstract contract CommonBase { 8 | // Cheat code address, 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D. 9 | address internal constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code")))); 10 | // console.sol and console2.sol work by executing a staticcall to this address. 11 | address internal constant CONSOLE = 0x000000000000000000636F6e736F6c652e6c6f67; 12 | // Used when deploying with create2, https://github.com/Arachnid/deterministic-deployment-proxy. 13 | address internal constant CREATE2_FACTORY = 0x4e59b44847b379578588920cA78FbF26c0B4956C; 14 | // Default address for tx.origin and msg.sender, 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38. 15 | address internal constant DEFAULT_SENDER = address(uint160(uint256(keccak256("foundry default caller")))); 16 | // Address of the test contract, deployed by the DEFAULT_SENDER. 17 | address internal constant DEFAULT_TEST_CONTRACT = 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f; 18 | // Deterministic deployment address of the Multicall3 contract. 19 | address internal constant MULTICALL3_ADDRESS = 0xcA11bde05977b3631167028862bE2a173976CA11; 20 | // The order of the secp256k1 curve. 21 | uint256 internal constant SECP256K1_ORDER = 22 | 115792089237316195423570985008687907852837564279074904382605163141518161494337; 23 | 24 | uint256 internal constant UINT256_MAX = 25 | 115792089237316195423570985008687907853269984665640564039457584007913129639935; 26 | 27 | Vm internal constant vm = Vm(VM_ADDRESS); 28 | StdStorage internal stdstore; 29 | } 30 | 31 | abstract contract TestBase is CommonBase {} 32 | 33 | abstract contract ScriptBase is CommonBase { 34 | VmSafe internal constant vmSafe = VmSafe(VM_ADDRESS); 35 | } 36 | -------------------------------------------------------------------------------- /EIP4337TestCase/lib/forge-std/src/Script.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2 <0.9.0; 3 | 4 | // 💬 ABOUT 5 | // Standard Library's default Script. 6 | 7 | // 🧩 MODULES 8 | import {ScriptBase} from "./Base.sol"; 9 | import {console} from "./console.sol"; 10 | import {console2} from "./console2.sol"; 11 | import {StdChains} from "./StdChains.sol"; 12 | import {StdCheatsSafe} from "./StdCheats.sol"; 13 | import {stdJson} from "./StdJson.sol"; 14 | import {stdMath} from "./StdMath.sol"; 15 | import {StdStorage, stdStorageSafe} from "./StdStorage.sol"; 16 | import {StdUtils} from "./StdUtils.sol"; 17 | import {VmSafe} from "./Vm.sol"; 18 | 19 | // 📦 BOILERPLATE 20 | import {ScriptBase} from "./Base.sol"; 21 | 22 | // ⭐️ SCRIPT 23 | abstract contract Script is StdChains, StdCheatsSafe, StdUtils, ScriptBase { 24 | // Note: IS_SCRIPT() must return true. 25 | bool public IS_SCRIPT = true; 26 | } 27 | -------------------------------------------------------------------------------- /EIP4337TestCase/lib/forge-std/src/StdChains.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2 <0.9.0; 3 | 4 | pragma experimental ABIEncoderV2; 5 | 6 | import {VmSafe} from "./Vm.sol"; 7 | 8 | /** 9 | * StdChains provides information about EVM compatible chains that can be used in scripts/tests. 10 | * For each chain, the chain's name, chain ID, and a default RPC URL are provided. Chains are 11 | * identified by their alias, which is the same as the alias in the `[rpc_endpoints]` section of 12 | * the `foundry.toml` file. For best UX, ensure the alias in the `foundry.toml` file match the 13 | * alias used in this contract, which can be found as the first argument to the 14 | * `setChainWithDefaultRpcUrl` call in the `initializeStdChains` function. 15 | * 16 | * There are two main ways to use this contract: 17 | * 1. Set a chain with `setChain(string memory chainAlias, ChainData memory chain)` or 18 | * `setChain(string memory chainAlias, Chain memory chain)` 19 | * 2. Get a chain with `getChain(string memory chainAlias)` or `getChain(uint256 chainId)`. 20 | * 21 | * The first time either of those are used, chains are initialized with the default set of RPC URLs. 22 | * This is done in `initializeStdChains`, which uses `setChainWithDefaultRpcUrl`. Defaults are recorded in 23 | * `defaultRpcUrls`. 24 | * 25 | * The `setChain` function is straightforward, and it simply saves off the given chain data. 26 | * 27 | * The `getChain` methods use `getChainWithUpdatedRpcUrl` to return a chain. For example, let's say 28 | * we want to retrieve the RPC URL for `mainnet`: 29 | * - If you have specified data with `setChain`, it will return that. 30 | * - If you have configured a mainnet RPC URL in `foundry.toml`, it will return the URL, provided it 31 | * is valid (e.g. a URL is specified, or an environment variable is given and exists). 32 | * - If neither of the above conditions is met, the default data is returned. 33 | * 34 | * Summarizing the above, the prioritization hierarchy is `setChain` -> `foundry.toml` -> environment variable -> defaults. 35 | */ 36 | abstract contract StdChains { 37 | VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); 38 | 39 | bool private stdChainsInitialized; 40 | 41 | struct ChainData { 42 | string name; 43 | uint256 chainId; 44 | string rpcUrl; 45 | } 46 | 47 | struct Chain { 48 | // The chain name. 49 | string name; 50 | // The chain's Chain ID. 51 | uint256 chainId; 52 | // The chain's alias. (i.e. what gets specified in `foundry.toml`). 53 | string chainAlias; 54 | // A default RPC endpoint for this chain. 55 | // NOTE: This default RPC URL is included for convenience to facilitate quick tests and 56 | // experimentation. Do not use this RPC URL for production test suites, CI, or other heavy 57 | // usage as you will be throttled and this is a disservice to others who need this endpoint. 58 | string rpcUrl; 59 | } 60 | 61 | // Maps from the chain's alias (matching the alias in the `foundry.toml` file) to chain data. 62 | mapping(string => Chain) private chains; 63 | // Maps from the chain's alias to it's default RPC URL. 64 | mapping(string => string) private defaultRpcUrls; 65 | // Maps from a chain ID to it's alias. 66 | mapping(uint256 => string) private idToAlias; 67 | 68 | bool private fallbackToDefaultRpcUrls = true; 69 | 70 | // The RPC URL will be fetched from config or defaultRpcUrls if possible. 71 | function getChain(string memory chainAlias) internal virtual returns (Chain memory chain) { 72 | require(bytes(chainAlias).length != 0, "StdChains getChain(string): Chain alias cannot be the empty string."); 73 | 74 | initializeStdChains(); 75 | chain = chains[chainAlias]; 76 | require( 77 | chain.chainId != 0, 78 | string(abi.encodePacked("StdChains getChain(string): Chain with alias \"", chainAlias, "\" not found.")) 79 | ); 80 | 81 | chain = getChainWithUpdatedRpcUrl(chainAlias, chain); 82 | } 83 | 84 | function getChain(uint256 chainId) internal virtual returns (Chain memory chain) { 85 | require(chainId != 0, "StdChains getChain(uint256): Chain ID cannot be 0."); 86 | initializeStdChains(); 87 | string memory chainAlias = idToAlias[chainId]; 88 | 89 | chain = chains[chainAlias]; 90 | 91 | require( 92 | chain.chainId != 0, 93 | string(abi.encodePacked("StdChains getChain(uint256): Chain with ID ", vm.toString(chainId), " not found.")) 94 | ); 95 | 96 | chain = getChainWithUpdatedRpcUrl(chainAlias, chain); 97 | } 98 | 99 | // set chain info, with priority to argument's rpcUrl field. 100 | function setChain(string memory chainAlias, ChainData memory chain) internal virtual { 101 | require( 102 | bytes(chainAlias).length != 0, 103 | "StdChains setChain(string,ChainData): Chain alias cannot be the empty string." 104 | ); 105 | 106 | require(chain.chainId != 0, "StdChains setChain(string,ChainData): Chain ID cannot be 0."); 107 | 108 | initializeStdChains(); 109 | string memory foundAlias = idToAlias[chain.chainId]; 110 | 111 | require( 112 | bytes(foundAlias).length == 0 || keccak256(bytes(foundAlias)) == keccak256(bytes(chainAlias)), 113 | string( 114 | abi.encodePacked( 115 | "StdChains setChain(string,ChainData): Chain ID ", 116 | vm.toString(chain.chainId), 117 | " already used by \"", 118 | foundAlias, 119 | "\"." 120 | ) 121 | ) 122 | ); 123 | 124 | uint256 oldChainId = chains[chainAlias].chainId; 125 | delete idToAlias[oldChainId]; 126 | 127 | chains[chainAlias] = 128 | Chain({name: chain.name, chainId: chain.chainId, chainAlias: chainAlias, rpcUrl: chain.rpcUrl}); 129 | idToAlias[chain.chainId] = chainAlias; 130 | } 131 | 132 | // set chain info, with priority to argument's rpcUrl field. 133 | function setChain(string memory chainAlias, Chain memory chain) internal virtual { 134 | setChain(chainAlias, ChainData({name: chain.name, chainId: chain.chainId, rpcUrl: chain.rpcUrl})); 135 | } 136 | 137 | function _toUpper(string memory str) private pure returns (string memory) { 138 | bytes memory strb = bytes(str); 139 | bytes memory copy = new bytes(strb.length); 140 | for (uint256 i = 0; i < strb.length; i++) { 141 | bytes1 b = strb[i]; 142 | if (b >= 0x61 && b <= 0x7A) { 143 | copy[i] = bytes1(uint8(b) - 32); 144 | } else { 145 | copy[i] = b; 146 | } 147 | } 148 | return string(copy); 149 | } 150 | 151 | // lookup rpcUrl, in descending order of priority: 152 | // current -> config (foundry.toml) -> environment variable -> default 153 | function getChainWithUpdatedRpcUrl(string memory chainAlias, Chain memory chain) private returns (Chain memory) { 154 | if (bytes(chain.rpcUrl).length == 0) { 155 | try vm.rpcUrl(chainAlias) returns (string memory configRpcUrl) { 156 | chain.rpcUrl = configRpcUrl; 157 | } catch (bytes memory err) { 158 | string memory envName = string(abi.encodePacked(_toUpper(chainAlias), "_RPC_URL")); 159 | if (fallbackToDefaultRpcUrls) { 160 | chain.rpcUrl = vm.envOr(envName, defaultRpcUrls[chainAlias]); 161 | } else { 162 | chain.rpcUrl = vm.envString(envName); 163 | } 164 | // distinguish 'not found' from 'cannot read' 165 | bytes memory notFoundError = 166 | abi.encodeWithSignature("CheatCodeError", string(abi.encodePacked("invalid rpc url ", chainAlias))); 167 | if (keccak256(notFoundError) != keccak256(err) || bytes(chain.rpcUrl).length == 0) { 168 | /// @solidity memory-safe-assembly 169 | assembly { 170 | revert(add(32, err), mload(err)) 171 | } 172 | } 173 | } 174 | } 175 | return chain; 176 | } 177 | 178 | function setFallbackToDefaultRpcUrls(bool useDefault) internal { 179 | fallbackToDefaultRpcUrls = useDefault; 180 | } 181 | 182 | function initializeStdChains() private { 183 | if (stdChainsInitialized) return; 184 | 185 | stdChainsInitialized = true; 186 | 187 | // If adding an RPC here, make sure to test the default RPC URL in `testRpcs` 188 | setChainWithDefaultRpcUrl("anvil", ChainData("Anvil", 31337, "http://127.0.0.1:8545")); 189 | setChainWithDefaultRpcUrl( 190 | "mainnet", ChainData("Mainnet", 1, "https://mainnet.infura.io/v3/b9794ad1ddf84dfb8c34d6bb5dca2001") 191 | ); 192 | setChainWithDefaultRpcUrl( 193 | "goerli", ChainData("Goerli", 5, "https://goerli.infura.io/v3/b9794ad1ddf84dfb8c34d6bb5dca2001") 194 | ); 195 | setChainWithDefaultRpcUrl( 196 | "sepolia", ChainData("Sepolia", 11155111, "https://sepolia.infura.io/v3/b9794ad1ddf84dfb8c34d6bb5dca2001") 197 | ); 198 | setChainWithDefaultRpcUrl("optimism", ChainData("Optimism", 10, "https://mainnet.optimism.io")); 199 | setChainWithDefaultRpcUrl("optimism_goerli", ChainData("Optimism Goerli", 420, "https://goerli.optimism.io")); 200 | setChainWithDefaultRpcUrl("arbitrum_one", ChainData("Arbitrum One", 42161, "https://arb1.arbitrum.io/rpc")); 201 | setChainWithDefaultRpcUrl( 202 | "arbitrum_one_goerli", ChainData("Arbitrum One Goerli", 421613, "https://goerli-rollup.arbitrum.io/rpc") 203 | ); 204 | setChainWithDefaultRpcUrl("arbitrum_nova", ChainData("Arbitrum Nova", 42170, "https://nova.arbitrum.io/rpc")); 205 | setChainWithDefaultRpcUrl("polygon", ChainData("Polygon", 137, "https://polygon-rpc.com")); 206 | setChainWithDefaultRpcUrl( 207 | "polygon_mumbai", ChainData("Polygon Mumbai", 80001, "https://rpc-mumbai.maticvigil.com") 208 | ); 209 | setChainWithDefaultRpcUrl("avalanche", ChainData("Avalanche", 43114, "https://api.avax.network/ext/bc/C/rpc")); 210 | setChainWithDefaultRpcUrl( 211 | "avalanche_fuji", ChainData("Avalanche Fuji", 43113, "https://api.avax-test.network/ext/bc/C/rpc") 212 | ); 213 | setChainWithDefaultRpcUrl( 214 | "bnb_smart_chain", ChainData("BNB Smart Chain", 56, "https://bsc-dataseed1.binance.org") 215 | ); 216 | setChainWithDefaultRpcUrl( 217 | "bnb_smart_chain_testnet", 218 | ChainData("BNB Smart Chain Testnet", 97, "https://rpc.ankr.com/bsc_testnet_chapel") 219 | ); 220 | setChainWithDefaultRpcUrl("gnosis_chain", ChainData("Gnosis Chain", 100, "https://rpc.gnosischain.com")); 221 | } 222 | 223 | // set chain info, with priority to chainAlias' rpc url in foundry.toml 224 | function setChainWithDefaultRpcUrl(string memory chainAlias, ChainData memory chain) private { 225 | string memory rpcUrl = chain.rpcUrl; 226 | defaultRpcUrls[chainAlias] = rpcUrl; 227 | chain.rpcUrl = ""; 228 | setChain(chainAlias, chain); 229 | chain.rpcUrl = rpcUrl; // restore argument 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /EIP4337TestCase/lib/forge-std/src/StdError.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // Panics work for versions >=0.8.0, but we lowered the pragma to make this compatible with Test 3 | pragma solidity >=0.6.2 <0.9.0; 4 | 5 | library stdError { 6 | bytes public constant assertionError = abi.encodeWithSignature("Panic(uint256)", 0x01); 7 | bytes public constant arithmeticError = abi.encodeWithSignature("Panic(uint256)", 0x11); 8 | bytes public constant divisionError = abi.encodeWithSignature("Panic(uint256)", 0x12); 9 | bytes public constant enumConversionError = abi.encodeWithSignature("Panic(uint256)", 0x21); 10 | bytes public constant encodeStorageError = abi.encodeWithSignature("Panic(uint256)", 0x22); 11 | bytes public constant popError = abi.encodeWithSignature("Panic(uint256)", 0x31); 12 | bytes public constant indexOOBError = abi.encodeWithSignature("Panic(uint256)", 0x32); 13 | bytes public constant memOverflowError = abi.encodeWithSignature("Panic(uint256)", 0x41); 14 | bytes public constant zeroVarError = abi.encodeWithSignature("Panic(uint256)", 0x51); 15 | } 16 | -------------------------------------------------------------------------------- /EIP4337TestCase/lib/forge-std/src/StdInvariant.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2 <0.9.0; 3 | 4 | pragma experimental ABIEncoderV2; 5 | 6 | contract StdInvariant { 7 | struct FuzzSelector { 8 | address addr; 9 | bytes4[] selectors; 10 | } 11 | 12 | address[] private _excludedContracts; 13 | address[] private _excludedSenders; 14 | address[] private _targetedContracts; 15 | address[] private _targetedSenders; 16 | 17 | string[] private _excludedArtifacts; 18 | string[] private _targetedArtifacts; 19 | 20 | FuzzSelector[] private _targetedArtifactSelectors; 21 | FuzzSelector[] private _targetedSelectors; 22 | 23 | // Functions for users: 24 | // These are intended to be called in tests. 25 | 26 | function excludeContract(address newExcludedContract_) internal { 27 | _excludedContracts.push(newExcludedContract_); 28 | } 29 | 30 | function excludeSender(address newExcludedSender_) internal { 31 | _excludedSenders.push(newExcludedSender_); 32 | } 33 | 34 | function excludeArtifact(string memory newExcludedArtifact_) internal { 35 | _excludedArtifacts.push(newExcludedArtifact_); 36 | } 37 | 38 | function targetArtifact(string memory newTargetedArtifact_) internal { 39 | _targetedArtifacts.push(newTargetedArtifact_); 40 | } 41 | 42 | function targetArtifactSelector(FuzzSelector memory newTargetedArtifactSelector_) internal { 43 | _targetedArtifactSelectors.push(newTargetedArtifactSelector_); 44 | } 45 | 46 | function targetContract(address newTargetedContract_) internal { 47 | _targetedContracts.push(newTargetedContract_); 48 | } 49 | 50 | function targetSelector(FuzzSelector memory newTargetedSelector_) internal { 51 | _targetedSelectors.push(newTargetedSelector_); 52 | } 53 | 54 | function targetSender(address newTargetedSender_) internal { 55 | _targetedSenders.push(newTargetedSender_); 56 | } 57 | 58 | // Functions for forge: 59 | // These are called by forge to run invariant tests and don't need to be called in tests. 60 | 61 | function excludeArtifacts() public view returns (string[] memory excludedArtifacts_) { 62 | excludedArtifacts_ = _excludedArtifacts; 63 | } 64 | 65 | function excludeContracts() public view returns (address[] memory excludedContracts_) { 66 | excludedContracts_ = _excludedContracts; 67 | } 68 | 69 | function excludeSenders() public view returns (address[] memory excludedSenders_) { 70 | excludedSenders_ = _excludedSenders; 71 | } 72 | 73 | function targetArtifacts() public view returns (string[] memory targetedArtifacts_) { 74 | targetedArtifacts_ = _targetedArtifacts; 75 | } 76 | 77 | function targetArtifactSelectors() public view returns (FuzzSelector[] memory targetedArtifactSelectors_) { 78 | targetedArtifactSelectors_ = _targetedArtifactSelectors; 79 | } 80 | 81 | function targetContracts() public view returns (address[] memory targetedContracts_) { 82 | targetedContracts_ = _targetedContracts; 83 | } 84 | 85 | function targetSelectors() public view returns (FuzzSelector[] memory targetedSelectors_) { 86 | targetedSelectors_ = _targetedSelectors; 87 | } 88 | 89 | function targetSenders() public view returns (address[] memory targetedSenders_) { 90 | targetedSenders_ = _targetedSenders; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /EIP4337TestCase/lib/forge-std/src/StdJson.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.0 <0.9.0; 3 | 4 | pragma experimental ABIEncoderV2; 5 | 6 | import {VmSafe} from "./Vm.sol"; 7 | 8 | // Helpers for parsing and writing JSON files 9 | // To parse: 10 | // ``` 11 | // using stdJson for string; 12 | // string memory json = vm.readFile("some_peth"); 13 | // json.parseUint(""); 14 | // ``` 15 | // To write: 16 | // ``` 17 | // using stdJson for string; 18 | // string memory json = "deploymentArtifact"; 19 | // Contract contract = new Contract(); 20 | // json.serialize("contractAddress", address(contract)); 21 | // json = json.serialize("deploymentTimes", uint(1)); 22 | // // store the stringified JSON to the 'json' variable we have been using as a key 23 | // // as we won't need it any longer 24 | // string memory json2 = "finalArtifact"; 25 | // string memory final = json2.serialize("depArtifact", json); 26 | // final.write(""); 27 | // ``` 28 | 29 | library stdJson { 30 | VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); 31 | 32 | function parseRaw(string memory json, string memory key) internal pure returns (bytes memory) { 33 | return vm.parseJson(json, key); 34 | } 35 | 36 | function readUint(string memory json, string memory key) internal returns (uint256) { 37 | return vm.parseJsonUint(json, key); 38 | } 39 | 40 | function readUintArray(string memory json, string memory key) internal returns (uint256[] memory) { 41 | return vm.parseJsonUintArray(json, key); 42 | } 43 | 44 | function readInt(string memory json, string memory key) internal returns (int256) { 45 | return vm.parseJsonInt(json, key); 46 | } 47 | 48 | function readIntArray(string memory json, string memory key) internal returns (int256[] memory) { 49 | return vm.parseJsonIntArray(json, key); 50 | } 51 | 52 | function readBytes32(string memory json, string memory key) internal returns (bytes32) { 53 | return vm.parseJsonBytes32(json, key); 54 | } 55 | 56 | function readBytes32Array(string memory json, string memory key) internal returns (bytes32[] memory) { 57 | return vm.parseJsonBytes32Array(json, key); 58 | } 59 | 60 | function readString(string memory json, string memory key) internal returns (string memory) { 61 | return vm.parseJsonString(json, key); 62 | } 63 | 64 | function readStringArray(string memory json, string memory key) internal returns (string[] memory) { 65 | return vm.parseJsonStringArray(json, key); 66 | } 67 | 68 | function readAddress(string memory json, string memory key) internal returns (address) { 69 | return vm.parseJsonAddress(json, key); 70 | } 71 | 72 | function readAddressArray(string memory json, string memory key) internal returns (address[] memory) { 73 | return vm.parseJsonAddressArray(json, key); 74 | } 75 | 76 | function readBool(string memory json, string memory key) internal returns (bool) { 77 | return vm.parseJsonBool(json, key); 78 | } 79 | 80 | function readBoolArray(string memory json, string memory key) internal returns (bool[] memory) { 81 | return vm.parseJsonBoolArray(json, key); 82 | } 83 | 84 | function readBytes(string memory json, string memory key) internal returns (bytes memory) { 85 | return vm.parseJsonBytes(json, key); 86 | } 87 | 88 | function readBytesArray(string memory json, string memory key) internal returns (bytes[] memory) { 89 | return vm.parseJsonBytesArray(json, key); 90 | } 91 | 92 | function serialize(string memory jsonKey, string memory key, bool value) internal returns (string memory) { 93 | return vm.serializeBool(jsonKey, key, value); 94 | } 95 | 96 | function serialize(string memory jsonKey, string memory key, bool[] memory value) 97 | internal 98 | returns (string memory) 99 | { 100 | return vm.serializeBool(jsonKey, key, value); 101 | } 102 | 103 | function serialize(string memory jsonKey, string memory key, uint256 value) internal returns (string memory) { 104 | return vm.serializeUint(jsonKey, key, value); 105 | } 106 | 107 | function serialize(string memory jsonKey, string memory key, uint256[] memory value) 108 | internal 109 | returns (string memory) 110 | { 111 | return vm.serializeUint(jsonKey, key, value); 112 | } 113 | 114 | function serialize(string memory jsonKey, string memory key, int256 value) internal returns (string memory) { 115 | return vm.serializeInt(jsonKey, key, value); 116 | } 117 | 118 | function serialize(string memory jsonKey, string memory key, int256[] memory value) 119 | internal 120 | returns (string memory) 121 | { 122 | return vm.serializeInt(jsonKey, key, value); 123 | } 124 | 125 | function serialize(string memory jsonKey, string memory key, address value) internal returns (string memory) { 126 | return vm.serializeAddress(jsonKey, key, value); 127 | } 128 | 129 | function serialize(string memory jsonKey, string memory key, address[] memory value) 130 | internal 131 | returns (string memory) 132 | { 133 | return vm.serializeAddress(jsonKey, key, value); 134 | } 135 | 136 | function serialize(string memory jsonKey, string memory key, bytes32 value) internal returns (string memory) { 137 | return vm.serializeBytes32(jsonKey, key, value); 138 | } 139 | 140 | function serialize(string memory jsonKey, string memory key, bytes32[] memory value) 141 | internal 142 | returns (string memory) 143 | { 144 | return vm.serializeBytes32(jsonKey, key, value); 145 | } 146 | 147 | function serialize(string memory jsonKey, string memory key, bytes memory value) internal returns (string memory) { 148 | return vm.serializeBytes(jsonKey, key, value); 149 | } 150 | 151 | function serialize(string memory jsonKey, string memory key, bytes[] memory value) 152 | internal 153 | returns (string memory) 154 | { 155 | return vm.serializeBytes(jsonKey, key, value); 156 | } 157 | 158 | function serialize(string memory jsonKey, string memory key, string memory value) 159 | internal 160 | returns (string memory) 161 | { 162 | return vm.serializeString(jsonKey, key, value); 163 | } 164 | 165 | function serialize(string memory jsonKey, string memory key, string[] memory value) 166 | internal 167 | returns (string memory) 168 | { 169 | return vm.serializeString(jsonKey, key, value); 170 | } 171 | 172 | function write(string memory jsonKey, string memory path) internal { 173 | vm.writeJson(jsonKey, path); 174 | } 175 | 176 | function write(string memory jsonKey, string memory path, string memory valueKey) internal { 177 | vm.writeJson(jsonKey, path, valueKey); 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /EIP4337TestCase/lib/forge-std/src/StdMath.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2 <0.9.0; 3 | 4 | library stdMath { 5 | int256 private constant INT256_MIN = -57896044618658097711785492504343953926634992332820282019728792003956564819968; 6 | 7 | function abs(int256 a) internal pure returns (uint256) { 8 | // Required or it will fail when `a = type(int256).min` 9 | if (a == INT256_MIN) { 10 | return 57896044618658097711785492504343953926634992332820282019728792003956564819968; 11 | } 12 | 13 | return uint256(a > 0 ? a : -a); 14 | } 15 | 16 | function delta(uint256 a, uint256 b) internal pure returns (uint256) { 17 | return a > b ? a - b : b - a; 18 | } 19 | 20 | function delta(int256 a, int256 b) internal pure returns (uint256) { 21 | // a and b are of the same sign 22 | // this works thanks to two's complement, the left-most bit is the sign bit 23 | if ((a ^ b) > -1) { 24 | return delta(abs(a), abs(b)); 25 | } 26 | 27 | // a and b are of opposite signs 28 | return abs(a) + abs(b); 29 | } 30 | 31 | function percentDelta(uint256 a, uint256 b) internal pure returns (uint256) { 32 | uint256 absDelta = delta(a, b); 33 | 34 | return absDelta * 1e18 / b; 35 | } 36 | 37 | function percentDelta(int256 a, int256 b) internal pure returns (uint256) { 38 | uint256 absDelta = delta(a, b); 39 | uint256 absB = abs(b); 40 | 41 | return absDelta * 1e18 / absB; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /EIP4337TestCase/lib/forge-std/src/StdUtils.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2 <0.9.0; 3 | 4 | pragma experimental ABIEncoderV2; 5 | 6 | import {IMulticall3} from "./interfaces/IMulticall3.sol"; 7 | import {VmSafe} from "./Vm.sol"; 8 | 9 | abstract contract StdUtils { 10 | /*////////////////////////////////////////////////////////////////////////// 11 | CONSTANTS 12 | //////////////////////////////////////////////////////////////////////////*/ 13 | 14 | IMulticall3 private constant multicall = IMulticall3(0xcA11bde05977b3631167028862bE2a173976CA11); 15 | VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); 16 | address private constant CONSOLE2_ADDRESS = 0x000000000000000000636F6e736F6c652e6c6f67; 17 | uint256 private constant INT256_MIN_ABS = 18 | 57896044618658097711785492504343953926634992332820282019728792003956564819968; 19 | uint256 private constant SECP256K1_ORDER = 20 | 115792089237316195423570985008687907852837564279074904382605163141518161494337; 21 | uint256 private constant UINT256_MAX = 22 | 115792089237316195423570985008687907853269984665640564039457584007913129639935; 23 | 24 | // Used by default when deploying with create2, https://github.com/Arachnid/deterministic-deployment-proxy. 25 | address private constant CREATE2_FACTORY = 0x4e59b44847b379578588920cA78FbF26c0B4956C; 26 | 27 | /*////////////////////////////////////////////////////////////////////////// 28 | INTERNAL FUNCTIONS 29 | //////////////////////////////////////////////////////////////////////////*/ 30 | 31 | function _bound(uint256 x, uint256 min, uint256 max) internal pure virtual returns (uint256 result) { 32 | require(min <= max, "StdUtils bound(uint256,uint256,uint256): Max is less than min."); 33 | // If x is between min and max, return x directly. This is to ensure that dictionary values 34 | // do not get shifted if the min is nonzero. More info: https://github.com/foundry-rs/forge-std/issues/188 35 | if (x >= min && x <= max) return x; 36 | 37 | uint256 size = max - min + 1; 38 | 39 | // If the value is 0, 1, 2, 3, wrap that to min, min+1, min+2, min+3. Similarly for the UINT256_MAX side. 40 | // This helps ensure coverage of the min/max values. 41 | if (x <= 3 && size > x) return min + x; 42 | if (x >= UINT256_MAX - 3 && size > UINT256_MAX - x) return max - (UINT256_MAX - x); 43 | 44 | // Otherwise, wrap x into the range [min, max], i.e. the range is inclusive. 45 | if (x > max) { 46 | uint256 diff = x - max; 47 | uint256 rem = diff % size; 48 | if (rem == 0) return max; 49 | result = min + rem - 1; 50 | } else if (x < min) { 51 | uint256 diff = min - x; 52 | uint256 rem = diff % size; 53 | if (rem == 0) return min; 54 | result = max - rem + 1; 55 | } 56 | } 57 | 58 | function bound(uint256 x, uint256 min, uint256 max) internal view virtual returns (uint256 result) { 59 | result = _bound(x, min, max); 60 | console2_log("Bound Result", result); 61 | } 62 | 63 | function _bound(int256 x, int256 min, int256 max) internal pure virtual returns (int256 result) { 64 | require(min <= max, "StdUtils bound(int256,int256,int256): Max is less than min."); 65 | 66 | // Shifting all int256 values to uint256 to use _bound function. The range of two types are: 67 | // int256 : -(2**255) ~ (2**255 - 1) 68 | // uint256: 0 ~ (2**256 - 1) 69 | // So, add 2**255, INT256_MIN_ABS to the integer values. 70 | // 71 | // If the given integer value is -2**255, we cannot use `-uint256(-x)` because of the overflow. 72 | // So, use `~uint256(x) + 1` instead. 73 | uint256 _x = x < 0 ? (INT256_MIN_ABS - ~uint256(x) - 1) : (uint256(x) + INT256_MIN_ABS); 74 | uint256 _min = min < 0 ? (INT256_MIN_ABS - ~uint256(min) - 1) : (uint256(min) + INT256_MIN_ABS); 75 | uint256 _max = max < 0 ? (INT256_MIN_ABS - ~uint256(max) - 1) : (uint256(max) + INT256_MIN_ABS); 76 | 77 | uint256 y = _bound(_x, _min, _max); 78 | 79 | // To move it back to int256 value, subtract INT256_MIN_ABS at here. 80 | result = y < INT256_MIN_ABS ? int256(~(INT256_MIN_ABS - y) + 1) : int256(y - INT256_MIN_ABS); 81 | } 82 | 83 | function bound(int256 x, int256 min, int256 max) internal view virtual returns (int256 result) { 84 | result = _bound(x, min, max); 85 | console2_log("Bound result", vm.toString(result)); 86 | } 87 | 88 | function boundPrivateKey(uint256 privateKey) internal view virtual returns (uint256 result) { 89 | result = _bound(privateKey, 1, SECP256K1_ORDER - 1); 90 | } 91 | 92 | function bytesToUint(bytes memory b) internal pure virtual returns (uint256) { 93 | require(b.length <= 32, "StdUtils bytesToUint(bytes): Bytes length exceeds 32."); 94 | return abi.decode(abi.encodePacked(new bytes(32 - b.length), b), (uint256)); 95 | } 96 | 97 | /// @dev Compute the address a contract will be deployed at for a given deployer address and nonce 98 | /// @notice adapted from Solmate implementation (https://github.com/Rari-Capital/solmate/blob/main/src/utils/LibRLP.sol) 99 | function computeCreateAddress(address deployer, uint256 nonce) internal pure virtual returns (address) { 100 | // forgefmt: disable-start 101 | // The integer zero is treated as an empty byte string, and as a result it only has a length prefix, 0x80, computed via 0x80 + 0. 102 | // A one byte integer uses its own value as its length prefix, there is no additional "0x80 + length" prefix that comes before it. 103 | if (nonce == 0x00) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), deployer, bytes1(0x80)))); 104 | if (nonce <= 0x7f) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), deployer, uint8(nonce)))); 105 | 106 | // Nonces greater than 1 byte all follow a consistent encoding scheme, where each value is preceded by a prefix of 0x80 + length. 107 | if (nonce <= 2**8 - 1) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd7), bytes1(0x94), deployer, bytes1(0x81), uint8(nonce)))); 108 | if (nonce <= 2**16 - 1) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd8), bytes1(0x94), deployer, bytes1(0x82), uint16(nonce)))); 109 | if (nonce <= 2**24 - 1) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd9), bytes1(0x94), deployer, bytes1(0x83), uint24(nonce)))); 110 | // forgefmt: disable-end 111 | 112 | // More details about RLP encoding can be found here: https://eth.wiki/fundamentals/rlp 113 | // 0xda = 0xc0 (short RLP prefix) + 0x16 (length of: 0x94 ++ proxy ++ 0x84 ++ nonce) 114 | // 0x94 = 0x80 + 0x14 (0x14 = the length of an address, 20 bytes, in hex) 115 | // 0x84 = 0x80 + 0x04 (0x04 = the bytes length of the nonce, 4 bytes, in hex) 116 | // We assume nobody can have a nonce large enough to require more than 32 bytes. 117 | return addressFromLast20Bytes( 118 | keccak256(abi.encodePacked(bytes1(0xda), bytes1(0x94), deployer, bytes1(0x84), uint32(nonce))) 119 | ); 120 | } 121 | 122 | function computeCreate2Address(bytes32 salt, bytes32 initcodeHash, address deployer) 123 | internal 124 | pure 125 | virtual 126 | returns (address) 127 | { 128 | return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xff), deployer, salt, initcodeHash))); 129 | } 130 | 131 | /// @dev returns the address of a contract created with CREATE2 using the default CREATE2 deployer 132 | function computeCreate2Address(bytes32 salt, bytes32 initCodeHash) internal pure returns (address) { 133 | return computeCreate2Address(salt, initCodeHash, CREATE2_FACTORY); 134 | } 135 | 136 | /// @dev returns the hash of the init code (creation code + no args) used in CREATE2 with no constructor arguments 137 | /// @param creationCode the creation code of a contract C, as returned by type(C).creationCode 138 | function hashInitCode(bytes memory creationCode) internal pure returns (bytes32) { 139 | return hashInitCode(creationCode, ""); 140 | } 141 | 142 | /// @dev returns the hash of the init code (creation code + ABI-encoded args) used in CREATE2 143 | /// @param creationCode the creation code of a contract C, as returned by type(C).creationCode 144 | /// @param args the ABI-encoded arguments to the constructor of C 145 | function hashInitCode(bytes memory creationCode, bytes memory args) internal pure returns (bytes32) { 146 | return keccak256(abi.encodePacked(creationCode, args)); 147 | } 148 | 149 | // Performs a single call with Multicall3 to query the ERC-20 token balances of the given addresses. 150 | function getTokenBalances(address token, address[] memory addresses) 151 | internal 152 | virtual 153 | returns (uint256[] memory balances) 154 | { 155 | uint256 tokenCodeSize; 156 | assembly { 157 | tokenCodeSize := extcodesize(token) 158 | } 159 | require(tokenCodeSize > 0, "StdUtils getTokenBalances(address,address[]): Token address is not a contract."); 160 | 161 | // ABI encode the aggregate call to Multicall3. 162 | uint256 length = addresses.length; 163 | IMulticall3.Call[] memory calls = new IMulticall3.Call[](length); 164 | for (uint256 i = 0; i < length; ++i) { 165 | // 0x70a08231 = bytes4("balanceOf(address)")) 166 | calls[i] = IMulticall3.Call({target: token, callData: abi.encodeWithSelector(0x70a08231, (addresses[i]))}); 167 | } 168 | 169 | // Make the aggregate call. 170 | (, bytes[] memory returnData) = multicall.aggregate(calls); 171 | 172 | // ABI decode the return data and return the balances. 173 | balances = new uint256[](length); 174 | for (uint256 i = 0; i < length; ++i) { 175 | balances[i] = abi.decode(returnData[i], (uint256)); 176 | } 177 | } 178 | 179 | /*////////////////////////////////////////////////////////////////////////// 180 | PRIVATE FUNCTIONS 181 | //////////////////////////////////////////////////////////////////////////*/ 182 | 183 | function addressFromLast20Bytes(bytes32 bytesValue) private pure returns (address) { 184 | return address(uint160(uint256(bytesValue))); 185 | } 186 | 187 | // Used to prevent the compilation of console, which shortens the compilation time when console is not used elsewhere. 188 | 189 | function console2_log(string memory p0, uint256 p1) private view { 190 | (bool status,) = address(CONSOLE2_ADDRESS).staticcall(abi.encodeWithSignature("log(string,uint256)", p0, p1)); 191 | status; 192 | } 193 | 194 | function console2_log(string memory p0, string memory p1) private view { 195 | (bool status,) = address(CONSOLE2_ADDRESS).staticcall(abi.encodeWithSignature("log(string,string)", p0, p1)); 196 | status; 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /EIP4337TestCase/lib/forge-std/src/Test.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2 <0.9.0; 3 | 4 | pragma experimental ABIEncoderV2; 5 | 6 | // 💬 ABOUT 7 | // Standard Library's default Test 8 | 9 | // 🧩 MODULES 10 | import {console} from "./console.sol"; 11 | import {console2} from "./console2.sol"; 12 | import {StdAssertions} from "./StdAssertions.sol"; 13 | import {StdChains} from "./StdChains.sol"; 14 | import {StdCheats} from "./StdCheats.sol"; 15 | import {stdError} from "./StdError.sol"; 16 | import {StdInvariant} from "./StdInvariant.sol"; 17 | import {stdJson} from "./StdJson.sol"; 18 | import {stdMath} from "./StdMath.sol"; 19 | import {StdStorage, stdStorage} from "./StdStorage.sol"; 20 | import {StdUtils} from "./StdUtils.sol"; 21 | import {Vm} from "./Vm.sol"; 22 | import {StdStyle} from "./StdStyle.sol"; 23 | 24 | // 📦 BOILERPLATE 25 | import {TestBase} from "./Base.sol"; 26 | import {DSTest} from "ds-test/test.sol"; 27 | 28 | // ⭐️ TEST 29 | abstract contract Test is DSTest, StdAssertions, StdChains, StdCheats, StdInvariant, StdUtils, TestBase { 30 | // Note: IS_TEST() must return true. 31 | // Note: Must have failure system, https://github.com/dapphub/ds-test/blob/cd98eff28324bfac652e63a239a60632a761790b/src/test.sol#L39-L76. 32 | } 33 | -------------------------------------------------------------------------------- /EIP4337TestCase/lib/forge-std/src/interfaces/IERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2; 3 | 4 | /// @dev Interface of the ERC20 standard as defined in the EIP. 5 | /// @dev This includes the optional name, symbol, and decimals metadata. 6 | interface IERC20 { 7 | /// @dev Emitted when `value` tokens are moved from one account (`from`) to another (`to`). 8 | event Transfer(address indexed from, address indexed to, uint256 value); 9 | 10 | /// @dev Emitted when the allowance of a `spender` for an `owner` is set, where `value` 11 | /// is the new allowance. 12 | event Approval(address indexed owner, address indexed spender, uint256 value); 13 | 14 | /// @notice Returns the amount of tokens in existence. 15 | function totalSupply() external view returns (uint256); 16 | 17 | /// @notice Returns the amount of tokens owned by `account`. 18 | function balanceOf(address account) external view returns (uint256); 19 | 20 | /// @notice Moves `amount` tokens from the caller's account to `to`. 21 | function transfer(address to, uint256 amount) external returns (bool); 22 | 23 | /// @notice Returns the remaining number of tokens that `spender` is allowed 24 | /// to spend on behalf of `owner` 25 | function allowance(address owner, address spender) external view returns (uint256); 26 | 27 | /// @notice Sets `amount` as the allowance of `spender` over the caller's tokens. 28 | /// @dev Be aware of front-running risks: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 29 | function approve(address spender, uint256 amount) external returns (bool); 30 | 31 | /// @notice Moves `amount` tokens from `from` to `to` using the allowance mechanism. 32 | /// `amount` is then deducted from the caller's allowance. 33 | function transferFrom(address from, address to, uint256 amount) external returns (bool); 34 | 35 | /// @notice Returns the name of the token. 36 | function name() external view returns (string memory); 37 | 38 | /// @notice Returns the symbol of the token. 39 | function symbol() external view returns (string memory); 40 | 41 | /// @notice Returns the decimals places of the token. 42 | function decimals() external view returns (uint8); 43 | } 44 | -------------------------------------------------------------------------------- /EIP4337TestCase/lib/forge-std/src/interfaces/IMulticall3.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2 <0.9.0; 3 | 4 | pragma experimental ABIEncoderV2; 5 | 6 | interface IMulticall3 { 7 | struct Call { 8 | address target; 9 | bytes callData; 10 | } 11 | 12 | struct Call3 { 13 | address target; 14 | bool allowFailure; 15 | bytes callData; 16 | } 17 | 18 | struct Call3Value { 19 | address target; 20 | bool allowFailure; 21 | uint256 value; 22 | bytes callData; 23 | } 24 | 25 | struct Result { 26 | bool success; 27 | bytes returnData; 28 | } 29 | 30 | function aggregate(Call[] calldata calls) 31 | external 32 | payable 33 | returns (uint256 blockNumber, bytes[] memory returnData); 34 | 35 | function aggregate3(Call3[] calldata calls) external payable returns (Result[] memory returnData); 36 | 37 | function aggregate3Value(Call3Value[] calldata calls) external payable returns (Result[] memory returnData); 38 | 39 | function blockAndAggregate(Call[] calldata calls) 40 | external 41 | payable 42 | returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData); 43 | 44 | function getBasefee() external view returns (uint256 basefee); 45 | 46 | function getBlockHash(uint256 blockNumber) external view returns (bytes32 blockHash); 47 | 48 | function getBlockNumber() external view returns (uint256 blockNumber); 49 | 50 | function getChainId() external view returns (uint256 chainid); 51 | 52 | function getCurrentBlockCoinbase() external view returns (address coinbase); 53 | 54 | function getCurrentBlockDifficulty() external view returns (uint256 difficulty); 55 | 56 | function getCurrentBlockGasLimit() external view returns (uint256 gaslimit); 57 | 58 | function getCurrentBlockTimestamp() external view returns (uint256 timestamp); 59 | 60 | function getEthBalance(address addr) external view returns (uint256 balance); 61 | 62 | function getLastBlockHash() external view returns (bytes32 blockHash); 63 | 64 | function tryAggregate(bool requireSuccess, Call[] calldata calls) 65 | external 66 | payable 67 | returns (Result[] memory returnData); 68 | 69 | function tryBlockAndAggregate(bool requireSuccess, Call[] calldata calls) 70 | external 71 | payable 72 | returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData); 73 | } 74 | -------------------------------------------------------------------------------- /EIP4337TestCase/lib/forge-std/test/StdChains.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.7.0 <0.9.0; 3 | 4 | import "../src/Test.sol"; 5 | 6 | contract StdChainsTest is Test { 7 | function testChainRpcInitialization() public { 8 | // RPCs specified in `foundry.toml` should be updated. 9 | assertEq(getChain(1).rpcUrl, "https://mainnet.infura.io/v3/b1d3925804e74152b316ca7da97060d3"); 10 | assertEq(getChain("optimism_goerli").rpcUrl, "https://goerli.optimism.io/"); 11 | assertEq(getChain("arbitrum_one_goerli").rpcUrl, "https://goerli-rollup.arbitrum.io/rpc/"); 12 | 13 | // Environment variables should be the next fallback 14 | assertEq(getChain("arbitrum_nova").rpcUrl, "https://nova.arbitrum.io/rpc"); 15 | vm.setEnv("ARBITRUM_NOVA_RPC_URL", "myoverride"); 16 | assertEq(getChain("arbitrum_nova").rpcUrl, "myoverride"); 17 | vm.setEnv("ARBITRUM_NOVA_RPC_URL", "https://nova.arbitrum.io/rpc"); 18 | 19 | // Cannot override RPCs defined in `foundry.toml` 20 | vm.setEnv("MAINNET_RPC_URL", "myoverride2"); 21 | assertEq(getChain("mainnet").rpcUrl, "https://mainnet.infura.io/v3/b1d3925804e74152b316ca7da97060d3"); 22 | 23 | // Other RPCs should remain unchanged. 24 | assertEq(getChain(31337).rpcUrl, "http://127.0.0.1:8545"); 25 | assertEq(getChain("sepolia").rpcUrl, "https://sepolia.infura.io/v3/b9794ad1ddf84dfb8c34d6bb5dca2001"); 26 | } 27 | 28 | function testRpc(string memory rpcAlias) internal { 29 | string memory rpcUrl = getChain(rpcAlias).rpcUrl; 30 | vm.createSelectFork(rpcUrl); 31 | } 32 | 33 | // Ensure we can connect to the default RPC URL for each chain. 34 | // function testRpcs() public { 35 | // testRpc("mainnet"); 36 | // testRpc("goerli"); 37 | // testRpc("sepolia"); 38 | // testRpc("optimism"); 39 | // testRpc("optimism_goerli"); 40 | // testRpc("arbitrum_one"); 41 | // testRpc("arbitrum_one_goerli"); 42 | // testRpc("arbitrum_nova"); 43 | // testRpc("polygon"); 44 | // testRpc("polygon_mumbai"); 45 | // testRpc("avalanche"); 46 | // testRpc("avalanche_fuji"); 47 | // testRpc("bnb_smart_chain"); 48 | // testRpc("bnb_smart_chain_testnet"); 49 | // testRpc("gnosis_chain"); 50 | // } 51 | 52 | function testChainNoDefault() public { 53 | vm.expectRevert("StdChains getChain(string): Chain with alias \"does_not_exist\" not found."); 54 | getChain("does_not_exist"); 55 | } 56 | 57 | function testSetChainFirstFails() public { 58 | vm.expectRevert("StdChains setChain(string,ChainData): Chain ID 31337 already used by \"anvil\"."); 59 | setChain("anvil2", ChainData("Anvil", 31337, "URL")); 60 | } 61 | 62 | function testChainBubbleUp() public { 63 | setChain("needs_undefined_env_var", ChainData("", 123456789, "")); 64 | vm.expectRevert( 65 | "Failed to resolve env var `UNDEFINED_RPC_URL_PLACEHOLDER` in `${UNDEFINED_RPC_URL_PLACEHOLDER}`: environment variable not found" 66 | ); 67 | getChain("needs_undefined_env_var"); 68 | } 69 | 70 | function testCannotSetChain_ChainIdExists() public { 71 | setChain("custom_chain", ChainData("Custom Chain", 123456789, "https://custom.chain/")); 72 | 73 | vm.expectRevert('StdChains setChain(string,ChainData): Chain ID 123456789 already used by "custom_chain".'); 74 | 75 | setChain("another_custom_chain", ChainData("", 123456789, "")); 76 | } 77 | 78 | function testSetChain() public { 79 | setChain("custom_chain", ChainData("Custom Chain", 123456789, "https://custom.chain/")); 80 | Chain memory customChain = getChain("custom_chain"); 81 | assertEq(customChain.name, "Custom Chain"); 82 | assertEq(customChain.chainId, 123456789); 83 | assertEq(customChain.chainAlias, "custom_chain"); 84 | assertEq(customChain.rpcUrl, "https://custom.chain/"); 85 | Chain memory chainById = getChain(123456789); 86 | assertEq(chainById.name, customChain.name); 87 | assertEq(chainById.chainId, customChain.chainId); 88 | assertEq(chainById.chainAlias, customChain.chainAlias); 89 | assertEq(chainById.rpcUrl, customChain.rpcUrl); 90 | customChain.name = "Another Custom Chain"; 91 | customChain.chainId = 987654321; 92 | setChain("another_custom_chain", customChain); 93 | Chain memory anotherCustomChain = getChain("another_custom_chain"); 94 | assertEq(anotherCustomChain.name, "Another Custom Chain"); 95 | assertEq(anotherCustomChain.chainId, 987654321); 96 | assertEq(anotherCustomChain.chainAlias, "another_custom_chain"); 97 | assertEq(anotherCustomChain.rpcUrl, "https://custom.chain/"); 98 | // Verify the first chain data was not overwritten 99 | chainById = getChain(123456789); 100 | assertEq(chainById.name, "Custom Chain"); 101 | assertEq(chainById.chainId, 123456789); 102 | } 103 | 104 | function testSetNoEmptyAlias() public { 105 | vm.expectRevert("StdChains setChain(string,ChainData): Chain alias cannot be the empty string."); 106 | setChain("", ChainData("", 123456789, "")); 107 | } 108 | 109 | function testSetNoChainId0() public { 110 | vm.expectRevert("StdChains setChain(string,ChainData): Chain ID cannot be 0."); 111 | setChain("alias", ChainData("", 0, "")); 112 | } 113 | 114 | function testGetNoChainId0() public { 115 | vm.expectRevert("StdChains getChain(uint256): Chain ID cannot be 0."); 116 | getChain(0); 117 | } 118 | 119 | function testGetNoEmptyAlias() public { 120 | vm.expectRevert("StdChains getChain(string): Chain alias cannot be the empty string."); 121 | getChain(""); 122 | } 123 | 124 | function testChainIdNotFound() public { 125 | vm.expectRevert("StdChains getChain(string): Chain with alias \"no_such_alias\" not found."); 126 | getChain("no_such_alias"); 127 | } 128 | 129 | function testChainAliasNotFound() public { 130 | vm.expectRevert("StdChains getChain(uint256): Chain with ID 321 not found."); 131 | getChain(321); 132 | } 133 | 134 | function testSetChain_ExistingOne() public { 135 | setChain("custom_chain", ChainData("Custom Chain", 123456789, "https://custom.chain/")); 136 | assertEq(getChain(123456789).chainId, 123456789); 137 | 138 | setChain("custom_chain", ChainData("Modified Chain", 999999999, "https://modified.chain/")); 139 | vm.expectRevert("StdChains getChain(uint256): Chain with ID 123456789 not found."); 140 | getChain(123456789); 141 | 142 | Chain memory modifiedChain = getChain(999999999); 143 | assertEq(modifiedChain.name, "Modified Chain"); 144 | assertEq(modifiedChain.chainId, 999999999); 145 | assertEq(modifiedChain.rpcUrl, "https://modified.chain/"); 146 | } 147 | 148 | function testDontUseDefaultRpcUrl() public { 149 | // Should error if default RPCs flag is set to false. 150 | setFallbackToDefaultRpcUrls(false); 151 | vm.expectRevert( 152 | "Failed to get environment variable `ANVIL_RPC_URL` as type `string`: environment variable not found" 153 | ); 154 | getChain(31337); 155 | vm.expectRevert( 156 | "Failed to get environment variable `SEPOLIA_RPC_URL` as type `string`: environment variable not found" 157 | ); 158 | getChain("sepolia"); 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /EIP4337TestCase/lib/forge-std/test/StdError.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0 <0.9.0; 3 | 4 | import "../src/StdError.sol"; 5 | import "../src/Test.sol"; 6 | 7 | contract StdErrorsTest is Test { 8 | ErrorsTest test; 9 | 10 | function setUp() public { 11 | test = new ErrorsTest(); 12 | } 13 | 14 | function testExpectAssertion() public { 15 | vm.expectRevert(stdError.assertionError); 16 | test.assertionError(); 17 | } 18 | 19 | function testExpectArithmetic() public { 20 | vm.expectRevert(stdError.arithmeticError); 21 | test.arithmeticError(10); 22 | } 23 | 24 | function testExpectDiv() public { 25 | vm.expectRevert(stdError.divisionError); 26 | test.divError(0); 27 | } 28 | 29 | function testExpectMod() public { 30 | vm.expectRevert(stdError.divisionError); 31 | test.modError(0); 32 | } 33 | 34 | function testExpectEnum() public { 35 | vm.expectRevert(stdError.enumConversionError); 36 | test.enumConversion(1); 37 | } 38 | 39 | function testExpectEncodeStg() public { 40 | vm.expectRevert(stdError.encodeStorageError); 41 | test.encodeStgError(); 42 | } 43 | 44 | function testExpectPop() public { 45 | vm.expectRevert(stdError.popError); 46 | test.pop(); 47 | } 48 | 49 | function testExpectOOB() public { 50 | vm.expectRevert(stdError.indexOOBError); 51 | test.indexOOBError(1); 52 | } 53 | 54 | function testExpectMem() public { 55 | vm.expectRevert(stdError.memOverflowError); 56 | test.mem(); 57 | } 58 | 59 | function testExpectIntern() public { 60 | vm.expectRevert(stdError.zeroVarError); 61 | test.intern(); 62 | } 63 | } 64 | 65 | contract ErrorsTest { 66 | enum T {T1} 67 | 68 | uint256[] public someArr; 69 | bytes someBytes; 70 | 71 | function assertionError() public pure { 72 | assert(false); 73 | } 74 | 75 | function arithmeticError(uint256 a) public pure { 76 | a -= 100; 77 | } 78 | 79 | function divError(uint256 a) public pure { 80 | 100 / a; 81 | } 82 | 83 | function modError(uint256 a) public pure { 84 | 100 % a; 85 | } 86 | 87 | function enumConversion(uint256 a) public pure { 88 | T(a); 89 | } 90 | 91 | function encodeStgError() public { 92 | /// @solidity memory-safe-assembly 93 | assembly { 94 | sstore(someBytes.slot, 1) 95 | } 96 | keccak256(someBytes); 97 | } 98 | 99 | function pop() public { 100 | someArr.pop(); 101 | } 102 | 103 | function indexOOBError(uint256 a) public pure { 104 | uint256[] memory t = new uint256[](0); 105 | t[a]; 106 | } 107 | 108 | function mem() public pure { 109 | uint256 l = 2 ** 256 / 32; 110 | new uint256[](l); 111 | } 112 | 113 | function intern() public returns (uint256) { 114 | function(uint256) internal returns (uint256) x; 115 | x(2); 116 | return 7; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /EIP4337TestCase/lib/forge-std/test/StdMath.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0 <0.9.0; 3 | 4 | import "../src/StdMath.sol"; 5 | import "../src/Test.sol"; 6 | 7 | contract StdMathTest is Test { 8 | function testGetAbs() external { 9 | assertEq(stdMath.abs(-50), 50); 10 | assertEq(stdMath.abs(50), 50); 11 | assertEq(stdMath.abs(-1337), 1337); 12 | assertEq(stdMath.abs(0), 0); 13 | 14 | assertEq(stdMath.abs(type(int256).min), (type(uint256).max >> 1) + 1); 15 | assertEq(stdMath.abs(type(int256).max), (type(uint256).max >> 1)); 16 | } 17 | 18 | function testGetAbs_Fuzz(int256 a) external { 19 | uint256 manualAbs = getAbs(a); 20 | 21 | uint256 abs = stdMath.abs(a); 22 | 23 | assertEq(abs, manualAbs); 24 | } 25 | 26 | function testGetDelta_Uint() external { 27 | assertEq(stdMath.delta(uint256(0), uint256(0)), 0); 28 | assertEq(stdMath.delta(uint256(0), uint256(1337)), 1337); 29 | assertEq(stdMath.delta(uint256(0), type(uint64).max), type(uint64).max); 30 | assertEq(stdMath.delta(uint256(0), type(uint128).max), type(uint128).max); 31 | assertEq(stdMath.delta(uint256(0), type(uint256).max), type(uint256).max); 32 | 33 | assertEq(stdMath.delta(0, uint256(0)), 0); 34 | assertEq(stdMath.delta(1337, uint256(0)), 1337); 35 | assertEq(stdMath.delta(type(uint64).max, uint256(0)), type(uint64).max); 36 | assertEq(stdMath.delta(type(uint128).max, uint256(0)), type(uint128).max); 37 | assertEq(stdMath.delta(type(uint256).max, uint256(0)), type(uint256).max); 38 | 39 | assertEq(stdMath.delta(1337, uint256(1337)), 0); 40 | assertEq(stdMath.delta(type(uint256).max, type(uint256).max), 0); 41 | assertEq(stdMath.delta(5000, uint256(1250)), 3750); 42 | } 43 | 44 | function testGetDelta_Uint_Fuzz(uint256 a, uint256 b) external { 45 | uint256 manualDelta; 46 | if (a > b) { 47 | manualDelta = a - b; 48 | } else { 49 | manualDelta = b - a; 50 | } 51 | 52 | uint256 delta = stdMath.delta(a, b); 53 | 54 | assertEq(delta, manualDelta); 55 | } 56 | 57 | function testGetDelta_Int() external { 58 | assertEq(stdMath.delta(int256(0), int256(0)), 0); 59 | assertEq(stdMath.delta(int256(0), int256(1337)), 1337); 60 | assertEq(stdMath.delta(int256(0), type(int64).max), type(uint64).max >> 1); 61 | assertEq(stdMath.delta(int256(0), type(int128).max), type(uint128).max >> 1); 62 | assertEq(stdMath.delta(int256(0), type(int256).max), type(uint256).max >> 1); 63 | 64 | assertEq(stdMath.delta(0, int256(0)), 0); 65 | assertEq(stdMath.delta(1337, int256(0)), 1337); 66 | assertEq(stdMath.delta(type(int64).max, int256(0)), type(uint64).max >> 1); 67 | assertEq(stdMath.delta(type(int128).max, int256(0)), type(uint128).max >> 1); 68 | assertEq(stdMath.delta(type(int256).max, int256(0)), type(uint256).max >> 1); 69 | 70 | assertEq(stdMath.delta(-0, int256(0)), 0); 71 | assertEq(stdMath.delta(-1337, int256(0)), 1337); 72 | assertEq(stdMath.delta(type(int64).min, int256(0)), (type(uint64).max >> 1) + 1); 73 | assertEq(stdMath.delta(type(int128).min, int256(0)), (type(uint128).max >> 1) + 1); 74 | assertEq(stdMath.delta(type(int256).min, int256(0)), (type(uint256).max >> 1) + 1); 75 | 76 | assertEq(stdMath.delta(int256(0), -0), 0); 77 | assertEq(stdMath.delta(int256(0), -1337), 1337); 78 | assertEq(stdMath.delta(int256(0), type(int64).min), (type(uint64).max >> 1) + 1); 79 | assertEq(stdMath.delta(int256(0), type(int128).min), (type(uint128).max >> 1) + 1); 80 | assertEq(stdMath.delta(int256(0), type(int256).min), (type(uint256).max >> 1) + 1); 81 | 82 | assertEq(stdMath.delta(1337, int256(1337)), 0); 83 | assertEq(stdMath.delta(type(int256).max, type(int256).max), 0); 84 | assertEq(stdMath.delta(type(int256).min, type(int256).min), 0); 85 | assertEq(stdMath.delta(type(int256).min, type(int256).max), type(uint256).max); 86 | assertEq(stdMath.delta(5000, int256(1250)), 3750); 87 | } 88 | 89 | function testGetDelta_Int_Fuzz(int256 a, int256 b) external { 90 | uint256 absA = getAbs(a); 91 | uint256 absB = getAbs(b); 92 | uint256 absDelta = absA > absB ? absA - absB : absB - absA; 93 | 94 | uint256 manualDelta; 95 | if ((a >= 0 && b >= 0) || (a < 0 && b < 0)) { 96 | manualDelta = absDelta; 97 | } 98 | // (a < 0 && b >= 0) || (a >= 0 && b < 0) 99 | else { 100 | manualDelta = absA + absB; 101 | } 102 | 103 | uint256 delta = stdMath.delta(a, b); 104 | 105 | assertEq(delta, manualDelta); 106 | } 107 | 108 | function testGetPercentDelta_Uint() external { 109 | assertEq(stdMath.percentDelta(uint256(0), uint256(1337)), 1e18); 110 | assertEq(stdMath.percentDelta(uint256(0), type(uint64).max), 1e18); 111 | assertEq(stdMath.percentDelta(uint256(0), type(uint128).max), 1e18); 112 | assertEq(stdMath.percentDelta(uint256(0), type(uint192).max), 1e18); 113 | 114 | assertEq(stdMath.percentDelta(1337, uint256(1337)), 0); 115 | assertEq(stdMath.percentDelta(type(uint192).max, type(uint192).max), 0); 116 | assertEq(stdMath.percentDelta(0, uint256(2500)), 1e18); 117 | assertEq(stdMath.percentDelta(2500, uint256(2500)), 0); 118 | assertEq(stdMath.percentDelta(5000, uint256(2500)), 1e18); 119 | assertEq(stdMath.percentDelta(7500, uint256(2500)), 2e18); 120 | 121 | vm.expectRevert(stdError.divisionError); 122 | stdMath.percentDelta(uint256(1), 0); 123 | } 124 | 125 | function testGetPercentDelta_Uint_Fuzz(uint192 a, uint192 b) external { 126 | vm.assume(b != 0); 127 | uint256 manualDelta; 128 | if (a > b) { 129 | manualDelta = a - b; 130 | } else { 131 | manualDelta = b - a; 132 | } 133 | 134 | uint256 manualPercentDelta = manualDelta * 1e18 / b; 135 | uint256 percentDelta = stdMath.percentDelta(a, b); 136 | 137 | assertEq(percentDelta, manualPercentDelta); 138 | } 139 | 140 | function testGetPercentDelta_Int() external { 141 | assertEq(stdMath.percentDelta(int256(0), int256(1337)), 1e18); 142 | assertEq(stdMath.percentDelta(int256(0), -1337), 1e18); 143 | assertEq(stdMath.percentDelta(int256(0), type(int64).min), 1e18); 144 | assertEq(stdMath.percentDelta(int256(0), type(int128).min), 1e18); 145 | assertEq(stdMath.percentDelta(int256(0), type(int192).min), 1e18); 146 | assertEq(stdMath.percentDelta(int256(0), type(int64).max), 1e18); 147 | assertEq(stdMath.percentDelta(int256(0), type(int128).max), 1e18); 148 | assertEq(stdMath.percentDelta(int256(0), type(int192).max), 1e18); 149 | 150 | assertEq(stdMath.percentDelta(1337, int256(1337)), 0); 151 | assertEq(stdMath.percentDelta(type(int192).max, type(int192).max), 0); 152 | assertEq(stdMath.percentDelta(type(int192).min, type(int192).min), 0); 153 | 154 | assertEq(stdMath.percentDelta(type(int192).min, type(int192).max), 2e18); // rounds the 1 wei diff down 155 | assertEq(stdMath.percentDelta(type(int192).max, type(int192).min), 2e18 - 1); // rounds the 1 wei diff down 156 | assertEq(stdMath.percentDelta(0, int256(2500)), 1e18); 157 | assertEq(stdMath.percentDelta(2500, int256(2500)), 0); 158 | assertEq(stdMath.percentDelta(5000, int256(2500)), 1e18); 159 | assertEq(stdMath.percentDelta(7500, int256(2500)), 2e18); 160 | 161 | vm.expectRevert(stdError.divisionError); 162 | stdMath.percentDelta(int256(1), 0); 163 | } 164 | 165 | function testGetPercentDelta_Int_Fuzz(int192 a, int192 b) external { 166 | vm.assume(b != 0); 167 | uint256 absA = getAbs(a); 168 | uint256 absB = getAbs(b); 169 | uint256 absDelta = absA > absB ? absA - absB : absB - absA; 170 | 171 | uint256 manualDelta; 172 | if ((a >= 0 && b >= 0) || (a < 0 && b < 0)) { 173 | manualDelta = absDelta; 174 | } 175 | // (a < 0 && b >= 0) || (a >= 0 && b < 0) 176 | else { 177 | manualDelta = absA + absB; 178 | } 179 | 180 | uint256 manualPercentDelta = manualDelta * 1e18 / absB; 181 | uint256 percentDelta = stdMath.percentDelta(a, b); 182 | 183 | assertEq(percentDelta, manualPercentDelta); 184 | } 185 | 186 | /*////////////////////////////////////////////////////////////////////////// 187 | HELPERS 188 | //////////////////////////////////////////////////////////////////////////*/ 189 | 190 | function getAbs(int256 a) private pure returns (uint256) { 191 | if (a < 0) { 192 | return a == type(int256).min ? uint256(type(int256).max) + 1 : uint256(-a); 193 | } 194 | 195 | return uint256(a); 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /EIP4337TestCase/lib/forge-std/test/StdStyle.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.7.0 <0.9.0; 3 | 4 | import "../src/Test.sol"; 5 | 6 | contract StdStyleTest is Test { 7 | function testStyleColor() public pure { 8 | console2.log(StdStyle.red("StdStyle.red String Test")); 9 | console2.log(StdStyle.red(uint256(10e18))); 10 | console2.log(StdStyle.red(int256(-10e18))); 11 | console2.log(StdStyle.red(true)); 12 | console2.log(StdStyle.red(address(0))); 13 | console2.log(StdStyle.redBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D")); 14 | console2.log(StdStyle.redBytes32("StdStyle.redBytes32")); 15 | console2.log(StdStyle.green("StdStyle.green String Test")); 16 | console2.log(StdStyle.green(uint256(10e18))); 17 | console2.log(StdStyle.green(int256(-10e18))); 18 | console2.log(StdStyle.green(true)); 19 | console2.log(StdStyle.green(address(0))); 20 | console2.log(StdStyle.greenBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D")); 21 | console2.log(StdStyle.greenBytes32("StdStyle.greenBytes32")); 22 | console2.log(StdStyle.yellow("StdStyle.yellow String Test")); 23 | console2.log(StdStyle.yellow(uint256(10e18))); 24 | console2.log(StdStyle.yellow(int256(-10e18))); 25 | console2.log(StdStyle.yellow(true)); 26 | console2.log(StdStyle.yellow(address(0))); 27 | console2.log(StdStyle.yellowBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D")); 28 | console2.log(StdStyle.yellowBytes32("StdStyle.yellowBytes32")); 29 | console2.log(StdStyle.blue("StdStyle.blue String Test")); 30 | console2.log(StdStyle.blue(uint256(10e18))); 31 | console2.log(StdStyle.blue(int256(-10e18))); 32 | console2.log(StdStyle.blue(true)); 33 | console2.log(StdStyle.blue(address(0))); 34 | console2.log(StdStyle.blueBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D")); 35 | console2.log(StdStyle.blueBytes32("StdStyle.blueBytes32")); 36 | console2.log(StdStyle.magenta("StdStyle.magenta String Test")); 37 | console2.log(StdStyle.magenta(uint256(10e18))); 38 | console2.log(StdStyle.magenta(int256(-10e18))); 39 | console2.log(StdStyle.magenta(true)); 40 | console2.log(StdStyle.magenta(address(0))); 41 | console2.log(StdStyle.magentaBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D")); 42 | console2.log(StdStyle.magentaBytes32("StdStyle.magentaBytes32")); 43 | console2.log(StdStyle.cyan("StdStyle.cyan String Test")); 44 | console2.log(StdStyle.cyan(uint256(10e18))); 45 | console2.log(StdStyle.cyan(int256(-10e18))); 46 | console2.log(StdStyle.cyan(true)); 47 | console2.log(StdStyle.cyan(address(0))); 48 | console2.log(StdStyle.cyanBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D")); 49 | console2.log(StdStyle.cyanBytes32("StdStyle.cyanBytes32")); 50 | } 51 | 52 | function testStyleFontWeight() public pure { 53 | console2.log(StdStyle.bold("StdStyle.bold String Test")); 54 | console2.log(StdStyle.bold(uint256(10e18))); 55 | console2.log(StdStyle.bold(int256(-10e18))); 56 | console2.log(StdStyle.bold(address(0))); 57 | console2.log(StdStyle.bold(true)); 58 | console2.log(StdStyle.boldBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D")); 59 | console2.log(StdStyle.boldBytes32("StdStyle.boldBytes32")); 60 | console2.log(StdStyle.dim("StdStyle.dim String Test")); 61 | console2.log(StdStyle.dim(uint256(10e18))); 62 | console2.log(StdStyle.dim(int256(-10e18))); 63 | console2.log(StdStyle.dim(address(0))); 64 | console2.log(StdStyle.dim(true)); 65 | console2.log(StdStyle.dimBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D")); 66 | console2.log(StdStyle.dimBytes32("StdStyle.dimBytes32")); 67 | console2.log(StdStyle.italic("StdStyle.italic String Test")); 68 | console2.log(StdStyle.italic(uint256(10e18))); 69 | console2.log(StdStyle.italic(int256(-10e18))); 70 | console2.log(StdStyle.italic(address(0))); 71 | console2.log(StdStyle.italic(true)); 72 | console2.log(StdStyle.italicBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D")); 73 | console2.log(StdStyle.italicBytes32("StdStyle.italicBytes32")); 74 | console2.log(StdStyle.underline("StdStyle.underline String Test")); 75 | console2.log(StdStyle.underline(uint256(10e18))); 76 | console2.log(StdStyle.underline(int256(-10e18))); 77 | console2.log(StdStyle.underline(address(0))); 78 | console2.log(StdStyle.underline(true)); 79 | console2.log(StdStyle.underlineBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D")); 80 | console2.log(StdStyle.underlineBytes32("StdStyle.underlineBytes32")); 81 | console2.log(StdStyle.inverse("StdStyle.inverse String Test")); 82 | console2.log(StdStyle.inverse(uint256(10e18))); 83 | console2.log(StdStyle.inverse(int256(-10e18))); 84 | console2.log(StdStyle.inverse(address(0))); 85 | console2.log(StdStyle.inverse(true)); 86 | console2.log(StdStyle.inverseBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D")); 87 | console2.log(StdStyle.inverseBytes32("StdStyle.inverseBytes32")); 88 | } 89 | 90 | function testStyleCombined() public pure { 91 | console2.log(StdStyle.red(StdStyle.bold("Red Bold String Test"))); 92 | console2.log(StdStyle.green(StdStyle.dim(uint256(10e18)))); 93 | console2.log(StdStyle.yellow(StdStyle.italic(int256(-10e18)))); 94 | console2.log(StdStyle.blue(StdStyle.underline(address(0)))); 95 | console2.log(StdStyle.magenta(StdStyle.inverse(true))); 96 | } 97 | 98 | function testStyleCustom() public pure { 99 | console2.log(h1("Custom Style 1")); 100 | console2.log(h2("Custom Style 2")); 101 | } 102 | 103 | function h1(string memory a) private pure returns (string memory) { 104 | return StdStyle.cyan(StdStyle.inverse(StdStyle.bold(a))); 105 | } 106 | 107 | function h2(string memory a) private pure returns (string memory) { 108 | return StdStyle.magenta(StdStyle.bold(StdStyle.underline(a))); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /EIP4337TestCase/lib/forge-std/test/compilation/CompilationScript.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2 <0.9.0; 3 | 4 | pragma experimental ABIEncoderV2; 5 | 6 | import "../../src/Script.sol"; 7 | 8 | // The purpose of this contract is to benchmark compilation time to avoid accidentally introducing 9 | // a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207 10 | contract CompilationScript is Script {} 11 | -------------------------------------------------------------------------------- /EIP4337TestCase/lib/forge-std/test/compilation/CompilationScriptBase.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2 <0.9.0; 3 | 4 | pragma experimental ABIEncoderV2; 5 | 6 | import "../../src/Script.sol"; 7 | 8 | // The purpose of this contract is to benchmark compilation time to avoid accidentally introducing 9 | // a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207 10 | contract CompilationScriptBase is ScriptBase {} 11 | -------------------------------------------------------------------------------- /EIP4337TestCase/lib/forge-std/test/compilation/CompilationTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2 <0.9.0; 3 | 4 | pragma experimental ABIEncoderV2; 5 | 6 | import "../../src/Test.sol"; 7 | 8 | // The purpose of this contract is to benchmark compilation time to avoid accidentally introducing 9 | // a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207 10 | contract CompilationTest is Test {} 11 | -------------------------------------------------------------------------------- /EIP4337TestCase/lib/forge-std/test/compilation/CompilationTestBase.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2 <0.9.0; 3 | 4 | pragma experimental ABIEncoderV2; 5 | 6 | import "../../src/Test.sol"; 7 | 8 | // The purpose of this contract is to benchmark compilation time to avoid accidentally introducing 9 | // a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207 10 | contract CompilationTestBase is TestBase {} 11 | -------------------------------------------------------------------------------- /EIP4337TestCase/lib/forge-std/test/fixtures/broadcast.log.json: -------------------------------------------------------------------------------- 1 | { 2 | "transactions": [ 3 | { 4 | "hash": "0xc6006863c267735a11476b7f15b15bc718e117e2da114a2be815dd651e1a509f", 5 | "type": "CALL", 6 | "contractName": "Test", 7 | "contractAddress": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", 8 | "function": "multiple_arguments(uint256,address,uint256[]):(uint256)", 9 | "arguments": ["1", "0000000000000000000000000000000000001337", "[3,4]"], 10 | "tx": { 11 | "type": "0x02", 12 | "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", 13 | "to": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", 14 | "gas": "0x73b9", 15 | "value": "0x0", 16 | "data": "0x23e99187000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000013370000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004", 17 | "nonce": "0x3", 18 | "accessList": [] 19 | } 20 | }, 21 | { 22 | "hash": "0xedf2b38d8d896519a947a1acf720f859bb35c0c5ecb8dd7511995b67b9853298", 23 | "type": "CALL", 24 | "contractName": "Test", 25 | "contractAddress": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", 26 | "function": "inc():(uint256)", 27 | "arguments": [], 28 | "tx": { 29 | "type": "0x02", 30 | "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", 31 | "to": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", 32 | "gas": "0xdcb2", 33 | "value": "0x0", 34 | "data": "0x371303c0", 35 | "nonce": "0x4", 36 | "accessList": [] 37 | } 38 | }, 39 | { 40 | "hash": "0xa57e8e3981a6c861442e46c9471bd19cb3e21f9a8a6c63a72e7b5c47c6675a7c", 41 | "type": "CALL", 42 | "contractName": "Test", 43 | "contractAddress": "0x7c6b4bbe207d642d98d5c537142d85209e585087", 44 | "function": "t(uint256):(uint256)", 45 | "arguments": ["1"], 46 | "tx": { 47 | "type": "0x02", 48 | "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", 49 | "to": "0x7c6b4bbe207d642d98d5c537142d85209e585087", 50 | "gas": "0x8599", 51 | "value": "0x0", 52 | "data": "0xafe29f710000000000000000000000000000000000000000000000000000000000000001", 53 | "nonce": "0x5", 54 | "accessList": [] 55 | } 56 | } 57 | ], 58 | "receipts": [ 59 | { 60 | "transactionHash": "0x481dc86e40bba90403c76f8e144aa9ff04c1da2164299d0298573835f0991181", 61 | "transactionIndex": "0x0", 62 | "blockHash": "0xef0730448490304e5403be0fa8f8ce64f118e9adcca60c07a2ae1ab921d748af", 63 | "blockNumber": "0x1", 64 | "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", 65 | "to": null, 66 | "cumulativeGasUsed": "0x13f3a", 67 | "gasUsed": "0x13f3a", 68 | "contractAddress": "0x5fbdb2315678afecb367f032d93f642f64180aa3", 69 | "logs": [], 70 | "status": "0x1", 71 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 72 | "effectiveGasPrice": "0xee6b2800" 73 | }, 74 | { 75 | "transactionHash": "0x6a187183545b8a9e7f1790e847139379bf5622baff2cb43acf3f5c79470af782", 76 | "transactionIndex": "0x0", 77 | "blockHash": "0xf3acb96a90071640c2a8c067ae4e16aad87e634ea8d8bbbb5b352fba86ba0148", 78 | "blockNumber": "0x2", 79 | "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", 80 | "to": null, 81 | "cumulativeGasUsed": "0x45d80", 82 | "gasUsed": "0x45d80", 83 | "contractAddress": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", 84 | "logs": [], 85 | "status": "0x1", 86 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 87 | "effectiveGasPrice": "0xee6b2800" 88 | }, 89 | { 90 | "transactionHash": "0x064ad173b4867bdef2fb60060bbdaf01735fbf10414541ea857772974e74ea9d", 91 | "transactionIndex": "0x0", 92 | "blockHash": "0x8373d02109d3ee06a0225f23da4c161c656ccc48fe0fcee931d325508ae73e58", 93 | "blockNumber": "0x3", 94 | "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", 95 | "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", 96 | "cumulativeGasUsed": "0x45feb", 97 | "gasUsed": "0x45feb", 98 | "contractAddress": null, 99 | "logs": [], 100 | "status": "0x1", 101 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 102 | "effectiveGasPrice": "0xee6b2800" 103 | }, 104 | { 105 | "transactionHash": "0xc6006863c267735a11476b7f15b15bc718e117e2da114a2be815dd651e1a509f", 106 | "transactionIndex": "0x0", 107 | "blockHash": "0x16712fae5c0e18f75045f84363fb6b4d9a9fe25e660c4ce286833a533c97f629", 108 | "blockNumber": "0x4", 109 | "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", 110 | "to": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", 111 | "cumulativeGasUsed": "0x5905", 112 | "gasUsed": "0x5905", 113 | "contractAddress": null, 114 | "logs": [], 115 | "status": "0x1", 116 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 117 | "effectiveGasPrice": "0xee6b2800" 118 | }, 119 | { 120 | "transactionHash": "0xedf2b38d8d896519a947a1acf720f859bb35c0c5ecb8dd7511995b67b9853298", 121 | "transactionIndex": "0x0", 122 | "blockHash": "0x156b88c3eb9a1244ba00a1834f3f70de735b39e3e59006dd03af4fe7d5480c11", 123 | "blockNumber": "0x5", 124 | "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", 125 | "to": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", 126 | "cumulativeGasUsed": "0xa9c4", 127 | "gasUsed": "0xa9c4", 128 | "contractAddress": null, 129 | "logs": [], 130 | "status": "0x1", 131 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 132 | "effectiveGasPrice": "0xee6b2800" 133 | }, 134 | { 135 | "transactionHash": "0xa57e8e3981a6c861442e46c9471bd19cb3e21f9a8a6c63a72e7b5c47c6675a7c", 136 | "transactionIndex": "0x0", 137 | "blockHash": "0xcf61faca67dbb2c28952b0b8a379e53b1505ae0821e84779679390cb8571cadb", 138 | "blockNumber": "0x6", 139 | "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", 140 | "to": "0x7c6b4bbe207d642d98d5c537142d85209e585087", 141 | "cumulativeGasUsed": "0x66c5", 142 | "gasUsed": "0x66c5", 143 | "contractAddress": null, 144 | "logs": [ 145 | { 146 | "address": "0x7c6b4bbe207d642d98d5c537142d85209e585087", 147 | "topics": [ 148 | "0x0b2e13ff20ac7b474198655583edf70dedd2c1dc980e329c4fbb2fc0748b796b" 149 | ], 150 | "data": "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000", 151 | "blockHash": "0xcf61faca67dbb2c28952b0b8a379e53b1505ae0821e84779679390cb8571cadb", 152 | "blockNumber": "0x6", 153 | "transactionHash": "0xa57e8e3981a6c861442e46c9471bd19cb3e21f9a8a6c63a72e7b5c47c6675a7c", 154 | "transactionIndex": "0x1", 155 | "logIndex": "0x0", 156 | "transactionLogIndex": "0x0", 157 | "removed": false 158 | } 159 | ], 160 | "status": "0x1", 161 | "logsBloom": "0x00000000000800000000000000000010000000000000000000000000000180000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100", 162 | "effectiveGasPrice": "0xee6b2800" 163 | }, 164 | { 165 | "transactionHash": "0x11fbb10230c168ca1e36a7e5c69a6dbcd04fd9e64ede39d10a83e36ee8065c16", 166 | "transactionIndex": "0x0", 167 | "blockHash": "0xf1e0ed2eda4e923626ec74621006ed50b3fc27580dc7b4cf68a07ca77420e29c", 168 | "blockNumber": "0x7", 169 | "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", 170 | "to": "0x0000000000000000000000000000000000001337", 171 | "cumulativeGasUsed": "0x5208", 172 | "gasUsed": "0x5208", 173 | "contractAddress": null, 174 | "logs": [], 175 | "status": "0x1", 176 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 177 | "effectiveGasPrice": "0xee6b2800" 178 | } 179 | ], 180 | "libraries": [ 181 | "src/Broadcast.t.sol:F:0x5fbdb2315678afecb367f032d93f642f64180aa3" 182 | ], 183 | "pending": [], 184 | "path": "broadcast/Broadcast.t.sol/31337/run-latest.json", 185 | "returns": {}, 186 | "timestamp": 1655140035 187 | } 188 | -------------------------------------------------------------------------------- /EIP4337TestCase/node_modules.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mirrorzk/Account-abstraction-coding-security-library/d7c92b94fc62438d199495dc1d28d653eb5bdab9/EIP4337TestCase/node_modules.zip -------------------------------------------------------------------------------- /EIP4337TestCase/out/IBeacon.sol/IBeacon.json: -------------------------------------------------------------------------------- 1 | { 2 | "abi": [ 3 | { 4 | "inputs": [], 5 | "name": "implementation", 6 | "outputs": [ 7 | { 8 | "internalType": "address", 9 | "name": "", 10 | "type": "address" 11 | } 12 | ], 13 | "stateMutability": "view", 14 | "type": "function" 15 | } 16 | ], 17 | "bytecode": { 18 | "object": "0x", 19 | "sourceMap": "", 20 | "linkReferences": {} 21 | }, 22 | "deployedBytecode": { 23 | "object": "0x", 24 | "sourceMap": "", 25 | "linkReferences": {} 26 | }, 27 | "methodIdentifiers": { 28 | "implementation()": "5c60da1b" 29 | }, 30 | "rawMetadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"implementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This is the interface that {BeaconProxy} expects of its beacon.\",\"kind\":\"dev\",\"methods\":{\"implementation()\":{\"details\":\"Must return an address that can be used as a delegate call target. {BeaconProxy} will check that this address is a contract.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"node_modules/@openzeppelin/contracts/proxy/beacon/IBeacon.sol\":\"IBeacon\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":@openzeppelin/=node_modules/@openzeppelin/\",\":@uniswap/=node_modules/@uniswap/\",\":base64-sol/=node_modules/base64-sol/\",\":ds-test/=lib/forge-std/lib/ds-test/src/\",\":forge-std/=lib/forge-std/src/\"]},\"sources\":{\"node_modules/@openzeppelin/contracts/proxy/beacon/IBeacon.sol\":{\"keccak256\":\"0xd50a3421ac379ccb1be435fa646d66a65c986b4924f0849839f08692f39dde61\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://ada1e030c0231db8d143b44ce92b4d1158eedb087880cad6d8cc7bd7ebe7b354\",\"dweb:/ipfs/QmWZ2NHZweRpz1U9GF6R1h65ri76dnX7fNxLBeM2t5N5Ce\"]}},\"version\":1}", 31 | "metadata": { 32 | "compiler": { 33 | "version": "0.8.17+commit.8df45f5f" 34 | }, 35 | "language": "Solidity", 36 | "output": { 37 | "abi": [ 38 | { 39 | "inputs": [], 40 | "stateMutability": "view", 41 | "type": "function", 42 | "name": "implementation", 43 | "outputs": [ 44 | { 45 | "internalType": "address", 46 | "name": "", 47 | "type": "address" 48 | } 49 | ] 50 | } 51 | ], 52 | "devdoc": { 53 | "kind": "dev", 54 | "methods": { 55 | "implementation()": { 56 | "details": "Must return an address that can be used as a delegate call target. {BeaconProxy} will check that this address is a contract." 57 | } 58 | }, 59 | "version": 1 60 | }, 61 | "userdoc": { 62 | "kind": "user", 63 | "methods": {}, 64 | "version": 1 65 | } 66 | }, 67 | "settings": { 68 | "remappings": [ 69 | ":@openzeppelin/=node_modules/@openzeppelin/", 70 | ":@uniswap/=node_modules/@uniswap/", 71 | ":base64-sol/=node_modules/base64-sol/", 72 | ":ds-test/=lib/forge-std/lib/ds-test/src/", 73 | ":forge-std/=lib/forge-std/src/" 74 | ], 75 | "optimizer": { 76 | "enabled": true, 77 | "runs": 200 78 | }, 79 | "metadata": { 80 | "bytecodeHash": "ipfs" 81 | }, 82 | "compilationTarget": { 83 | "node_modules/@openzeppelin/contracts/proxy/beacon/IBeacon.sol": "IBeacon" 84 | }, 85 | "libraries": {} 86 | }, 87 | "sources": { 88 | "node_modules/@openzeppelin/contracts/proxy/beacon/IBeacon.sol": { 89 | "keccak256": "0xd50a3421ac379ccb1be435fa646d66a65c986b4924f0849839f08692f39dde61", 90 | "urls": [ 91 | "bzz-raw://ada1e030c0231db8d143b44ce92b4d1158eedb087880cad6d8cc7bd7ebe7b354", 92 | "dweb:/ipfs/QmWZ2NHZweRpz1U9GF6R1h65ri76dnX7fNxLBeM2t5N5Ce" 93 | ], 94 | "license": "MIT" 95 | } 96 | }, 97 | "version": 1 98 | }, 99 | "ast": { 100 | "absolutePath": "node_modules/@openzeppelin/contracts/proxy/beacon/IBeacon.sol", 101 | "id": 36890, 102 | "exportedSymbols": { 103 | "IBeacon": [ 104 | 36889 105 | ] 106 | }, 107 | "nodeType": "SourceUnit", 108 | "src": "93:357:48", 109 | "nodes": [ 110 | { 111 | "id": 36881, 112 | "nodeType": "PragmaDirective", 113 | "src": "93:23:48", 114 | "nodes": [], 115 | "literals": [ 116 | "solidity", 117 | "^", 118 | "0.8", 119 | ".0" 120 | ] 121 | }, 122 | { 123 | "id": 36889, 124 | "nodeType": "ContractDefinition", 125 | "src": "198:251:48", 126 | "nodes": [ 127 | { 128 | "id": 36888, 129 | "nodeType": "FunctionDefinition", 130 | "src": "389:58:48", 131 | "nodes": [], 132 | "documentation": { 133 | "id": 36883, 134 | "nodeType": "StructuredDocumentation", 135 | "src": "222:162:48", 136 | "text": " @dev Must return an address that can be used as a delegate call target.\n {BeaconProxy} will check that this address is a contract." 137 | }, 138 | "functionSelector": "5c60da1b", 139 | "implemented": false, 140 | "kind": "function", 141 | "modifiers": [], 142 | "name": "implementation", 143 | "nameLocation": "398:14:48", 144 | "parameters": { 145 | "id": 36884, 146 | "nodeType": "ParameterList", 147 | "parameters": [], 148 | "src": "412:2:48" 149 | }, 150 | "returnParameters": { 151 | "id": 36887, 152 | "nodeType": "ParameterList", 153 | "parameters": [ 154 | { 155 | "constant": false, 156 | "id": 36886, 157 | "mutability": "mutable", 158 | "name": "", 159 | "nameLocation": "-1:-1:-1", 160 | "nodeType": "VariableDeclaration", 161 | "scope": 36888, 162 | "src": "438:7:48", 163 | "stateVariable": false, 164 | "storageLocation": "default", 165 | "typeDescriptions": { 166 | "typeIdentifier": "t_address", 167 | "typeString": "address" 168 | }, 169 | "typeName": { 170 | "id": 36885, 171 | "name": "address", 172 | "nodeType": "ElementaryTypeName", 173 | "src": "438:7:48", 174 | "stateMutability": "nonpayable", 175 | "typeDescriptions": { 176 | "typeIdentifier": "t_address", 177 | "typeString": "address" 178 | } 179 | }, 180 | "visibility": "internal" 181 | } 182 | ], 183 | "src": "437:9:48" 184 | }, 185 | "scope": 36889, 186 | "stateMutability": "view", 187 | "virtual": false, 188 | "visibility": "external" 189 | } 190 | ], 191 | "abstract": false, 192 | "baseContracts": [], 193 | "canonicalName": "IBeacon", 194 | "contractDependencies": [], 195 | "contractKind": "interface", 196 | "documentation": { 197 | "id": 36882, 198 | "nodeType": "StructuredDocumentation", 199 | "src": "118:79:48", 200 | "text": " @dev This is the interface that {BeaconProxy} expects of its beacon." 201 | }, 202 | "fullyImplemented": false, 203 | "linearizedBaseContracts": [ 204 | 36889 205 | ], 206 | "name": "IBeacon", 207 | "nameLocation": "208:7:48", 208 | "scope": 36890, 209 | "usedErrors": [] 210 | } 211 | ], 212 | "license": "MIT" 213 | }, 214 | "id": 48 215 | } -------------------------------------------------------------------------------- /EIP4337TestCase/out/draft-IERC1822.sol/IERC1822Proxiable.json: -------------------------------------------------------------------------------- 1 | { 2 | "abi": [ 3 | { 4 | "inputs": [], 5 | "name": "proxiableUUID", 6 | "outputs": [ 7 | { 8 | "internalType": "bytes32", 9 | "name": "", 10 | "type": "bytes32" 11 | } 12 | ], 13 | "stateMutability": "view", 14 | "type": "function" 15 | } 16 | ], 17 | "bytecode": { 18 | "object": "0x", 19 | "sourceMap": "", 20 | "linkReferences": {} 21 | }, 22 | "deployedBytecode": { 23 | "object": "0x", 24 | "sourceMap": "", 25 | "linkReferences": {} 26 | }, 27 | "methodIdentifiers": { 28 | "proxiableUUID()": "52d1902d" 29 | }, 30 | "rawMetadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"proxiableUUID\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified proxy whose upgrades are fully controlled by the current implementation.\",\"kind\":\"dev\",\"methods\":{\"proxiableUUID()\":{\"details\":\"Returns the storage slot that the proxiable contract assumes is being used to store the implementation address. IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this function revert if invoked through a proxy.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"node_modules/@openzeppelin/contracts/interfaces/draft-IERC1822.sol\":\"IERC1822Proxiable\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":@openzeppelin/=node_modules/@openzeppelin/\",\":@uniswap/=node_modules/@uniswap/\",\":base64-sol/=node_modules/base64-sol/\",\":ds-test/=lib/forge-std/lib/ds-test/src/\",\":forge-std/=lib/forge-std/src/\"]},\"sources\":{\"node_modules/@openzeppelin/contracts/interfaces/draft-IERC1822.sol\":{\"keccak256\":\"0x1d4afe6cb24200cc4545eed814ecf5847277dfe5d613a1707aad5fceecebcfff\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://383fb7b8181016ac5ccf07bc9cdb7c1b5045ea36e2cc4df52bcbf20396fc7688\",\"dweb:/ipfs/QmYJ7Cg4WmE3rR8KGQxjUCXFfTH6TcwZ2Z1f6tPrq7jHFr\"]}},\"version\":1}", 31 | "metadata": { 32 | "compiler": { 33 | "version": "0.8.17+commit.8df45f5f" 34 | }, 35 | "language": "Solidity", 36 | "output": { 37 | "abi": [ 38 | { 39 | "inputs": [], 40 | "stateMutability": "view", 41 | "type": "function", 42 | "name": "proxiableUUID", 43 | "outputs": [ 44 | { 45 | "internalType": "bytes32", 46 | "name": "", 47 | "type": "bytes32" 48 | } 49 | ] 50 | } 51 | ], 52 | "devdoc": { 53 | "kind": "dev", 54 | "methods": { 55 | "proxiableUUID()": { 56 | "details": "Returns the storage slot that the proxiable contract assumes is being used to store the implementation address. IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this function revert if invoked through a proxy." 57 | } 58 | }, 59 | "version": 1 60 | }, 61 | "userdoc": { 62 | "kind": "user", 63 | "methods": {}, 64 | "version": 1 65 | } 66 | }, 67 | "settings": { 68 | "remappings": [ 69 | ":@openzeppelin/=node_modules/@openzeppelin/", 70 | ":@uniswap/=node_modules/@uniswap/", 71 | ":base64-sol/=node_modules/base64-sol/", 72 | ":ds-test/=lib/forge-std/lib/ds-test/src/", 73 | ":forge-std/=lib/forge-std/src/" 74 | ], 75 | "optimizer": { 76 | "enabled": true, 77 | "runs": 200 78 | }, 79 | "metadata": { 80 | "bytecodeHash": "ipfs" 81 | }, 82 | "compilationTarget": { 83 | "node_modules/@openzeppelin/contracts/interfaces/draft-IERC1822.sol": "IERC1822Proxiable" 84 | }, 85 | "libraries": {} 86 | }, 87 | "sources": { 88 | "node_modules/@openzeppelin/contracts/interfaces/draft-IERC1822.sol": { 89 | "keccak256": "0x1d4afe6cb24200cc4545eed814ecf5847277dfe5d613a1707aad5fceecebcfff", 90 | "urls": [ 91 | "bzz-raw://383fb7b8181016ac5ccf07bc9cdb7c1b5045ea36e2cc4df52bcbf20396fc7688", 92 | "dweb:/ipfs/QmYJ7Cg4WmE3rR8KGQxjUCXFfTH6TcwZ2Z1f6tPrq7jHFr" 93 | ], 94 | "license": "MIT" 95 | } 96 | }, 97 | "version": 1 98 | }, 99 | "ast": { 100 | "absolutePath": "node_modules/@openzeppelin/contracts/interfaces/draft-IERC1822.sol", 101 | "id": 36473, 102 | "exportedSymbols": { 103 | "IERC1822Proxiable": [ 104 | 36472 105 | ] 106 | }, 107 | "nodeType": "SourceUnit", 108 | "src": "113:766:44", 109 | "nodes": [ 110 | { 111 | "id": 36464, 112 | "nodeType": "PragmaDirective", 113 | "src": "113:23:44", 114 | "nodes": [], 115 | "literals": [ 116 | "solidity", 117 | "^", 118 | "0.8", 119 | ".0" 120 | ] 121 | }, 122 | { 123 | "id": 36472, 124 | "nodeType": "ContractDefinition", 125 | "src": "342:536:44", 126 | "nodes": [ 127 | { 128 | "id": 36471, 129 | "nodeType": "FunctionDefinition", 130 | "src": "819:57:44", 131 | "nodes": [], 132 | "documentation": { 133 | "id": 36466, 134 | "nodeType": "StructuredDocumentation", 135 | "src": "376:438:44", 136 | "text": " @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation\n address.\n IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks\n bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this\n function revert if invoked through a proxy." 137 | }, 138 | "functionSelector": "52d1902d", 139 | "implemented": false, 140 | "kind": "function", 141 | "modifiers": [], 142 | "name": "proxiableUUID", 143 | "nameLocation": "828:13:44", 144 | "parameters": { 145 | "id": 36467, 146 | "nodeType": "ParameterList", 147 | "parameters": [], 148 | "src": "841:2:44" 149 | }, 150 | "returnParameters": { 151 | "id": 36470, 152 | "nodeType": "ParameterList", 153 | "parameters": [ 154 | { 155 | "constant": false, 156 | "id": 36469, 157 | "mutability": "mutable", 158 | "name": "", 159 | "nameLocation": "-1:-1:-1", 160 | "nodeType": "VariableDeclaration", 161 | "scope": 36471, 162 | "src": "867:7:44", 163 | "stateVariable": false, 164 | "storageLocation": "default", 165 | "typeDescriptions": { 166 | "typeIdentifier": "t_bytes32", 167 | "typeString": "bytes32" 168 | }, 169 | "typeName": { 170 | "id": 36468, 171 | "name": "bytes32", 172 | "nodeType": "ElementaryTypeName", 173 | "src": "867:7:44", 174 | "typeDescriptions": { 175 | "typeIdentifier": "t_bytes32", 176 | "typeString": "bytes32" 177 | } 178 | }, 179 | "visibility": "internal" 180 | } 181 | ], 182 | "src": "866:9:44" 183 | }, 184 | "scope": 36472, 185 | "stateMutability": "view", 186 | "virtual": false, 187 | "visibility": "external" 188 | } 189 | ], 190 | "abstract": false, 191 | "baseContracts": [], 192 | "canonicalName": "IERC1822Proxiable", 193 | "contractDependencies": [], 194 | "contractKind": "interface", 195 | "documentation": { 196 | "id": 36465, 197 | "nodeType": "StructuredDocumentation", 198 | "src": "138:203:44", 199 | "text": " @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified\n proxy whose upgrades are fully controlled by the current implementation." 200 | }, 201 | "fullyImplemented": false, 202 | "linearizedBaseContracts": [ 203 | 36472 204 | ], 205 | "name": "IERC1822Proxiable", 206 | "nameLocation": "352:17:44", 207 | "scope": 36473, 208 | "usedErrors": [] 209 | } 210 | ], 211 | "license": "MIT" 212 | }, 213 | "id": 44 214 | } -------------------------------------------------------------------------------- /EIP4337TestCase/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "EIP4337Test", 3 | "lockfileVersion": 3, 4 | "requires": true, 5 | "packages": { 6 | "": { 7 | "dependencies": { 8 | "@openzeppelin/contracts": "^4.8.0", 9 | "@uniswap/v3-periphery": "^1.4.3" 10 | } 11 | }, 12 | "node_modules/@openzeppelin/contracts": { 13 | "version": "4.8.0", 14 | "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-4.8.0.tgz", 15 | "integrity": "sha512-AGuwhRRL+NaKx73WKRNzeCxOCOCxpaqF+kp8TJ89QzAipSwZy/NoflkWaL9bywXFRhIzXt8j38sfF7KBKCPWLw==" 16 | }, 17 | "node_modules/@uniswap/lib": { 18 | "version": "4.0.1-alpha", 19 | "resolved": "https://registry.npmjs.org/@uniswap/lib/-/lib-4.0.1-alpha.tgz", 20 | "integrity": "sha512-f6UIliwBbRsgVLxIaBANF6w09tYqc6Y/qXdsrbEmXHyFA7ILiKrIwRFXe1yOg8M3cksgVsO9N7yuL2DdCGQKBA==", 21 | "engines": { 22 | "node": ">=10" 23 | } 24 | }, 25 | "node_modules/@uniswap/v2-core": { 26 | "version": "1.0.1", 27 | "resolved": "https://registry.npmjs.org/@uniswap/v2-core/-/v2-core-1.0.1.tgz", 28 | "integrity": "sha512-MtybtkUPSyysqLY2U210NBDeCHX+ltHt3oADGdjqoThZaFRDKwM6k1Nb3F0A3hk5hwuQvytFWhrWHOEq6nVJ8Q==", 29 | "engines": { 30 | "node": ">=10" 31 | } 32 | }, 33 | "node_modules/@uniswap/v3-core": { 34 | "version": "1.0.0", 35 | "resolved": "https://registry.npmjs.org/@uniswap/v3-core/-/v3-core-1.0.0.tgz", 36 | "integrity": "sha512-kSC4djMGKMHj7sLMYVnn61k9nu+lHjMIxgg9CDQT+s2QYLoA56GbSK9Oxr+qJXzzygbkrmuY6cwgP6cW2JXPFA==", 37 | "engines": { 38 | "node": ">=10" 39 | } 40 | }, 41 | "node_modules/@uniswap/v3-periphery": { 42 | "version": "1.4.3", 43 | "resolved": "https://registry.npmjs.org/@uniswap/v3-periphery/-/v3-periphery-1.4.3.tgz", 44 | "integrity": "sha512-80c+wtVzl5JJT8UQskxVYYG3oZb4pkhY0zDe0ab/RX4+8f9+W5d8wI4BT0wLB0wFQTSnbW+QdBSpkHA/vRyGBA==", 45 | "dependencies": { 46 | "@openzeppelin/contracts": "3.4.2-solc-0.7", 47 | "@uniswap/lib": "^4.0.1-alpha", 48 | "@uniswap/v2-core": "1.0.1", 49 | "@uniswap/v3-core": "1.0.0", 50 | "base64-sol": "1.0.1" 51 | }, 52 | "engines": { 53 | "node": ">=10" 54 | } 55 | }, 56 | "node_modules/@uniswap/v3-periphery/node_modules/@openzeppelin/contracts": { 57 | "version": "3.4.2-solc-0.7", 58 | "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-3.4.2-solc-0.7.tgz", 59 | "integrity": "sha512-W6QmqgkADuFcTLzHL8vVoNBtkwjvQRpYIAom7KiUNoLKghyx3FgH0GBjt8NRvigV1ZmMOBllvE1By1C+bi8WpA==" 60 | }, 61 | "node_modules/base64-sol": { 62 | "version": "1.0.1", 63 | "resolved": "https://registry.npmjs.org/base64-sol/-/base64-sol-1.0.1.tgz", 64 | "integrity": "sha512-ld3cCNMeXt4uJXmLZBHFGMvVpK9KsLVEhPpFRXnvSVAqABKbuNZg/+dsq3NuM+wxFLb/UrVkz7m1ciWmkMfTbg==" 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /EIP4337TestCase/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "@openzeppelin/contracts": "^4.8.0", 4 | "@uniswap/v3-periphery": "^1.4.3" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /EIP4337TestCase/remappings.txt: -------------------------------------------------------------------------------- 1 | ds-test/=lib/forge-std/lib/ds-test/src/ 2 | forge-std/=lib/forge-std/src/ 3 | @openzeppelin/=node_modules/@openzeppelin/ 4 | -------------------------------------------------------------------------------- /EIP4337TestCase/test/BaseTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "contracts/core/EntryPoint.sol"; 5 | import {SimpleAccount as Wallet} from "contracts/samples/SimpleAccount.sol"; 6 | import {SimpleAccountFactory as AccountFactory} from "contracts/samples/SimpleAccountFactory.sol"; 7 | import {LegacyTokenPaymaster as Paymaster} from "contracts/samples/LegacyTokenPaymaster.sol"; 8 | import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; 9 | import "forge-std/Test.sol"; 10 | 11 | 12 | contract BaseTest is Test { 13 | using ECDSA for bytes32; 14 | EntryPoint public entryPoint; 15 | 16 | AccountFactory public factory; 17 | Wallet public account; 18 | Paymaster public paymaster; 19 | 20 | address public owner; 21 | uint public key; 22 | 23 | function _initAccount()internal{ 24 | entryPoint = new EntryPoint(); 25 | (owner, key) = makeAddrAndKey("owner"); 26 | factory=new AccountFactory(entryPoint); 27 | account=factory.createAccount(owner,1); 28 | } 29 | function _initPaymaster()internal{ 30 | _initAccount(); 31 | paymaster =new Paymaster(address(factory),"LT",entryPoint); 32 | entryPoint.depositTo{value:1 ether}(address(paymaster)); 33 | } 34 | 35 | function fillUserOp(address _sender)internal view returns (UserOperation memory op) 36 | { 37 | op.sender = _sender; 38 | op.nonce = entryPoint.getNonce(_sender, 0); 39 | op.callData = abi.encodeWithSelector(Wallet.execute.selector, address(0),0,bytes("")); 40 | op.callGasLimit = 10000000; 41 | op.verificationGasLimit = 10000000; 42 | op.preVerificationGas = 100000; 43 | op.maxFeePerGas = 100000; 44 | op.maxPriorityFeePerGas = 100000; 45 | } 46 | 47 | function getSignature(uint _key,bytes32 _opHash)internal pure returns(bytes memory signature){ 48 | (uint8 v, bytes32 r, bytes32 s) = vm.sign(_key, _opHash.toEthSignedMessageHash()); 49 | signature = abi.encodePacked(r, s, v); 50 | } 51 | 52 | //Ensure that the returned `op` and `ophash` can be successfully validated. 53 | function getOp()internal view returns(UserOperation memory op,bytes32 ophash){ 54 | op = fillUserOp(address(account)); 55 | ophash=entryPoint.getUserOpHash(op); 56 | op.signature=getSignature(key,ophash); 57 | } 58 | 59 | function getOpWithPm(bytes memory _paymasterAndData)internal view returns(UserOperation memory op,bytes32 ophash){ 60 | op = fillUserOp(address(account)); 61 | op.paymasterAndData=_paymasterAndData; 62 | ophash=entryPoint.getUserOpHash(op); 63 | op.signature=getSignature(key,ophash); 64 | } 65 | } -------------------------------------------------------------------------------- /EIP4337TestCase/test/Paymaster.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "test/BaseTest.sol"; 5 | 6 | contract PaymasterTest is BaseTest { 7 | 8 | function setUp() public { 9 | _initPaymaster(); 10 | } 11 | 12 | function test_validatePaymasterUserOp_revert() external { 13 | bytes memory _pmdata=abi.encode(address(paymaster)); 14 | (UserOperation memory op,bytes32 ophash)=getOpWithPm(_pmdata); 15 | vm.startPrank(address(entryPoint)); 16 | vm.expectRevert(); 17 | paymaster.validatePaymasterUserOp(op, ophash, 10000); 18 | vm.stopPrank(); 19 | } 20 | 21 | function test_validatePaymasterUserOp_onlyEntryPoint(address msgSender)external{ 22 | vm.assume(msgSender!=address(entryPoint)); 23 | // Ensure that it correctly validates when called by the entrypoint 24 | paymaster.mintTokens(address(account),1 ether *100); 25 | bytes memory _pmdata=abi.encode(address(paymaster)); 26 | (UserOperation memory op,bytes32 ophash)=getOpWithPm(_pmdata); 27 | vm.startPrank(address(entryPoint)); 28 | paymaster.validatePaymasterUserOp(op, ophash, 10000); 29 | vm.stopPrank(); 30 | //test 31 | vm.startPrank(msgSender); 32 | vm.expectRevert(); 33 | paymaster.validatePaymasterUserOp(op, ophash, 10000); 34 | vm.stopPrank(); 35 | } 36 | } -------------------------------------------------------------------------------- /EIP4337TestCase/test/Wallet.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "test/BaseTest.sol"; 5 | 6 | contract WalletTest is BaseTest { 7 | 8 | function setUp() public { 9 | _initAccount(); 10 | } 11 | 12 | function test_validateUserOp_sig_sucess() external { 13 | (UserOperation memory op,bytes32 ophash)=getOp(); 14 | vm.startPrank(address(entryPoint)); 15 | uint ret = account.validateUserOp(op, ophash, 0); 16 | vm.stopPrank(); 17 | uint authorizer=uint(uint160(ret)); 18 | assertEq(authorizer, 0); 19 | } 20 | 21 | function test_validateUserOp_sig_fail() external { 22 | (UserOperation memory op,bytes32 ophash)=getOp(); 23 | bytes memory errorSig=getSignature(key,bytes32(0)); 24 | op.signature=errorSig; 25 | vm.startPrank(address(entryPoint)); 26 | uint ret = account.validateUserOp(op, ophash, 0); 27 | vm.stopPrank(); 28 | uint authorizer=uint(uint160(ret)); 29 | bool failure=(authorizer==0); 30 | assertFalse(failure); 31 | } 32 | 33 | function test_validateUserOp_missingAccountFunds() external { 34 | uint missingFunds=100000; 35 | (address(account)).call{value:1 ether}(""); 36 | (UserOperation memory op,bytes32 ophash)=getOp(); 37 | uint112 before_deposit=entryPoint.getDepositInfo(address(account)).deposit; 38 | vm.startPrank(address(entryPoint)); 39 | account.validateUserOp(op, ophash, missingFunds); 40 | vm.stopPrank(); 41 | uint112 after_deposit=entryPoint.getDepositInfo(address(account)).deposit; 42 | assertGe(after_deposit-before_deposit, missingFunds); 43 | } 44 | 45 | function test_validateUserOp_onlyEntryPoint(address msgSender)external{ 46 | vm.assume(msgSender!=address(entryPoint)); 47 | (UserOperation memory op,bytes32 ophash)=getOp(); 48 | vm.startPrank(msgSender); 49 | vm.expectRevert(); 50 | account.validateUserOp(op, ophash, 0); 51 | vm.stopPrank(); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /pic/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mirrorzk/Account-abstraction-coding-security-library/d7c92b94fc62438d199495dc1d28d653eb5bdab9/pic/1.png -------------------------------------------------------------------------------- /pic/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mirrorzk/Account-abstraction-coding-security-library/d7c92b94fc62438d199495dc1d28d653eb5bdab9/pic/2.png --------------------------------------------------------------------------------