Skip to content

Commit

Permalink
starting rewrite account common as ERC7579
Browse files Browse the repository at this point in the history
  • Loading branch information
Amxx committed Jul 19, 2024
1 parent 5a4b300 commit de032e3
Show file tree
Hide file tree
Showing 21 changed files with 1,355 additions and 109 deletions.
21 changes: 13 additions & 8 deletions contracts/abstraction/account/Account.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

pragma solidity ^0.8.20;

import {PackedUserOperation, IAccount, IEntryPoint} from "../../interfaces/IERC4337.sol";
import {SignatureChecker} from "../../utils/cryptography/SignatureChecker.sol";
import {PackedUserOperation, IAccount, IAccountExecute, IEntryPoint} from "../../interfaces/IERC4337.sol";
import {ERC4337Utils} from "./../utils/ERC4337Utils.sol";
import {SignatureChecker} from "../../utils/cryptography/SignatureChecker.sol";
import {Address} from "../../utils/Address.sol";

abstract contract Account is IAccount {
abstract contract Account is IAccount, IAccountExecute {
error AccountEntryPointRestricted();
error AccountInvalidBatchLength();

/****************************************************************************************************************
* Modifiers *
Expand Down Expand Up @@ -39,15 +39,15 @@ abstract contract Account is IAccount {
*
* Subclass must implement this using their own access control mechanism.
*/
function _isAuthorized(address) internal virtual returns (bool);
function _isAuthorized(address) internal view virtual returns (bool);

/**
* @dev Recover the signer for a given signature and user operation hash. This function does not need to verify
* that the recovered signer is authorized.
*
* Subclass must implement this using their own choice of cryptography.
*/
function _recoverSigner(bytes32 userOpHash, bytes calldata signature) internal virtual returns (address);
function _recoverSigner(bytes32 userOpHash, bytes calldata signature) internal view virtual returns (address);

/****************************************************************************************************************
* Public interface *
Expand All @@ -72,13 +72,18 @@ abstract contract Account is IAccount {
PackedUserOperation calldata userOp,
bytes32 userOpHash,
uint256 missingAccountFunds
) public virtual override onlyEntryPoint returns (uint256 validationData) {
) public virtual onlyEntryPoint returns (uint256 validationData) {
(bool valid, , uint48 validAfter, uint48 validUntil) = _processSignature(userOpHash, userOp.signature);
_validateNonce(userOp.nonce);
_payPrefund(missingAccountFunds);
return ERC4337Utils.packValidationData(valid, validAfter, validUntil);
}

/// @inheritdoc IAccountExecute
function executeUserOp(PackedUserOperation calldata userOp, bytes32 /*userOpHash*/) public virtual onlyEntryPoint {
Address.functionDelegateCall(address(this), userOp.callData[4:]);
}

/****************************************************************************************************************
* Internal mechanisms *
****************************************************************************************************************/
Expand All @@ -95,7 +100,7 @@ abstract contract Account is IAccount {
function _processSignature(
bytes32 userOpHash,
bytes calldata signature
) internal virtual returns (bool valid, address signer, uint48 validAfter, uint48 validUntil) {
) internal view virtual returns (bool valid, address signer, uint48 validAfter, uint48 validUntil) {
address recovered = _recoverSigner(userOpHash, signature);
return (recovered != address(0) && _isAuthorized(recovered), recovered, 0, 0);
}
Expand Down
46 changes: 0 additions & 46 deletions contracts/abstraction/account/AccountCommon.sol

This file was deleted.

200 changes: 200 additions & 0 deletions contracts/abstraction/account/ERC7579Account.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import {Account} from "./Account.sol";
import {Address} from "../../utils/Address.sol";
import {ERC1155Holder} from "../../token/ERC1155/utils/ERC1155Holder.sol";
import {ERC721Holder} from "../../token/ERC721/utils/ERC721Holder.sol";
import {IEntryPoint} from "../../interfaces/IERC4337.sol";
import {IERC1271} from "../../interfaces/IERC1271.sol";
import {IERC165, ERC165} from "../../utils/introspection/ERC165.sol";
import {IERC7579Execution, IERC7579AccountConfig, IERC7579ModuleConfig, Execution} from "../../interfaces/IERC7579Account.sol";
import {ERC7579Utils, Mode, CallType, ExecType} from "../utils/ERC7579Utils.sol";

abstract contract ERC7579Account is
IERC165, // required by erc-7579
IERC1271, // required by erc-7579
IERC7579Execution, // required by erc-7579
IERC7579AccountConfig, // required by erc-7579
IERC7579ModuleConfig, // required by erc-7579
Account,
ERC165,
ERC721Holder,
ERC1155Holder
{
using ERC7579Utils for *;

IEntryPoint private immutable _entryPoint;

event ERC7579TryExecuteUnsuccessful(uint256 batchExecutionindex, bytes result);
error ERC7579UnsupportedCallType(CallType);
error ERC7579UnsupportedExecType(ExecType);

modifier onlyExecutorModule() {
// TODO
_;
}

constructor(IEntryPoint entryPoint_) {
_entryPoint = entryPoint_;
}

receive() external payable {}

function entryPoint() public view virtual override returns (IEntryPoint) {
return _entryPoint;
}

/// @inheritdoc IERC165
function supportsInterface(
bytes4 interfaceId
) public view virtual override(IERC165, ERC165, ERC1155Holder) returns (bool) {
// TODO: more?
return super.supportsInterface(interfaceId);
}

/// @inheritdoc IERC1271
function isValidSignature(bytes32 hash, bytes calldata signature) public view returns (bytes4 magicValue) {
(bool valid, , uint48 validAfter, uint48 validUntil) = _processSignature(hash, signature);
return
(valid && validAfter < block.timestamp && (validUntil == 0 || validUntil > block.timestamp))
? IERC1271.isValidSignature.selector
: bytes4(0);
}

/// @inheritdoc IERC7579Execution
function execute(bytes32 mode, bytes calldata executionCalldata) public virtual onlyEntryPoint {
_execute(Mode.wrap(mode), executionCalldata);
}

/// @inheritdoc IERC7579Execution
function executeFromExecutor(
bytes32 mode,
bytes calldata executionCalldata
) public virtual onlyExecutorModule returns (bytes[] memory) {
return _execute(Mode.wrap(mode), executionCalldata);
}

function _execute(
Mode mode,
bytes calldata executionCalldata
) internal virtual returns (bytes[] memory returnData) {
// TODO: ModeSelector? ModePayload?
(CallType callType, ExecType execType, , ) = mode.decodeMode();

if (callType == ERC7579Utils.CALLTYPE_SINGLE) {
(address target, uint256 value, bytes calldata callData) = executionCalldata.decodeSingle();
returnData = new bytes[](1);
returnData[0] = _execute(0, execType, target, value, callData);
} else if (callType == ERC7579Utils.CALLTYPE_BATCH) {
Execution[] calldata executionBatch = executionCalldata.decodeBatch();
returnData = new bytes[](executionBatch.length);
for (uint256 i = 0; i < executionBatch.length; ++i) {
returnData[i] = _execute(
i,
execType,
executionBatch[i].target,
executionBatch[i].value,
executionBatch[i].callData
);
}
} else if (callType == ERC7579Utils.CALLTYPE_DELEGATECALL) {
(address target, bytes calldata callData) = executionCalldata.decodeDelegate();
returnData = new bytes[](1);
returnData[0] = _executeDelegate(0, execType, target, callData);
} else {
revert ERC7579UnsupportedCallType(callType);
}
}

function _execute(
uint256 index,
ExecType execType,
address target,
uint256 value,
bytes memory data
) private returns (bytes memory) {
if (execType == ERC7579Utils.EXECTYPE_DEFAULT) {
(bool success, bytes memory returndata) = target.call{value: value}(data);
Address.verifyCallResult(success, returndata);
return returndata;
} else if (execType == ERC7579Utils.EXECTYPE_TRY) {
(bool success, bytes memory returndata) = target.call{value: value}(data);
if (!success) emit ERC7579TryExecuteUnsuccessful(index, returndata);
return returndata;
} else {
revert ERC7579UnsupportedExecType(execType);
}
}

function _executeDelegate(
uint256 index,
ExecType execType,
address target,
bytes memory data
) private returns (bytes memory) {
if (execType == ERC7579Utils.EXECTYPE_DEFAULT) {
(bool success, bytes memory returndata) = target.delegatecall(data);
Address.verifyCallResult(success, returndata);
return returndata;
} else if (execType == ERC7579Utils.EXECTYPE_TRY) {
(bool success, bytes memory returndata) = target.delegatecall(data);
if (!success) emit ERC7579TryExecuteUnsuccessful(index, returndata);
return returndata;
} else {
revert ERC7579UnsupportedExecType(execType);
}
}

/// @inheritdoc IERC7579AccountConfig
function accountId() public view virtual returns (string memory) {
//vendorname.accountname.semver
return "@openzeppelin/contracts.erc7579account.v0-beta";
}

/// @inheritdoc IERC7579AccountConfig
function supportsExecutionMode(bytes32 encodedMode) public view virtual returns (bool) {
(CallType callType, , , ) = Mode.wrap(encodedMode).decodeMode();
return
callType == ERC7579Utils.CALLTYPE_SINGLE ||
callType == ERC7579Utils.CALLTYPE_BATCH ||
callType == ERC7579Utils.CALLTYPE_DELEGATECALL;
}

/// @inheritdoc IERC7579AccountConfig
function supportsModule(uint256 moduleTypeId) public view virtual returns (bool) {
// TODO: update when module support is added
moduleTypeId;
return false;
}

/// @inheritdoc IERC7579ModuleConfig
function installModule(uint256 moduleTypeId, address module, bytes calldata initData) public pure {
moduleTypeId;
module;
initData;
revert("not-implemented-yet");
}

/// @inheritdoc IERC7579ModuleConfig
function uninstallModule(uint256 moduleTypeId, address module, bytes calldata deInitData) public pure {
moduleTypeId;
module;
deInitData;
revert("not-implemented-yet");
}

/// @inheritdoc IERC7579ModuleConfig
function isModuleInstalled(
uint256 moduleTypeId,
address module,
bytes calldata additionalContext
) public view returns (bool) {
moduleTypeId;
module;
additionalContext;
address(this);
revert("not-implemented-yet");
}
}
2 changes: 1 addition & 1 deletion contracts/abstraction/account/modules/AccountMultisig.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ abstract contract AccountMultisig is Account {
function _processSignature(
bytes32 userOpHash,
bytes calldata signatures
) internal virtual override returns (bool, address, uint48 validAfter, uint48 validUntil) {
) internal view virtual override returns (bool, address, uint48 validAfter, uint48 validUntil) {
bytes[] calldata signatureArray = _decodeBytesArray(signatures);

if (signatureArray.length < requiredSignatures()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ abstract contract AccountAllSignatures is AccountECDSA, AccountERC1271 {
function _recoverSigner(
bytes32 userOpHash,
bytes calldata signature
) internal virtual override(AccountECDSA, AccountERC1271) returns (address) {
) internal view virtual override(AccountECDSA, AccountERC1271) returns (address) {
SignatureType sigType = SignatureType(uint8(bytes1(signature)));

if (sigType == SignatureType.ECDSA) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ abstract contract AccountECDSA is Account {
function _recoverSigner(
bytes32 userOpHash,
bytes calldata signature
) internal virtual override returns (address signer) {
) internal view virtual override returns (address signer) {
bytes32 msgHash = MessageHashUtils.toEthSignedMessageHash(userOpHash);

// This implementation support both "normal" and short signature formats:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ import {Account} from "../../Account.sol";
abstract contract AccountERC1271 is Account {
error P256InvalidSignatureLength(uint256 length);

function _recoverSigner(bytes32 userOpHash, bytes calldata signature) internal virtual override returns (address) {
function _recoverSigner(
bytes32 userOpHash,
bytes calldata signature
) internal view virtual override returns (address) {
bytes32 msgHash = MessageHashUtils.toEthSignedMessageHash(userOpHash);
address signer = address(bytes20(signature[0x00:0x14]));

Expand Down
11 changes: 5 additions & 6 deletions contracts/abstraction/mocks/AdvancedAccount.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@ pragma solidity ^0.8.20;

import {IEntryPoint} from "../../interfaces/IERC4337.sol";
import {AccessControl} from "../../access/AccessControl.sol";
import {ERC1155Holder} from "../../token/ERC1155/utils/ERC1155Holder.sol";
import {Account} from "../account/Account.sol";
import {AccountCommon} from "../account/AccountCommon.sol";
import {ERC7579Account} from "../account/ERC7579Account.sol";
import {AccountMultisig} from "../account/modules/AccountMultisig.sol";
import {AccountAllSignatures} from "../account/modules/recovery/AccountAllSignatures.sol";

contract AdvancedAccount is AccessControl, AccountCommon, AccountAllSignatures, AccountMultisig {
contract AdvancedAccount is AccessControl, ERC7579Account, AccountAllSignatures, AccountMultisig {
bytes32 public constant SIGNER_ROLE = keccak256("SIGNER_ROLE");
uint256 private _requiredSignatures;

Expand All @@ -19,7 +18,7 @@ contract AdvancedAccount is AccessControl, AccountCommon, AccountAllSignatures,
address admin_,
address[] memory signers_,
uint256 requiredSignatures_
) AccountCommon(entryPoint_) {
) ERC7579Account(entryPoint_) {
_grantRole(DEFAULT_ADMIN_ROLE, admin_);
for (uint256 i = 0; i < signers_.length; ++i) {
_grantRole(SIGNER_ROLE, signers_[i]);
Expand All @@ -29,7 +28,7 @@ contract AdvancedAccount is AccessControl, AccountCommon, AccountAllSignatures,

function supportsInterface(
bytes4 interfaceId
) public view virtual override(AccessControl, ERC1155Holder) returns (bool) {
) public view virtual override(ERC7579Account, AccessControl) returns (bool) {
return super.supportsInterface(interfaceId);
}

Expand All @@ -44,7 +43,7 @@ contract AdvancedAccount is AccessControl, AccountCommon, AccountAllSignatures,
function _processSignature(
bytes32 userOpHash,
bytes calldata signature
) internal virtual override(Account, AccountMultisig) returns (bool, address, uint48, uint48) {
) internal view virtual override(Account, AccountMultisig) returns (bool, address, uint48, uint48) {
return super._processSignature(userOpHash, signature);
}
}
Loading

0 comments on commit de032e3

Please sign in to comment.