Last active
November 25, 2024 00:05
-
-
Save frangio/e40305b9f99de290b73750dff5ebe50a to your computer and use it in GitHub Desktop.
A simple ERC-4337 account for use as an EIP-7702 template. UNAUDITED
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.28; | |
struct PackedUserOperation { | |
address sender; | |
uint256 nonce; | |
bytes initCode; | |
bytes callData; | |
bytes32 accountGasLimits; | |
uint256 preVerificationGas; | |
bytes32 gasFees; | |
bytes paymasterAndData; | |
bytes signature; | |
} | |
interface IAccount { | |
function validateUserOp( | |
PackedUserOperation calldata userOp, | |
bytes32 userOpHash, | |
uint256 missingAccountFunds | |
) external returns (uint256 validationData); | |
} | |
interface IERC165 { | |
function supportsInterface(bytes4 interfaceId) external view returns (bool); | |
} | |
interface IERC1155Receiver { | |
function onERC1155Received( | |
address operator, | |
address from, | |
uint256 id, | |
uint256 value, | |
bytes calldata data | |
) external returns (bytes4); | |
function onERC1155BatchReceived( | |
address operator, | |
address from, | |
uint256[] calldata ids, | |
uint256[] calldata values, | |
bytes calldata data | |
) external returns (bytes4); | |
} | |
contract EIP7702Account is IAccount, IERC165, IERC1155Receiver { | |
address payable private immutable entrypoint = payable(0x0000000071727De22E5E9d8BAf0edAc6f37da032); | |
function validateUserOp( | |
PackedUserOperation calldata userOp, | |
bytes32 userOpHash, | |
uint256 missingAccountFunds | |
) external returns (uint256 validationData) { | |
require(msg.sender == entrypoint); | |
(bytes32 r, bytes32 vs) = abi.decode(userOp.signature, (bytes32, bytes32)); | |
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); | |
uint8 v = uint8(uint256(vs >> 255) + 27); | |
if (address(this) == ecrecover(userOpHash, v, r, s)) { | |
(bool ok, ) = entrypoint.call{ | |
value: missingAccountFunds, | |
gas: type(uint256).max | |
}(""); | |
require(ok); | |
return 0; // success | |
} else { | |
return 1; // failure | |
} | |
} | |
struct Call { | |
address target; | |
uint256 value; | |
bytes data; | |
} | |
function execute(Call[] calldata calls) external { | |
require(msg.sender == entrypoint || msg.sender == address(this)); | |
for (uint256 i = 0; i < calls.length; i++) { | |
Call calldata call = calls[i]; | |
(bool ok, bytes memory retdata) = call.target.call{value: call.value}(call.data); | |
if (!ok) assembly { | |
revert(add(retdata, 32), mload(retdata)) | |
} | |
} | |
} | |
function onERC721Received(address, address, uint256, bytes memory) public virtual returns (bytes4) { | |
return this.onERC721Received.selector; | |
} | |
function onERC1155Received(address, address, uint256, uint256, bytes calldata) public virtual override returns (bytes4) { | |
return this.onERC1155Received.selector; | |
} | |
function onERC1155BatchReceived(address, address, uint256[] calldata, uint256[] calldata, bytes calldata) public virtual override returns (bytes4) { | |
return this.onERC1155BatchReceived.selector; | |
} | |
function supportsInterface(bytes4 id) external pure returns (bool) { | |
return id == type(IERC165).interfaceId || id == type(IERC1155Receiver).interfaceId; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment