Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: merge v0.8-develop into develop #113

Merged
merged 64 commits into from
Jul 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
d666f50
feat: Remove hook group (#39)
adam-alchemy Mar 5, 2024
f6e335c
feat: [v0.8-develop, experimental] Merge validation function assignme…
adam-alchemy Apr 15, 2024
cf5355a
refactor: [v0.8-develop] 6900 iteration setup (#43)
adam-alchemy Apr 16, 2024
a66dcd8
refactor: [v0.8-develop] account test base (#44)
adam-alchemy Apr 17, 2024
8b58330
feat: [v0.8-develop] Bump solidity version and remove optimizations (…
adam-alchemy Apr 18, 2024
d9bcff3
feat: [v0.8-develop] merge pre validation types (#46)
adam-alchemy Apr 26, 2024
3b1e32e
chore: update to 4337 v0.7 (1/n) (#48)
howydev May 1, 2024
f00dba4
feat: [v0.8-develop] remove hook overlap support (#47)
adam-alchemy May 3, 2024
0f28a13
feat: [v0.8-develop] Simplify hook declaration and storage (#51)
adam-alchemy May 8, 2024
443b87b
fix: Add owner view function to manifest validation list (#55)
adamegyed May 14, 2024
59e8564
refactor: cleanup migrated content (#56)
adamegyed May 16, 2024
ed804c3
feat: [v0.8-develop, experimental] split up interfaces by type [1/N] …
adamegyed May 31, 2024
765a34f
feat: [v0.8-develop]: sig validation in interface (#59)
adamegyed May 31, 2024
7ac0f6b
feat: [v0.8-develop, experimental]: remove plugin call restriction [3…
adamegyed May 31, 2024
0923c21
feat: [v0.8-develop]: move runtime validation always allow to executi…
adamegyed May 31, 2024
3d54094
feat: [v0.8-develop] multi validation in user op signature (#62)
adamegyed Jun 10, 2024
81bef34
feat: Add various native function checks for plugin installation (#75)
fangting-alchemy Jun 18, 2024
c0a1e9d
feat: [v0.8-develop, experimental] default validation (#63)
adamegyed Jun 19, 2024
18261cb
feat: [v0.8-develop] associate pre-validation hooks with validation f…
adamegyed Jun 20, 2024
400e833
feat: [v0.8-develop] remove execute from plugin (#65)
adamegyed Jun 20, 2024
6e97d84
[1/n permissions] chore: remove existing permissions system (#67)
howydev Jun 28, 2024
f22a521
[2/n permissions] feat: add permission hooks (#76)
howydev Jul 9, 2024
f63137b
[3/n permissions] feat: add execute user operation (#77)
howydev Jul 9, 2024
de28c60
feat: [v0.8-develop] per validation hook data (#66)
adamegyed Jul 9, 2024
d8c726c
feat: [v0.8-develop] Add allowlist sample hook, refactor test base (#70)
adamegyed Jul 10, 2024
f376bf0
feat: [v0.8-develop] account self call restrictions (#78)
adamegyed Jul 10, 2024
072fa15
refactor: [v0.8-develop] invert validation mapping (#85)
adamegyed Jul 10, 2024
cfa31b1
feat: [v0.8-develop] remove plugin dependencies (#86)
adamegyed Jul 10, 2024
30596f8
style: [v0.8-develop] propose renaming default to global (#83)
adamegyed Jul 10, 2024
d50ae10
feat: [v0.8-develop] update SingleOwnerPlugin to use installValidatio…
adamegyed Jul 11, 2024
42d3db8
feat: [v0.8-develop] remove duplicate test factory [2/2] (#92)
adamegyed Jul 11, 2024
4279a97
fix: [v0.8-develop] cleanup requireUOHookCount (#95)
adamegyed Jul 16, 2024
c74d1ff
feat: add native token spend limit plugin
howydev Jun 12, 2024
8e7e33d
chore: update
howydev Jun 27, 2024
953bc11
fix: tests
howydev Jun 27, 2024
75d245e
chore: remove permission hooks, add new internal helper function for …
howydev Jun 28, 2024
c2d0910
fix: move to associated storage
howydev Jul 8, 2024
2743097
feat: add special paymaster list to still count towards limits
howydev Jul 8, 2024
a19fcda
c
howydev Jul 10, 2024
162131c
fix: lint
howydev Jul 10, 2024
1d38111
fix: lint, test
howydev Jul 10, 2024
3faa350
fix: test
howydev Jul 16, 2024
1685e91
[5/n permissions] feat: add erc20 token spend limit plugin (#80)
howydev Jul 16, 2024
d2e3c3a
feat: Validation revamp - Introduce validation composability and allo…
fangting-alchemy Jul 17, 2024
a598069
Allow direct plugin calls with validation & permission hooks (#90)
Zer0dot Jul 17, 2024
70ccd3e
style: [v0.8-develop] linter and fmt update (#98)
adamegyed Jul 17, 2024
5d0c3bb
Zer0dot/remove redundancy (#99)
Zer0dot Jul 17, 2024
a257ded
fix: Add back pluginEntityLib test and update old references and docs…
fangting-alchemy Jul 17, 2024
cca4572
fix: Rename plugin to module and update readme and docs (#106)
fangting-alchemy Jul 19, 2024
6abe02c
fix: organize all modules under modules folder (#107)
fangting-alchemy Jul 19, 2024
ce001a8
feat: [v0.8-develop] User controlled install 1/N (#101)
adamegyed Jul 23, 2024
c41cc7c
feat: [v0.8-develop] merge plugin manager contracts 2/N (#102)
adamegyed Jul 23, 2024
13a36fa
feat: add factory
howydev Jul 18, 2024
3b100c5
update: add ownable, access control
howydev Jul 18, 2024
f2ef9d0
chore: comments
howydev Jul 18, 2024
a99f86d
fix: lint
howydev Jul 19, 2024
01db0f2
test: add tests, cleanup
howydev Jul 19, 2024
268b487
chore: use immutable single signer validation
howydev Jul 19, 2024
4278acf
fix: pr review fixes
howydev Jul 22, 2024
4f8947d
feat: [v0.8-develop] Remove validation installation from the manifest…
adamegyed Jul 23, 2024
e36feac
feat: [v0.8-develop] HookConfig install parameter & internal structur…
adamegyed Jul 24, 2024
ebabd8c
test: [v0.8-develop] Add test for ValidationConfigLib 5/N (#110)
adamegyed Jul 24, 2024
b71d6c9
fix: Handle fallback hooks & entrypoint/self-call/public selector run…
Zer0dot Jul 25, 2024
27e00b5
chore: [v0.8-develop] alpha.0 deploy prep (#111)
adamegyed Jul 26, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@

# Factory owner capable only of managing stake
OWNER=
# EP 0.7 address
ENTRYPOINT=

# Create2 expected addresses of the contracts.
# When running for the first time, the error message will contain the expected addresses.
ACCOUNT_IMPL=
FACTORY=
SINGLE_SIGNER_VALIDATION=

# Optional, defaults to bytes32(0)
ACCOUNT_IMPL_SALT=
FACTORY_SALT=
SINGLE_SIGNER_VALIDATION_SALT=

# Optional, defaults to 0.1 ether and 1 day, respectively
STAKE_AMOUNT=
UNSTAKE_DELAY=
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@ node_modules/
# Coverage
report/
lcov.info

# env vars
.env
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@
[submodule "lib/forge-std"]
path = lib/forge-std
url = https://github.com/foundry-rs/forge-std
[submodule "lib/modular-account-libs"]
path = lib/modular-account-libs
url = https://github.com/erc6900/modular-account-libs
33 changes: 18 additions & 15 deletions .solhint-test.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
{
"extends": "solhint:recommended",
"rules": {
"func-name-mixedcase": "off",
"immutable-vars-naming": ["error"],
"no-unused-import": ["error"],
"compiler-version": ["error", ">=0.8.19"],
"func-visibility": ["error", { "ignoreConstructors": true }],
"max-line-length": ["error", 120],
"max-states-count": ["warn", 30],
"modifier-name-mixedcase": ["error"],
"private-vars-leading-underscore": ["error"],
"no-inline-assembly": "off",
"avoid-low-level-calls": "off"
}
"extends": "solhint:recommended",
"rules": {
"func-name-mixedcase": "off",
"immutable-vars-naming": ["error"],
"no-unused-import": ["error"],
"compiler-version": ["error", ">=0.8.19"],
"custom-errors": "off",
"func-visibility": ["error", { "ignoreConstructors": true }],
"max-line-length": ["error", 120],
"max-states-count": ["warn", 30],
"modifier-name-mixedcase": ["error"],
"private-vars-leading-underscore": ["error"],
"no-inline-assembly": "off",
"avoid-low-level-calls": "off",
"one-contract-per-file": "off",
"no-empty-blocks": "off",
"reason-string": ["warn", { "maxLength": 64 }]
}
}
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"solidity.packageDefaultDependenciesContractsDirectory": "src",
"solidity.packageDefaultDependenciesDirectory": "lib",
"solidity.compileUsingRemoteVersion": "v0.8.19",
"solidity.compileUsingRemoteVersion": "v0.8.25",
"editor.formatOnSave": true,
"[solidity]": {
"editor.defaultFormatter": "JuanBlanco.solidity"
Expand Down
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Reference implementation for [ERC-6900](https://eips.ethereum.org/EIPS/eip-6900). It is an early draft implementation.

The implementation includes an upgradable modular account with two plugins (`SingleOwnerPlugin` and `TokenReceiverPlugin`). It is compliant with ERC-6900 with the latest updates.
The implementation includes an upgradable modular account with three modules (`SingleSignerValidation`, `TokenReceiverModule`, and `AllowlistModule`). It is compliant with ERC-6900 with the latest updates.

## Important Callouts

Expand All @@ -11,7 +11,7 @@ The implementation includes an upgradable modular account with two plugins (`Sin

## Development

Anyone is welcome to submit feedback and/or PRs to improve code or add Plugins.
Anyone is welcome to submit feedback and/or PRs to improve code.

### Testing

Expand All @@ -28,3 +28,14 @@ Since IR compilation generates different bytecode, it's useful to test against t
FOUNDRY_PROFILE=optimized-build forge build
FOUNDRY_PROFILE=optimized-test forge test -vvv
```

## Integration testing

The reference implementation provides a sample factory and deploy script for the factory, account implementation, and the demo validation module `SingleSignerValidation`. This is not auditted, nor intended for production use. Limitations set by the GPL-V3 license apply.

To run this script, provide appropriate values in a `.env` file based on the `.env.example` template, then run:
```bash
forge script script/Deploy.s.sol <wallet options> -r <rpc_url> --broadcast
```

Where `<wallet_options>` specifies a way to sign the deployment transaction (see [here](https://book.getfoundry.sh/reference/forge/forge-script#wallet-options---raw)) and `<rpc_url>` specifies an RPC for the network you are deploying on.
12 changes: 9 additions & 3 deletions foundry.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
[profile.default]
solc = '0.8.19'
solc = '0.8.26'
via_ir = false
src = 'src'
test = 'test'
libs = ['lib']
out = 'out'
optimizer = true
optimizer_runs = 200
ignored_error_codes = []
auto_detect_solc = false
bytecode_hash = "none"
auto_detect_remappings = false
fs_permissions = [
{ access = "read", path = "./out-optimized" }
]
Expand All @@ -23,6 +25,7 @@ depth = 10
[profile.optimized-build]
via_ir = true
test = 'src'
optimizer_runs = 20000
out = 'out-optimized'

[profile.optimized-test]
Expand All @@ -39,7 +42,7 @@ runs = 5000
depth = 32

[profile.deep.fuzz]
runs = 10000
runs = 100000

[profile.deep.invariant]
runs = 5000
Expand All @@ -48,6 +51,9 @@ depth = 32
[fmt]
line_length = 115
wrap_comments = true
sort_imports = true
number_underscore = "thousands"
int_types = "long"

[rpc_endpoints]
mainnet = "${RPC_URL_MAINNET}"
Expand Down
2 changes: 1 addition & 1 deletion lib/account-abstraction
1 change: 1 addition & 0 deletions lib/modular-account-libs
Submodule modular-account-libs added at 5d9d0e
2 changes: 1 addition & 1 deletion lib/openzeppelin-contracts
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
},
"scripts": {
"lint": "pnpm lint:src && pnpm lint:test",
"lint:src": "solhint -c .solhint-src.json ./src/**/*.sol",
"lint:test": "solhint -c .solhint-test.json ./test/**/*.sol"
"lint:src": "solhint --max-warnings 0 -c .solhint-src.json './src/**/*.sol'",
"lint:test": "solhint --max-warnings 0 -c .solhint-test.json './test/**/*.sol'"
}
}
1 change: 1 addition & 0 deletions remappings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ ds-test/=lib/forge-std/lib/ds-test/src/
forge-std/=lib/forge-std/src/
@eth-infinitism/account-abstraction/=lib/account-abstraction/contracts/
@openzeppelin/=lib/openzeppelin-contracts/
@modular-account-libs/=lib/modular-account-libs/src/
156 changes: 156 additions & 0 deletions script/Deploy.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.25;

import {IEntryPoint} from "@eth-infinitism/account-abstraction/interfaces/IEntryPoint.sol";
import {Script} from "forge-std/Script.sol";
import {console2} from "forge-std/Test.sol";

import {Create2} from "@openzeppelin/contracts/utils/Create2.sol";

import {AccountFactory} from "../src/account/AccountFactory.sol";
import {UpgradeableModularAccount} from "../src/account/UpgradeableModularAccount.sol";
import {SingleSignerValidation} from "../src/modules/validation/SingleSignerValidation.sol";

contract DeployScript is Script {
IEntryPoint public entryPoint = IEntryPoint(payable(vm.envAddress("ENTRYPOINT")));

address public owner = vm.envAddress("OWNER");

address public accountImpl = vm.envOr("ACCOUNT_IMPL", address(0));
address public factory = vm.envOr("FACTORY", address(0));
address public singleSignerValidation = vm.envOr("SINGLE_SIGNER_VALIDATION", address(0));

bytes32 public accountImplSalt = bytes32(vm.envOr("ACCOUNT_IMPL_SALT", uint256(0)));
bytes32 public factorySalt = bytes32(vm.envOr("FACTORY_SALT", uint256(0)));
bytes32 public singleSignerValidationSalt = bytes32(vm.envOr("SINGLE_SIGNER_VALIDATION_SALT", uint256(0)));

uint256 public requiredStakeAmount = vm.envOr("STAKE_AMOUNT", uint256(0.1 ether));
uint256 public requiredUnstakeDelay = vm.envOr("UNSTAKE_DELAY", uint256(1 days));

function run() public {
console2.log("******** Deploying ERC-6900 Reference Implementation ********");
console2.log("Chain: ", block.chainid);
console2.log("EP: ", address(entryPoint));
console2.log("Factory owner: ", owner);

_deployAccountImpl(accountImplSalt, accountImpl);
_deploySingleSignerValidation(singleSignerValidationSalt, singleSignerValidation);
_deployAccountFactory(factorySalt, factory);
_addStakeForFactory(uint32(requiredUnstakeDelay), requiredStakeAmount);
}

function _deployAccountImpl(bytes32 salt, address expected) internal {
console2.log(string.concat("Deploying AccountImpl with salt: ", vm.toString(salt)));

address addr = Create2.computeAddress(
salt, keccak256(abi.encodePacked(type(UpgradeableModularAccount).creationCode, abi.encode(entryPoint)))
);
if (addr != expected) {
console2.log("Expected address mismatch");
console2.log("Expected: ", expected);
console2.log("Actual: ", addr);
revert();
}

if (addr.code.length == 0) {
console2.log("No code found at expected address, deploying...");
UpgradeableModularAccount deployed = new UpgradeableModularAccount{salt: salt}(entryPoint);

if (address(deployed) != expected) {
console2.log("Deployed address mismatch");
console2.log("Expected: ", expected);
console2.log("Deployed: ", address(deployed));
revert();
}

console2.log("Deployed AccountImpl at: ", address(deployed));
} else {
console2.log("Code found at expected address, skipping deployment");
}
}

function _deploySingleSignerValidation(bytes32 salt, address expected) internal {
console2.log(string.concat("Deploying SingleSignerValidation with salt: ", vm.toString(salt)));

address addr =
Create2.computeAddress(salt, keccak256(abi.encodePacked(type(SingleSignerValidation).creationCode)));
if (addr != expected) {
console2.log("Expected address mismatch");
console2.log("Expected: ", expected);
console2.log("Actual: ", addr);
revert();
}

if (addr.code.length == 0) {
console2.log("No code found at expected address, deploying...");
SingleSignerValidation deployed = new SingleSignerValidation{salt: salt}();

if (address(deployed) != expected) {
console2.log("Deployed address mismatch");
console2.log("Expected: ", expected);
console2.log("Deployed: ", address(deployed));
revert();
}

console2.log("Deployed SingleSignerValidation at: ", address(deployed));
} else {
console2.log("Code found at expected address, skipping deployment");
}
}

function _deployAccountFactory(bytes32 salt, address expected) internal {
console2.log(string.concat("Deploying AccountFactory with salt: ", vm.toString(salt)));

address addr = Create2.computeAddress(
salt,
keccak256(
abi.encodePacked(
type(AccountFactory).creationCode,
abi.encode(entryPoint, accountImpl, singleSignerValidation, owner)
)
)
);
if (addr != expected) {
console2.log("Expected address mismatch");
console2.log("Expected: ", expected);
console2.log("Actual: ", addr);
revert();
}

if (addr.code.length == 0) {
console2.log("No code found at expected address, deploying...");
AccountFactory deployed = new AccountFactory{salt: salt}(
entryPoint, UpgradeableModularAccount(payable(accountImpl)), singleSignerValidation, owner
);

if (address(deployed) != expected) {
console2.log("Deployed address mismatch");
console2.log("Expected: ", expected);
console2.log("Deployed: ", address(deployed));
revert();
}

console2.log("Deployed AccountFactory at: ", address(deployed));
} else {
console2.log("Code found at expected address, skipping deployment");
}
}

function _addStakeForFactory(uint32 unstakeDelay, uint256 stakeAmount) internal {
console2.log("Adding stake to factory");

uint256 currentStake = entryPoint.getDepositInfo(address(factory)).stake;
console2.log("Current stake: ", currentStake);
uint256 stakeToAdd = stakeAmount - currentStake;

if (stakeToAdd > 0) {
console2.log("Adding stake: ", stakeToAdd);
entryPoint.addStake{value: stakeToAdd}(unstakeDelay);
console2.log("Staked factory: ", address(factory));
console2.log("Total stake amount: ", entryPoint.getDepositInfo(address(factory)).stake);
console2.log("Unstake delay: ", entryPoint.getDepositInfo(address(factory)).unstakeDelaySec);
} else {
console2.log("No stake to add");
}
}
}
15 changes: 1 addition & 14 deletions src/account/AccountExecutor.sol
Original file line number Diff line number Diff line change
@@ -1,25 +1,12 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.19;

import {ERC165Checker} from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
import {IPlugin} from "../interfaces/IPlugin.sol";
pragma solidity ^0.8.25;

abstract contract AccountExecutor {
error PluginExecutionDenied(address plugin);

/// @dev If the target is a plugin (as determined by its support for the IPlugin interface), revert.
/// This prevents the modular account from calling plugins (both installed and uninstalled) outside
/// of the normal flow (via execution functions installed on the account), which could lead to data
/// inconsistencies and unexpected behavior.
/// @param target The address of the contract to call.
/// @param value The value to send with the call.
/// @param data The call data.
/// @return result The return data of the call, or the error message from the call if call reverts.
function _exec(address target, uint256 value, bytes memory data) internal returns (bytes memory result) {
if (ERC165Checker.supportsInterface(target, type(IPlugin).interfaceId)) {
revert PluginExecutionDenied(target);
}

bool success;
(success, result) = target.call{value: value}(data);

Expand Down
Loading
Loading