Skip to content

Commit

Permalink
feat: revert back to v0.6
Browse files Browse the repository at this point in the history
This PR also includes the rework of 712.
  • Loading branch information
huaweigu committed Oct 11, 2024
1 parent b70545e commit ce3055f
Show file tree
Hide file tree
Showing 68 changed files with 1,112 additions and 998 deletions.
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[submodule "lib/account-abstraction"]
path = lib/account-abstraction
url = https://github.com/eth-infinitism/account-abstraction
branch = releases/v0.7
branch = releases/v0.6
2 changes: 1 addition & 1 deletion lib/account-abstraction
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
"license": "GPL-3.0-or-later",
"dependencies": {
"@modular-account-libs": "github:erc6900/modular-account-libs#v0.8.0-rc.0",
"@openzeppelin/contracts": "5.0.2",
"@openzeppelin/contracts-upgradeable": "5.0.2",
"@openzeppelin/contracts": "4.9.6",
"@openzeppelin/contracts-upgradeable": "4.9.6",
"fcl": "github:rdubois-crypto/FreshCryptoLib#8179e08cac72072bd260796633fec41fdfd5b441",
"forge-std": "github:foundry-rs/forge-std#v1.9.2",
"solady": "0.0.243"
Expand Down
5 changes: 3 additions & 2 deletions src/account/CoreAccount.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {BaseAccount} from "@account-abstraction/contracts/core/BaseAccount.sol";
import {IEntryPoint} from "@account-abstraction/contracts/interfaces/IEntryPoint.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import {IERC1271} from "@openzeppelin/contracts/interfaces/IERC1271.sol";

/**
Expand Down Expand Up @@ -70,7 +70,8 @@ abstract contract CoreAccount is

// for mutable values in proxies
function __CoreAccount_init(address _newOwner) internal onlyInitializing {

Check warning on line 72 in src/account/CoreAccount.sol

View workflow job for this annotation

GitHub Actions / lint_and_test

Function name must be in mixedCase
__Ownable_init(_newOwner);
__Ownable_init();
transferOwnership(_newOwner);
__Pausable_init();
}

Expand Down
53 changes: 40 additions & 13 deletions src/account/v1/ECDSAAccount.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,31 @@
*/
pragma solidity 0.8.24;

import {SIG_VALIDATION_FAILED} from "../../common/Constants.sol";
import "../CoreAccount.sol";
import "@account-abstraction/contracts/interfaces/IEntryPoint.sol";
import "@account-abstraction/contracts/interfaces/PackedUserOperation.sol";
import {
EIP1271_INVALID_SIGNATURE,
EIP1271_VALID_SIGNATURE,
SIG_VALIDATION_FAILED,
WALLET_VERSION_1
} from "../../common/Constants.sol";

import {BaseERC712CompliantAccount} from "../../erc712/BaseERC712CompliantAccount.sol";
import {CoreAccount} from "../CoreAccount.sol";
import {IEntryPoint} from "@account-abstraction/contracts/interfaces/IEntryPoint.sol";
import {UserOperation} from "@account-abstraction/contracts/interfaces/UserOperation.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
import "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {SignatureChecker} from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";

/**
* @dev Upgradable & ownable (by EOA key) contract. One of the most common templates.
*/
contract ECDSAAccount is CoreAccount, UUPSUpgradeable {
contract ECDSAAccount is CoreAccount, UUPSUpgradeable, BaseERC712CompliantAccount {
using ECDSA for bytes32;
using MessageHashUtils for bytes32;

string public constant NAME = "Circle_ECDSAAccount";
bytes32 private constant _HASHED_NAME = keccak256(bytes(NAME));
bytes32 private constant _HASHED_VERSION = keccak256(bytes(WALLET_VERSION_1));
bytes32 private constant _MESSAGE_TYPEHASH = keccak256("CircleECDSAAccountMessage(bytes32 hash)");

/// @inheritdoc UUPSUpgradeable
// The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
Expand All @@ -52,7 +62,7 @@ contract ECDSAAccount is CoreAccount, UUPSUpgradeable {
__UUPSUpgradeable_init();
}

function _validateSignature(PackedUserOperation calldata userOp, bytes32 userOpHash)
function _validateSignature(UserOperation calldata userOp, bytes32 userOpHash)
internal
view
override
Expand All @@ -69,9 +79,26 @@ contract ECDSAAccount is CoreAccount, UUPSUpgradeable {
}

function isValidSignature(bytes32 hash, bytes memory signature) external view override returns (bytes4) {
if (!SignatureChecker.isValidSignatureNow(owner(), hash.toEthSignedMessageHash(), signature)) {
return bytes4(0xffffffff);
// use address(this) to prevent replay attacks
bytes32 replaySafeHash = getReplaySafeMessageHash(hash);
if (SignatureChecker.isValidSignatureNow(owner(), replaySafeHash, signature)) {
return EIP1271_VALID_SIGNATURE;
}
return EIP1271_MAGIC_VALUE;
return EIP1271_INVALID_SIGNATURE;
}

/// @inheritdoc BaseERC712CompliantAccount
function _getAccountTypeHash() internal pure override returns (bytes32) {
return _MESSAGE_TYPEHASH;
}

/// @inheritdoc BaseERC712CompliantAccount
function _getAccountName() internal pure override returns (bytes32) {
return _HASHED_NAME;
}

/// @inheritdoc BaseERC712CompliantAccount
function _getAccountVersion() internal pure override returns (bytes32) {
return _HASHED_VERSION;
}
}
10 changes: 10 additions & 0 deletions src/common/CommonStructs.sol
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,13 @@ struct OwnerData {
uint256 publicKeyX; // 32 bytes if used
uint256 publicKeyY; // 32 bytes if used
}

/// @notice Metadata of the ownership of an account.
/// @param numOwners number of owners on the account
/// @param thresholdWeight weight of signatures required to perform an action
/// @param totalWeight total weight of signatures required to perform an action
struct OwnershipMetadata {
uint256 numOwners;
uint256 thresholdWeight;
uint256 totalWeight;
}
53 changes: 53 additions & 0 deletions src/erc712/BaseERC712CompliantAccount.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright 2024 Circle Internet Group, Inc. All rights reserved.
* SPDX-License-Identifier: GPL-3.0-or-later
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.24;

import {MessageHashUtils} from "../libs/MessageHashUtils.sol";

abstract contract BaseERC712CompliantAccount {
// keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")
bytes32 private constant _DOMAIN_SEPARATOR_TYPEHASH =
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");

/// @notice Wraps a replay safe hash in an EIP-712 envelope to prevent cross-account replay attacks.
/// domainSeparator = hashStruct(eip712Domain).
/// eip712Domain = (string name,string version,uint256 chainId,address verifyingContract)
/// hashStruct(s) = keccak256(typeHash ‖ encodeData(s)) where typeHash = keccak256(encodeType(typeOf(s)))
/// @param hash Message that should be hashed.
/// @return Replay safe message hash.
function getReplaySafeMessageHash(bytes32 hash) public view returns (bytes32) {
return MessageHashUtils.toTypedDataHash({
domainSeparator: keccak256(
abi.encode(
_DOMAIN_SEPARATOR_TYPEHASH, _getAccountName(), _getAccountVersion(), block.chainid, address(this)
)
),
structHash: keccak256(abi.encode(_getAccountTypeHash(), hash))
});
}

/// @dev Returns the account message typehash.
function _getAccountTypeHash() internal pure virtual returns (bytes32);

/// @dev Returns the account name.
function _getAccountName() internal pure virtual returns (bytes32);

/// @dev Returns the account version.
function _getAccountVersion() internal pure virtual returns (bytes32);
}
49 changes: 49 additions & 0 deletions src/libs/MessageHashUtils.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright 2024 Circle Internet Group, Inc. All rights reserved.
* SPDX-License-Identifier: GPL-3.0-or-later
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.24;

/**
* @notice Forked from OZ V5 as it doesn't exist in V4.
* @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.
*
* The library provides methods for generating a hash of a message that conforms to the
* https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]
* specifications.
*/
library MessageHashUtils {
/**
* @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`).
*
* The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with
* `\x19\x01` and hashing the result. It corresponds to the hash signed by the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.
*
* See {ECDSA-recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, hex"1901")
mstore(add(ptr, 0x02), domainSeparator)
mstore(add(ptr, 0x22), structHash)
digest := keccak256(ptr, 0x42)
}
}
}
61 changes: 61 additions & 0 deletions src/msca/6900/shared/erc712/BaseERC712CompliantModule.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright 2024 Circle Internet Group, Inc. All rights reserved.
* SPDX-License-Identifier: GPL-3.0-or-later
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.24;

import {MessageHashUtils} from "../../../../libs/MessageHashUtils.sol";

// @notice Inspired by 6900 reference implementation with some modifications.
// A base contract for modules that use EIP-712 structured data signing.
// Unlike other EIP712 libraries, this base contract uses the salt field (bytes32(bytes20(account)) to hold the
// account address
// and uses the verifyingContract field to hold module address.
// This abstract contract does not implement EIP-5267, as the domain retrieval function eip712Domain() does not provide
// a parameter to hold the account address.
// If we use verifyingContract to hold account address, then `msg.sender` would be address(0) for an `eth_call` without
// an override.
abstract contract BaseERC712CompliantModule {
// keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract,bytes32 salt)")
bytes32 private constant _DOMAIN_SEPARATOR_TYPEHASH =
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract,bytes32 salt)");

/// @notice Wraps a replay safe hash in an EIP-712 envelope to prevent cross-account replay attacks.
/// domainSeparator = hashStruct(eip712Domain).
/// eip712Domain = (string name,string version,uint256 chainId,address verifyingContract,bytes32 salt)
/// The domain separator includes the chainId, module address and account address.
/// hashStruct(s) = keccak256(typeHash ‖ encodeData(s)) where typeHash = keccak256(encodeType(typeOf(s)))
/// @param account SCA to build the message hash for.
/// @param hash Message that should be hashed.
/// @return Replay safe message hash.
function getReplaySafeMessageHash(address account, bytes32 hash) public view returns (bytes32) {
return MessageHashUtils.toTypedDataHash({
domainSeparator: keccak256(
abi.encode(
_DOMAIN_SEPARATOR_TYPEHASH, _getModuleIdHash(), block.chainid, address(this), bytes32(bytes20(account))
)
),
structHash: keccak256(abi.encode(_getModuleTypeHash(), hash))
});
}

/// @dev Returns the module typehash.
function _getModuleTypeHash() internal pure virtual returns (bytes32);

/// @dev Returns the module id.
function _getModuleIdHash() internal pure virtual returns (bytes32);
}
34 changes: 0 additions & 34 deletions src/msca/6900/shared/erc712/IERC712Compliant.sol

This file was deleted.

4 changes: 2 additions & 2 deletions src/msca/6900/shared/libs/AddressDLLLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ import {AddressDLL} from "../common/Structs.sol";
* Item is expected to be unique.
*/
library AddressDLLLib {
address constant SENTINEL_ADDRESS = address(0x0);
uint160 constant SENTINEL_ADDRESS_UINT = 0;
address internal constant SENTINEL_ADDRESS = address(0x0);
uint160 internal constant SENTINEL_ADDRESS_UINT = 0;

event AddressAdded(address indexed addr);
event AddressRemoved(address indexed addr);
Expand Down
8 changes: 4 additions & 4 deletions src/msca/6900/v0.7/account/BaseMSCA.sol
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ import {StandardExecutor} from "../managers/StandardExecutor.sol";

import {WalletStorageInitializable} from "./WalletStorageInitializable.sol";
import {IEntryPoint} from "@account-abstraction/contracts/interfaces/IEntryPoint.sol";
import {PackedUserOperation} from "@account-abstraction/contracts/interfaces/PackedUserOperation.sol";
import {UserOperation} from "@account-abstraction/contracts/interfaces/UserOperation.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";

/**
Expand Down Expand Up @@ -163,7 +163,7 @@ abstract contract BaseMSCA is
* subclass doesn't need to override this method. Instead, it should override the specific internal validation
* methods.
*/
function validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds)
function validateUserOp(UserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds)
external
virtual
returns (uint256 validationData)
Expand Down Expand Up @@ -349,7 +349,7 @@ abstract contract BaseMSCA is
* failure.
* Note that the validation code cannot use block.timestamp (or block.number) directly due to the storage rule.
*/
function _authenticateAndAuthorizeUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash)
function _authenticateAndAuthorizeUserOp(UserOperation calldata userOp, bytes32 userOpHash)
internal
virtual
returns (uint256 validationData)
Expand Down Expand Up @@ -464,7 +464,7 @@ abstract contract BaseMSCA is

function _processPreUserOpValidationHooks(
ExecutionDetail storage executionDetail,
PackedUserOperation calldata userOp,
UserOperation calldata userOp,
bytes32 userOpHash
) internal virtual returns (ValidationData memory unpackedValidationData) {
unpackedValidationData = ValidationData(0, 0xFFFFFFFFFFFF, address(0));
Expand Down
Loading

0 comments on commit ce3055f

Please sign in to comment.