Skip to content

Commit

Permalink
feat: update contracts
Browse files Browse the repository at this point in the history
* v1 MSCA and plugins
* v2 MSCA and modules (WIP)
  • Loading branch information
huaweigu committed Nov 5, 2024
1 parent d395e5e commit 5f1e247
Show file tree
Hide file tree
Showing 96 changed files with 2,980 additions and 3,559 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,7 @@ jobs:
- name: Setup environment
uses: ./.github/actions/setup

# TODO report and check coverage
# TODO: fail the build if coverage is below the threshold
# TODO: print the coverage report in the github output
- name: Run Test Coverage
run: yarn coverage
1 change: 1 addition & 0 deletions .licenseignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pkg:npm/%40erc6900/reference-implementation@github:erc6900/reference-implementation#0.8.0-rc.6
3 changes: 2 additions & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ fs_permissions = [{ access = "read-write", path = "./gas"},
{ access = "read", path = "./test/fixtures"}]
src = 'src'
out = 'out'
libs = ['lib']
libs = ['lib', 'node_modules']
solc_version = "0.8.24"
test = 'test'
via_ir = true
auto_detect_solc = false
auto_detect_remappings = false
deny_warnings = true

[fuzz]
runs = 1024
Expand Down
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
"scripts": {
"clean": "rm -rf cache artifacts typechain-types",
"build": "forge build",
"lint": "solhint -w 112 -c .solhint-src.json './src/**/*.sol' && solhint -w 228 -c .solhint-test.json './test/**/*.sol' && solhint -w 0 -c .solhint-script.json './script/**/*.sol'",
"lint": "solhint -w 105 -c .solhint-src.json './src/**/*.sol' && solhint -w 228 -c .solhint-test.json './test/**/*.sol' && solhint -w 0 -c .solhint-script.json './script/**/*.sol'",
"test": "forge test -vv",
"gasreport": "forge test --gas-report > gas/reports/gas-report.txt",
"coverage": "forge coverage --ir-minimum",
"coverage": "forge coverage",
"format:check": "forge fmt --check",
"format:write": "forge fmt"
},
Expand All @@ -20,7 +20,8 @@
"@openzeppelin/contracts-upgradeable": "5.0.2",
"fcl": "github:rdubois-crypto/FreshCryptoLib#8179e08cac72072bd260796633fec41fdfd5b441",
"forge-std": "github:foundry-rs/forge-std#v1.9.2",
"solady": "0.0.243"
"solady": "0.0.243",
"@erc6900/reference-implementation": "github:erc6900/reference-implementation#v0.8.0-rc.6"
},
"devDependencies": {
"solhint": "^5.0.3"
Expand Down
2 changes: 2 additions & 0 deletions remappings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@
@solady/=node_modules/solady/src/
@fcl/=node_modules/fcl/solidity/src/
forge-std/=node_modules/forge-std/
@erc6900/reference-implementation/=node_modules/@erc6900/reference-implementation/src/
@eth-infinitism/account-abstraction/=lib/account-abstraction/contracts/
2 changes: 2 additions & 0 deletions src/msca/6900/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Acknowledgements
The contracts in this folder are based on the ERC-6900 specification and are significantly influenced by the design of the ERC-6900 reference implementation.
2 changes: 2 additions & 0 deletions src/msca/6900/shared/common/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,5 @@ error InvalidItem();

// v2 NotImplemented
error NotImplementedFunction(bytes4 selector, uint32 entityId);

error SignatureInflation();
18 changes: 17 additions & 1 deletion src/msca/6900/v0.7/account/UpgradableMSCA.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/
pragma solidity 0.8.24;

import {DefaultCallbackHandler} from "../../../../callback/DefaultCallbackHandler.sol";
import {ExecutionUtils} from "../../../../utils/ExecutionUtils.sol";
import {InvalidInitializationInput} from "../../shared/common/Errors.sol";
import {FunctionReference} from "../common/Structs.sol";
Expand All @@ -26,13 +27,17 @@ import {BaseMSCA} from "./BaseMSCA.sol";
import {IEntryPoint} from "@account-abstraction/contracts/interfaces/IEntryPoint.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";

import {IERC1271} from "@openzeppelin/contracts/interfaces/IERC1271.sol";
import {IERC1155Receiver} from "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";

/**
* @dev Leverage {ERC1967Proxy} brought by UUPS proxies, when this contract is set as the implementation behind such a
* proxy.
* The {_authorizeUpgrade} function is overridden here so more granular ACLs to the upgrade mechanism should be enforced
* by plugins.
*/
contract UpgradableMSCA is BaseMSCA, UUPSUpgradeable {
contract UpgradableMSCA is BaseMSCA, DefaultCallbackHandler, UUPSUpgradeable {
using ExecutionUtils for address;

event UpgradableMSCAInitialized(address indexed account, address indexed entryPointAddress);
Expand Down Expand Up @@ -72,6 +77,17 @@ contract UpgradableMSCA is BaseMSCA, UUPSUpgradeable {
emit UpgradableMSCAInitialized(address(this), address(entryPoint));
}

function supportsInterface(bytes4 interfaceId)
public
view
override(BaseMSCA, DefaultCallbackHandler)
returns (bool)
{
// BaseMSCA has already implemented ERC165
return BaseMSCA.supportsInterface(interfaceId) || interfaceId == type(IERC721Receiver).interfaceId
|| interfaceId == type(IERC1155Receiver).interfaceId || interfaceId == type(IERC1271).interfaceId;
}

/// @inheritdoc UUPSUpgradeable
function upgradeToAndCall(address newImplementation, bytes memory data)
public
Expand Down
8 changes: 7 additions & 1 deletion src/msca/6900/v0.7/libs/SelectorRegistryLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ import {IAggregator} from "@account-abstraction/contracts/interfaces/IAggregator
import {IPaymaster} from "@account-abstraction/contracts/interfaces/IPaymaster.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";

import {IERC777Recipient} from "@openzeppelin/contracts/interfaces/IERC777Recipient.sol";
import {IERC1155Receiver} from "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";

library SelectorRegistryLib {
Expand Down Expand Up @@ -61,7 +64,10 @@ library SelectorRegistryLib {
|| selector == IAccountLoupe.getInstalledPlugins.selector || selector == VALIDATE_USER_OP
|| selector == GET_ENTRYPOINT || selector == GET_NONCE || selector == INITIALIZE_UPGRADABLE_MSCA
|| selector == INITIALIZE_SINGLE_OWNER_MSCA || selector == TRANSFER_NATIVE_OWNERSHIP
|| selector == RENOUNCE_NATIVE_OWNERSHIP || selector == GET_NATIVE_OWNER;
|| selector == RENOUNCE_NATIVE_OWNERSHIP || selector == GET_NATIVE_OWNER
|| selector == IERC1155Receiver.onERC1155Received.selector
|| selector == IERC1155Receiver.onERC1155BatchReceived.selector
|| selector == IERC721Receiver.onERC721Received.selector || selector == IERC777Recipient.tokensReceived.selector;
}

function _isErc4337FunctionSelector(bytes4 selector) internal pure returns (bool) {
Expand Down
6 changes: 3 additions & 3 deletions src/msca/6900/v0.7/plugins/BasePlugin.sol
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ abstract contract BasePlugin is IPlugin, ERC165 {
virtual
returns (uint256 validationData)
{
(functionId, userOp, userOpHash);
(functionId, userOp, userOpHash, validationData);
revert NotImplemented(msg.sig, functionId);
}

Expand All @@ -98,7 +98,7 @@ abstract contract BasePlugin is IPlugin, ERC165 {
virtual
returns (uint256 validationData)
{
(functionId, userOp, userOpHash);
(functionId, userOp, userOpHash, validationData);
revert NotImplemented(msg.sig, functionId);
}

Expand Down Expand Up @@ -145,7 +145,7 @@ abstract contract BasePlugin is IPlugin, ERC165 {
virtual
returns (bytes memory context)
{
(functionId, sender, value, data);
(functionId, sender, value, data, context);
revert NotImplemented(msg.sig, functionId);
}

Expand Down
27 changes: 13 additions & 14 deletions src/msca/6900/v0.7/plugins/v1_0_0/multisig/BaseMultisigPlugin.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import {

import {NotImplemented} from "../../../../shared/common/Errors.sol";
import {BasePlugin} from "../../BasePlugin.sol";
import {IWeightedMultisigPlugin} from "./IWeightedMultisigPlugin.sol";

import {PackedUserOperation} from "@account-abstraction/contracts/interfaces/PackedUserOperation.sol";
import {
AssociatedLinkedListSet,
Expand Down Expand Up @@ -71,26 +73,18 @@ abstract contract BaseMultisigPlugin is BasePlugin {
AssociatedLinkedListSet internal _owners;

address public immutable ENTRYPOINT;
string constant ADD_OWNERS_PERMISSION = "Add Owners";
string constant UPDATE_MULTISIG_WEIGHTS_PERMISSION = "Update Multisig Weights";
string constant REMOVE_OWNERS_PERMISSION = "Remove Owners";
string internal constant ADD_OWNERS_PERMISSION = "Add Owners";
string internal constant UPDATE_MULTISIG_WEIGHTS_PERMISSION = "Update Multisig Weights";
string internal constant REMOVE_OWNERS_PERMISSION = "Remove Owners";

constructor(address entryPoint) {
ENTRYPOINT = entryPoint;
}

/// @notice Check if the signatures are valid for the account.
/// @param actualDigest The actual gas digest.
/// @param minimalDigest Digest of user op with minimal required fields set:
/// (address sender, uint256 nonce, bytes initCode, bytes callData), and remaining
/// fields set to default values.
/// @param account The account to check the signatures for.
/// @param signatures The signatures to check.
/// @return success True if the signatures are valid.
/// @return firstFailure first failure, if failed is true.
/// (Note: if all signatures are individually valid but do not satisfy the
/// multisig, firstFailure will be set to the last signature's index.)
function checkNSignatures(bytes32 actualDigest, bytes32 minimalDigest, address account, bytes memory signatures)
function checkNSignatures(IWeightedMultisigPlugin.CheckNSignatureInput memory input)
public
view
virtual
Expand All @@ -114,8 +108,13 @@ abstract contract BaseMultisigPlugin is BasePlugin {
if (actualUserOpDigest == minimalUserOpDigest) {
revert InvalidUserOpDigest();
}
(bool success,) = checkNSignatures(actualUserOpDigest, minimalUserOpDigest, msg.sender, userOp.signature);

IWeightedMultisigPlugin.CheckNSignatureInput memory input = IWeightedMultisigPlugin.CheckNSignatureInput({
actualDigest: actualUserOpDigest,
minimalDigest: minimalUserOpDigest,
account: msg.sender,
signatures: userOp.signature
});
(bool success,) = checkNSignatures(input);
return success ? SIG_VALIDATION_SUCCEEDED : SIG_VALIDATION_FAILED;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ abstract contract BaseWeightedMultisigPlugin is BaseMultisigPlugin, IWeightedMul
}

/// @inheritdoc IWeightedMultisigPlugin
function checkNSignatures(bytes32 actualDigest, bytes32 minimalDigest, address account, bytes memory signatures)
function checkNSignatures(CheckNSignatureInput memory inputs)
public
view
virtual
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ interface IWeightedMultisigPlugin {
error OwnersWeightsMismatch();
error ThresholdWeightExceedsTotalWeight(uint256 thresholdWeight, uint256 totalWeight);

struct CheckNSignatureInput {
bytes32 actualDigest;
bytes32 minimalDigest;
address account;
bytes signatures;
}

/// @notice Add owners and their associated weights for the account, and optionally update threshold weight required
/// to perform an action.
/// @dev Constraints:
Expand Down Expand Up @@ -141,19 +148,19 @@ interface IWeightedMultisigPlugin {
function getOwnerId(PublicKey memory pubKeyOwnerToCheck) external pure returns (bytes30);

/// @notice Check if the signatures are valid for the account.
/// @param actualDigest Digest of user op with all fields filled in.
/// At least one signature must cover the actualDigest, with a v value >= 32,
/// if it differs from the minimal digest.
/// @param minimalDigest Digest of user op with minimal required fields set:
/// @param input has minimalDigest Digest of user op with minimal required fields set:
/// (address sender, uint256 nonce, bytes initCode, bytes callData), and remaining
/// fields set to default values.
/// @param account The account to check the signatures for.
/// @param signatures The signatures to check.
/// actualDigest Digest of user op with all fields filled in.
/// At least one signature must cover the actualDigest, with a v value >= 32,
/// if it differs from the minimal digest.
/// account The account to check the signatures for.
/// signatures The signatures to check.
/// @return success True if the signatures are valid.
/// @return firstFailure first failure, if failed is true.
/// (Note: if all signatures are individually valid but do not satisfy the
/// multisig, firstFailure will be set to the last signature's index.)
function checkNSignatures(bytes32 actualDigest, bytes32 minimalDigest, address account, bytes memory signatures)
function checkNSignatures(CheckNSignatureInput memory input)
external
view
returns (bool success, uint256 firstFailure);
Expand Down
Loading

0 comments on commit 5f1e247

Please sign in to comment.