123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113 |
- // SPDX-License-Identifier: MIT
- pragma solidity ^0.8.20;
- import {Test} from "forge-std/Test.sol";
- import {AccountERC7702Mock} from "@openzeppelin/contracts/mocks/account/AccountMock.sol";
- import {CallReceiverMock} from "@openzeppelin/contracts/mocks/CallReceiverMock.sol";
- import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
- import {
- ERC7579Utils,
- Execution,
- Mode,
- ModeSelector,
- ModePayload
- } from "@openzeppelin/contracts/account/utils/draft-ERC7579Utils.sol";
- import {ERC4337Utils, IEntryPointExtra} from "@openzeppelin/contracts/account/utils/draft-ERC4337Utils.sol";
- import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
- import {PackedUserOperation} from "@openzeppelin/contracts/interfaces/draft-IERC4337.sol";
- import {ERC7821} from "@openzeppelin/contracts/account/extensions/draft-ERC7821.sol";
- contract AccountERC7702MockConstructor is AccountERC7702Mock {
- constructor() EIP712("MyAccount", "1") {}
- }
- contract AccountERC7702Test is Test {
- using ERC7579Utils for *;
- using ERC4337Utils for PackedUserOperation;
- using Strings for *;
- uint256 private constant MAX_ETH = type(uint128).max;
- // Test accounts
- CallReceiverMock private _target;
- // ERC-4337 signer
- uint256 private _signerPrivateKey;
- AccountERC7702MockConstructor private _signer;
- function setUp() public {
- // Deploy target contract
- _target = new CallReceiverMock();
- // Setup signer
- _signerPrivateKey = 0x1234;
- _signer = AccountERC7702MockConstructor(payable(vm.addr(_signerPrivateKey)));
- vm.deal(address(_signer), MAX_ETH);
- // Sign and attach delegation
- vm.signAndAttachDelegation(address(new AccountERC7702MockConstructor()), _signerPrivateKey);
- // Setup entrypoint
- address entrypoint = address(ERC4337Utils.ENTRYPOINT_V08);
- vm.deal(entrypoint, MAX_ETH);
- vm.etch(
- entrypoint,
- vm.readFileBinary(
- string.concat(
- "node_modules/hardhat-predeploy/bin/",
- Strings.toChecksumHexString(entrypoint),
- ".bytecode"
- )
- )
- );
- }
- function testExecuteBatch(uint256 argA, uint256 argB) public {
- // Create the mode for batch execution
- Mode mode = ERC7579Utils.CALLTYPE_BATCH.encodeMode(
- ERC7579Utils.EXECTYPE_DEFAULT,
- ModeSelector.wrap(0x00000000),
- ModePayload.wrap(0x00000000)
- );
- Execution[] memory execution = new Execution[](2);
- execution[0] = Execution({
- target: address(_target),
- value: 1 ether,
- callData: abi.encodeCall(CallReceiverMock.mockFunctionExtra, ())
- });
- execution[1] = Execution({
- target: address(_target),
- value: 0,
- callData: abi.encodeCall(CallReceiverMock.mockFunctionWithArgs, (argA, argB))
- });
- // Pack the batch within a PackedUserOperation
- PackedUserOperation[] memory ops = new PackedUserOperation[](1);
- ops[0] = PackedUserOperation({
- sender: address(_signer),
- nonce: 0,
- initCode: bytes(""),
- callData: abi.encodeCall(ERC7821.execute, (Mode.unwrap(mode), execution.encodeBatch())),
- preVerificationGas: 100000,
- accountGasLimits: bytes32(abi.encodePacked(uint128(100000), uint128(100000))),
- gasFees: bytes32(abi.encodePacked(uint128(1000000), uint128(1000000))),
- paymasterAndData: bytes(""),
- signature: bytes("")
- });
- (uint8 v, bytes32 r, bytes32 s) = vm.sign(
- _signerPrivateKey,
- IEntryPointExtra(address(ERC4337Utils.ENTRYPOINT_V08)).getUserOpHash(ops[0])
- );
- ops[0].signature = abi.encodePacked(r, s, v);
- // Expect the events to be emitted
- vm.expectEmit(true, true, true, true);
- emit CallReceiverMock.MockFunctionCalledExtra(address(_signer), 1 ether);
- vm.expectEmit(true, true, true, true);
- emit CallReceiverMock.MockFunctionCalledWithArgs(argA, argB);
- // Execute the batch
- _signer.entryPoint().handleOps(ops, payable(makeAddr("beneficiary")));
- }
- }
|