diff --git a/.github/ISSUE_TEMPLATE/Safe7579_issue_template.md b/.github/ISSUE_TEMPLATE/Safe7579_issue_template.md new file mode 100644 index 00000000..965109b2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Safe7579_issue_template.md @@ -0,0 +1,6 @@ +--- +name: Safe7579 Issue Template +about: Use this template to report a bug in the Safe7579 module +title: "[Safe7579]: [TITLE OF THE ISSUE]" +labels: safe7579, modulekit +--- diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 00000000..12842800 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,50 @@ +on: + - push + - pull_request + +jobs: + lint-modulekit: + uses: "rhinestonewtf/reusable-workflows/.github/workflows/forge-lint-workspaces.yaml@main" + with: + match-workspace: "@rhinestone/modulekit" + + build-modulekit: + uses: "rhinestonewtf/reusable-workflows/.github/workflows/forge-test-workspaces.yaml@main" + with: + match-workspace: "@rhinestone/modulekit" + + lint-safe7579: + needs: ["lint-modulekit"] + uses: "rhinestonewtf/reusable-workflows/.github/workflows/forge-lint-workspaces.yaml@main" + with: + match-workspace: "@rhinestone/safe7579" + + test-safe7579: + needs: ["build-modulekit"] + uses: "rhinestonewtf/reusable-workflows/.github/workflows/forge-test-workspaces.yaml@main" + with: + match-workspace: "@rhinestone/safe7579" + + lint-sessionkeymanager: + needs: ["lint-modulekit"] + uses: "rhinestonewtf/reusable-workflows/.github/workflows/forge-lint-workspaces.yaml@main" + with: + match-workspace: "@rhinestone/sessionkeymanager" + + test-sessionkeymanager: + needs: ["build-modulekit"] + uses: "rhinestonewtf/reusable-workflows/.github/workflows/forge-test-workspaces.yaml@main" + with: + match-workspace: "@rhinestone/sessionkeymanager" + + lint-modulekit-examples: + needs: ["lint-modulekit"] + uses: "rhinestonewtf/reusable-workflows/.github/workflows/forge-lint-workspaces.yaml@main" + with: + match-workspace: "@rhinestone/modulekit-examples" + + test-modulekit-examples: + needs: ["build-modulekit"] + uses: "rhinestonewtf/reusable-workflows/.github/workflows/forge-test-workspaces.yaml@main" + with: + match-workspace: "@rhinestone/modulekit-examples" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index 9282e829..00000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: test - -on: workflow_dispatch - -env: - FOUNDRY_PROFILE: ci - -jobs: - check: - strategy: - fail-fast: true - - name: Foundry project - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Install Foundry - uses: foundry-rs/foundry-toolchain@v1 - with: - version: nightly - - - name: Run Forge build - run: | - forge --version - forge build --sizes - id: build - - - name: Run Forge tests - run: | - forge test -vvv - id: test diff --git a/.gitignore b/.gitignore index 63d07405..f0620b6b 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,7 @@ out/ /broadcast/*/31337/ /broadcast/**/dry-run/ -gas_calculations/*.json +packages/modulekit/gas_calculations/*.json # Docs docs/ diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index e69de29b..00000000 diff --git a/CHANGELOG.md b/CHANGELOG.md index 88dc4473..aa98f61c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,26 @@ All notable changes to this project will be documented in this file. The format is based on [Common Changelog](https://common-changelog.org/). +[0.3.1]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.3.1 [0.3.0]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.3.0 [0.2.0]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.2.0 [0.1.0]: https://github.com/rhinestonewtf/modulekit/releases/tag/v0.1.0 +## [0.3.1] - 23-02-2024 + +### Changed + +- File structure: + - `packages` now includes the core components + - `examples` now includes the example modules + - `accounts` includes the account integrations (the ERC-7579 reference implementation is currently inside the `packages/modulekit` package) +- Support for the latest version of ERC-7579 +- Entrypoint address is now the official v0.7 EntryPoint address + +### Added + +- Module Examples are now in the `examples` folder + ## [0.3.0] - 01-02-2024 ### Changed diff --git a/README.md b/README.md index 82350df9..23201080 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,26 @@ For feature or change requests, feel free to open a PR, start a discussion or ge For guidance on how to create PRs, see the [CONTRIBUTING](./CONTRIBUTING.md) guide. +## Using this repo + +To install dependencies, run: + +```bash +pnpm install +``` + +To build the project, run: + +```bash +pnpm build +``` + +To run tests, run: + +```bash +pnpm test -r +``` + ## Credits - [Safe{Core} Protocol](https://github.com/safe-global/safe-core-protocol/): ExecutorManager.sol is heavily insprired by Safe's SafeProtocolManager but is compatible across all supported accounts diff --git a/accounts/safe7579/.solhintignore b/accounts/safe7579/.solhintignore new file mode 100644 index 00000000..dbd17a1c --- /dev/null +++ b/accounts/safe7579/.solhintignore @@ -0,0 +1,2 @@ +node_modules/ +test/ diff --git a/src/accounts/safe/README.md b/accounts/safe7579/README.md similarity index 100% rename from src/accounts/safe/README.md rename to accounts/safe7579/README.md diff --git a/src/accounts/safe/foundry.toml b/accounts/safe7579/foundry.toml similarity index 100% rename from src/accounts/safe/foundry.toml rename to accounts/safe7579/foundry.toml diff --git a/src/accounts/safe/package.json b/accounts/safe7579/package.json similarity index 76% rename from src/accounts/safe/package.json rename to accounts/safe7579/package.json index 9df5689a..6d0df445 100644 --- a/src/accounts/safe/package.json +++ b/accounts/safe7579/package.json @@ -1,5 +1,5 @@ { - "name": "@rhinestone/safe-erc7579", + "name": "@rhinestone/safe7579", "description": "Safe ERC7579 implementation", "license": "MIT", "version": "0.1.0", @@ -8,23 +8,26 @@ "url": "https://rhinestone.wtf" }, "bugs": { - "url": "https://github.com/rhinestonewtf/safe-erc7579/issues" + "url": "https://github.com/rhinestonewtf/modulekit/issues" }, "devDependencies": { - "@openzeppelin/contracts": "5.0.1", - "@rhinestone/modulekit": "github:rhinestonewtf/modulekit", + "@rhinestone/modulekit": "workspace:*", + "@rhinestone/sessionkeymanager": "workspace:*", "@safe-global/safe-contracts": "^1.4.1", - "@rhinestone/sessionkeymanager": "github:rhinestonewtf/sessionkeymanager", - "account-abstraction": "github:eth-infinitism/account-abstraction#develop", - "ds-test": "github:dapphub/ds-test", + "@openzeppelin/contracts": "5.0.1", + "@ERC4337/account-abstraction": "github:kopy-kat/account-abstraction#develop", + "@ERC4337/account-abstraction-v0.6": "github:eth-infinitism/account-abstraction#v0.6.0", + "erc4337-validation": "github:rhinestonewtf/erc4337-validation", + "@prb/math": "^4.0.2", "forge-std": "github:foundry-rs/forge-std", + "ds-test": "github:dapphub/ds-test", "erc7579": "github:erc7579/erc7579-implementation", - "prettier": "^2.8.8", "sentinellist": "github:zeroknots/sentinellist", "solady": "github:vectorized/solady", "solarray": "github:sablier-labs/solarray", + "solmate": "github:transmissions11/solmate", "solhint": "^4.1.1", - "solmate": "github:transmissions11/solmate" + "prettier": "^2.8.8" }, "files": [ "artifacts", @@ -33,7 +36,6 @@ "CHANGELOG.md", "LICENSE-GPL.md" ], - "homepage": "https://github.com/rhinestonewtf/safe-erc7579/#readme", "keywords": [ "blockchain", "ethereum", @@ -45,8 +47,9 @@ "publishConfig": { "access": "public" }, - "repository": "github.com/rhinestonewtf/modulekit-examples", + "repository": "github.com/rhinestonewtf/modulekit", "scripts": { + "fmt": "forge fmt", "build": "forge build", "build:optimized": "FOUNDRY_PROFILE=optimized forge build", "build:smt": "FOUNDRY_PROFILE=smt forge build", diff --git a/accounts/safe7579/remappings.txt b/accounts/safe7579/remappings.txt new file mode 100644 index 00000000..24b26f77 --- /dev/null +++ b/accounts/safe7579/remappings.txt @@ -0,0 +1,15 @@ +ds-test/=node_modules/ds-test/src/ +forge-std/=node_modules/forge-std/src/ +account-abstraction/=node_modules/@ERC4337/account-abstraction/contracts/ +account-abstraction-v0.6/=node_modules/@ERC4337/account-abstraction-v0.6/contracts/ +erc7579/=node_modules/erc7579/src/ +sentinellist/=node_modules/sentinellist/src/ +solmate/=node_modules/solmate/src/ +solady/=node_modules/solady/ +solarray/=node_modules/solarray/src/ +@rhinestone/=node_modules/@rhinestone/ +@safe-global/=node_modules/@safe-global/ +@ERC4337/=node_modules/@ERC4337/ +@openzeppelin/=node_modules/@openzeppelin/ +@prb/math/=node_modules/@prb/math/ +erc4337-validation/=node_modules/erc4337-validation/src/ diff --git a/src/accounts/safe/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol similarity index 78% rename from src/accounts/safe/src/SafeERC7579.sol rename to accounts/safe7579/src/SafeERC7579.sol index 7ceae9cd..36603ba6 100644 --- a/src/accounts/safe/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -1,34 +1,48 @@ // SPDX-License-Identifier: MIT -pragma solidity >=0.8.0 <0.9.0; +pragma solidity ^0.8.23; -import "erc7579/interfaces/IERC7579Account.sol"; -import "erc7579/interfaces/IMSA.sol"; -import "erc7579/lib/ModeLib.sol"; -import "erc7579/lib/ExecutionLib.sol"; -import "erc7579/interfaces/IERC7579Module.sol"; -import "./AccessControl.sol"; -import "./HookManager.sol"; -import "./ExecutionHelper.sol"; -import "./ModuleManager.sol"; -import "./interfaces/ISafeOp.sol"; -import { UserOperationLib } from "account-abstraction/core/UserOperationLib.sol"; -import { _packValidationData } from "account-abstraction/core/Helpers.sol"; +import { IERC7579Account, Execution } from "erc7579/interfaces/IERC7579Account.sol"; +import { IMSA } from "erc7579/interfaces/IMSA.sol"; +import { + CallType, ModeCode, ModeLib, CALLTYPE_SINGLE, CALLTYPE_BATCH +} from "erc7579/lib/ModeLib.sol"; +import { ExecutionLib } from "erc7579/lib/ExecutionLib.sol"; +import { + IValidator, + MODULE_TYPE_VALIDATOR, + MODULE_TYPE_HOOK, + MODULE_TYPE_EXECUTOR, + MODULE_TYPE_FALLBACK +} from "erc7579/interfaces/IERC7579Module.sol"; +import { AccessControl } from "./core/AccessControl.sol"; +import { HookManager } from "./core/HookManager.sol"; +import { ISafeOp, SAFE_OP_TYPEHASH } from "./interfaces/ISafeOp.sol"; +import { ISafe } from "./interfaces/ISafe.sol"; +import { + PackedUserOperation, + UserOperationLib +} from "@ERC4337/account-abstraction/contracts/core/UserOperationLib.sol"; +import { _packValidationData } from "@ERC4337/account-abstraction/contracts/core/Helpers.sol"; -contract SafeERC7579 is - ISafeOp, - IERC7579Account, - AccessControl, - ExecutionHelper, - IMSA, - HookManager -{ +/** + * @title ERC7579 Adapter for Safe accounts. + * By using Safe's Fallback and Execution modules, + * this contract creates full ERC7579 compliance to Safe accounts + * @author zeroknots.eth | rhinestone.wtf + */ +contract SafeERC7579 is ISafeOp, IERC7579Account, AccessControl, IMSA, HookManager { using UserOperationLib for PackedUserOperation; using ModeLib for ModeCode; using ExecutionLib for bytes; + error Unsupported(); + bytes32 private constant DOMAIN_SEPARATOR_TYPEHASH = 0x47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a79469218; + /** + * @inheritdoc IERC7579Account + */ function execute( ModeCode mode, bytes calldata executionCalldata @@ -36,8 +50,8 @@ contract SafeERC7579 is external payable override + withHook // ! this modifier has side effects / external calls onlyEntryPointOrSelf - withHook { CallType callType = mode.getCallType(); @@ -53,6 +67,9 @@ contract SafeERC7579 is } } + /** + * @inheritdoc IERC7579Account + */ function executeFromExecutor( ModeCode mode, bytes calldata executionCalldata @@ -61,7 +78,7 @@ contract SafeERC7579 is payable override onlyExecutorModule - withHook + withHook // ! this modifier has side effects / external calls returns (bytes[] memory returnData) { CallType callType = mode.getCallType(); @@ -79,13 +96,22 @@ contract SafeERC7579 is } } + /** + * @inheritdoc IERC7579Account + */ function executeUserOp(PackedUserOperation calldata userOp) external payable override onlyEntryPointOrSelf - { } + { + (bool success,) = address(this).delegatecall(userOp.callData[4:]); + if (!success) revert ExecutionFailed(); + } + /** + * @inheritdoc IERC7579Account + */ function validateUserOp( PackedUserOperation calldata userOp, bytes32 userOpHash, @@ -98,11 +124,12 @@ contract SafeERC7579 is { address validator; uint256 nonce = userOp.nonce; + // solhint-disable-next-line no-inline-assembly assembly { validator := shr(96, nonce) } - // check if validator is enabled. If terminate the validation phase. + // check if validator is enabled. If not, use Safe's checkSignatures() if (!_isValidatorInstalled(validator)) return _validateSignatures(userOp); // bubble up the return value of the validator module @@ -110,9 +137,12 @@ contract SafeERC7579 is // pay prefund if (missingAccountFunds != 0) { - ISafe(userOp.getSender()).execTransactionFromModule( - entryPoint(), missingAccountFunds, "", 0 - ); + _execute({ + safe: userOp.getSender(), + target: entryPoint(), + value: missingAccountFunds, + callData: "" + }); } } @@ -142,8 +172,14 @@ contract SafeERC7579 is } } + /** + * @inheritdoc IERC7579Account + */ function isValidSignature(bytes32 hash, bytes calldata data) external view returns (bytes4) { } + /** + * @inheritdoc IERC7579Account + */ function installModule( uint256 moduleType, address module, @@ -162,6 +198,9 @@ contract SafeERC7579 is emit ModuleInstalled(moduleType, module); } + /** + * @inheritdoc IERC7579Account + */ function uninstallModule( uint256 moduleType, address module, @@ -180,6 +219,9 @@ contract SafeERC7579 is emit ModuleUninstalled(moduleType, module); } + /** + * @inheritdoc IERC7579Account + */ function supportsAccountMode(ModeCode encodedMode) external pure override returns (bool) { CallType callType = encodedMode.getCallType(); if (callType == CALLTYPE_BATCH) return true; @@ -187,13 +229,20 @@ contract SafeERC7579 is else return false; } + /** + * @inheritdoc IERC7579Account + */ function supportsModule(uint256 moduleTypeId) external pure override returns (bool) { if (moduleTypeId == MODULE_TYPE_VALIDATOR) return true; else if (moduleTypeId == MODULE_TYPE_EXECUTOR) return true; else if (moduleTypeId == MODULE_TYPE_FALLBACK) return true; + else if (moduleTypeId == MODULE_TYPE_HOOK) return true; else return false; } + /** + * @inheritdoc IERC7579Account + */ function isModuleInstalled( uint256 moduleType, address module, @@ -211,8 +260,11 @@ contract SafeERC7579 is else return false; } + /** + * @inheritdoc IERC7579Account + */ function accountId() external pure override returns (string memory accountImplementationId) { - return "safe-erc7579.v0.0.1"; + return "safe-erc7579.v0.0.0"; } /** @@ -293,20 +345,19 @@ contract SafeERC7579 is } } + /** + * Domain Separator for EIP-712. + */ function domainSeparator() public view returns (bytes32) { return keccak256(abi.encode(DOMAIN_SEPARATOR_TYPEHASH, block.chainid, this)); } function initializeAccount(bytes calldata data) external payable { _initModuleManager(); - (address[] memory validators, address[] memory executors) = - abi.decode(data, (address[], address[])); - for (uint256 i = 0; i < validators.length; i++) { - _installValidator(validators[i], data); - } - for (uint256 i = 0; i < executors.length; i++) { - _installExecutor(executors[i], data); - } + (address bootstrap, bytes memory bootstrapCall) = abi.decode(data, (address, bytes)); + + (bool success,) = bootstrap.delegatecall(bootstrapCall); + if (!success) revert AccountInitializationFailed(); } } diff --git a/src/accounts/safe/src/AccessControl.sol b/accounts/safe7579/src/core/AccessControl.sol similarity index 90% rename from src/accounts/safe/src/AccessControl.sol rename to accounts/safe7579/src/core/AccessControl.sol index 8e5e7f02..5a866403 100644 --- a/src/accounts/safe/src/AccessControl.sol +++ b/accounts/safe7579/src/core/AccessControl.sol @@ -13,6 +13,6 @@ contract AccessControl is HandlerContext, AccountBase { } function entryPoint() public view virtual override returns (address) { - return 0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789; + return 0x0000000071727De22E5E9d8BAf0edAc6f37da032; } } diff --git a/accounts/safe7579/src/core/ExecutionHelper.sol b/accounts/safe7579/src/core/ExecutionHelper.sol new file mode 100644 index 00000000..8cf4953d --- /dev/null +++ b/accounts/safe7579/src/core/ExecutionHelper.sol @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0 <0.9.0; + +import { Execution } from "erc7579/interfaces/IERC7579Account.sol"; +import { ISafe } from "../interfaces/ISafe.sol"; + +/** + * @title Helper contract to execute transactions from a safe + * All functions implemented in this contract check, + * that the transaction was successful + * @author zeroknots.eth + */ +abstract contract ExecutionHelper { + error ExecutionFailed(); + + /** + * Execute call on Safe + * @dev This function will revert if the call fails + * @param safe address of the safe + * @param target address of the contract to call + * @param value value of the transaction + * @param callData data of the transaction + */ + function _execute( + address safe, + address target, + uint256 value, + bytes memory callData + ) + internal + { + bool success = ISafe(safe).execTransactionFromModule(target, value, callData, 0); + if (!success) revert ExecutionFailed(); + } + + /** + * Execute call on Safe, get return value from call + * @dev This function will revert if the call fails + * @param safe address of the safe + * @param target address of the contract to call + * @param value value of the transaction + * @param callData data of the transaction + * @return returnData data returned from the call + */ + function _executeReturnData( + address safe, + address target, + uint256 value, + bytes memory callData + ) + internal + returns (bytes memory returnData) + { + bool success; + (success, returnData) = + ISafe(safe).execTransactionFromModuleReturnData(target, value, callData, 0); + if (!success) revert ExecutionFailed(); + } + + /** + * Execute call on Safe + * @dev This function will revert if the call fails + * @param safe address of the safe + * @param executions ERC-7579 struct for batched executions + */ + function _execute(address safe, Execution[] calldata executions) internal { + uint256 length = executions.length; + for (uint256 i; i < length; i++) { + Execution calldata execution = executions[i]; + _execute(safe, execution.target, execution.value, execution.callData); + } + } + + /** + * Execute call on Safe + * @dev This function will revert if the call fails + * @param safe address of the safe + * @param executions ERC-7579 struct for batched executions + * @return returnDatas array returned datas from the batched calls + */ + function _executeReturnData( + address safe, + Execution[] calldata executions + ) + internal + returns (bytes[] memory returnDatas) + { + uint256 length = executions.length; + returnDatas = new bytes[](length); + for (uint256 i; i < length; i++) { + Execution calldata execution = executions[i]; + returnDatas[i] = + _executeReturnData(safe, execution.target, execution.value, execution.callData); + } + } +} diff --git a/accounts/safe7579/src/core/HookManager.sol b/accounts/safe7579/src/core/HookManager.sol new file mode 100644 index 00000000..1330e279 --- /dev/null +++ b/accounts/safe7579/src/core/HookManager.sol @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import { ModuleManager } from "./ModuleManager.sol"; +import { IHook, IModule } from "erc7579/interfaces/IERC7579Module.sol"; + +/** + * @title reference implementation of HookManager + * @author zeroknots.eth | rhinestone.wtf + */ +abstract contract HookManager is ModuleManager { + mapping(address smartAccount => address hook) internal $hookManager; + + error HookPostCheckFailed(); + error HookAlreadyInstalled(address currentHook); + + modifier withHook() { + address hook = $hookManager[msg.sender]; + bool isHookEnabled = hook != address(0); + bytes memory hookPreContext; + + // pre hook + if (isHookEnabled) hookPreContext = _doPreHook(hook); + + _; // <-- hooked Function Bytecode here + + // post hook + if (isHookEnabled) _doPostHook(hook, hookPreContext); + } + + function _doPreHook(address hook) internal returns (bytes memory hookPreContext) { + hookPreContext = abi.decode( + _executeReturnData({ + safe: msg.sender, + target: hook, + value: 0, + callData: abi.encodeCall(IHook.preCheck, (_msgSender(), msg.data)) + }), + (bytes) + ); + } + + function _doPostHook(address hook, bytes memory hookPreContext) internal { + _execute({ + safe: msg.sender, + target: hook, + value: 0, + callData: abi.encodeCall(IHook.postCheck, (hookPreContext)) + }); + } + + function _installHook(address hook, bytes calldata data) internal virtual { + address currentHook = $hookManager[msg.sender]; + if (currentHook != address(0)) { + revert HookAlreadyInstalled(currentHook); + } + $hookManager[msg.sender] = hook; + _execute({ + safe: msg.sender, + target: hook, + value: 0, + callData: abi.encodeCall(IModule.onInstall, (data)) + }); + } + + function _uninstallHook(address hook, bytes calldata data) internal virtual { + $hookManager[msg.sender] = address(0); + _execute({ + safe: msg.sender, + target: hook, + value: 0, + callData: abi.encodeCall(IModule.onUninstall, (data)) + }); + } + + function _isHookInstalled(address module) internal view returns (bool) { + return $hookManager[msg.sender] == module; + } + + function getActiveHook() external view returns (address hook) { + return $hookManager[msg.sender]; + } +} diff --git a/accounts/safe7579/src/core/ModuleManager.sol b/accounts/safe7579/src/core/ModuleManager.sol new file mode 100644 index 00000000..1d242bc4 --- /dev/null +++ b/accounts/safe7579/src/core/ModuleManager.sol @@ -0,0 +1,224 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import { SentinelListLib } from "sentinellist/SentinelList.sol"; +import { SentinelList4337Lib } from "sentinellist/SentinelList4337.sol"; +import { IModule } from "erc7579/interfaces/IERC7579Module.sol"; +import { ExecutionHelper } from "./ExecutionHelper.sol"; +import { Receiver } from "erc7579/core/Receiver.sol"; +import { AccessControl } from "./AccessControl.sol"; + +struct ModuleManagerStorage { + // linked list of executors. List is initialized by initializeAccount() + SentinelListLib.SentinelList _executors; + // single fallback handler for all fallbacks + address fallbackHandler; +} + +/** + * @title ModuleManager + * Contract that implements ERC7579 Module compatibility for Safe accounts + * @author zeroknots.eth | rhinestone.wtf + */ +abstract contract ModuleManager is AccessControl, Receiver, ExecutionHelper { + using SentinelListLib for SentinelListLib.SentinelList; + using SentinelList4337Lib for SentinelList4337Lib.SentinelList; + + error InvalidModule(address module); + error LinkedListError(); + error CannotRemoveLastValidator(); + error InitializerError(); + error ValidatorStorageHelperError(); + error NoFallbackHandler(); + + mapping(address smartAccount => ModuleManagerStorage moduleManagerStorage) internal + $moduleManager; + + SentinelList4337Lib.SentinelList internal $validators; + + modifier onlyExecutorModule() { + if (!_isExecutorInstalled(_msgSender())) revert InvalidModule(_msgSender()); + _; + } + + /** + * Initializes linked list that handles installed Validator and Executor + */ + function _initModuleManager() internal { + ModuleManagerStorage storage $mms = $moduleManager[msg.sender]; + // this will revert if list is already initialized + $validators.init({ account: msg.sender }); + $mms._executors.init(); + } + + ///////////////////////////////////////////////////// + // Manage Validators + //////////////////////////////////////////////////// + /** + * install and initialize validator module + */ + function _installValidator(address validator, bytes memory data) internal virtual { + $validators.push({ account: msg.sender, newEntry: validator }); + + // Initialize Validator Module via Safe + _execute({ + safe: msg.sender, + target: validator, + value: 0, + callData: abi.encodeCall(IModule.onInstall, (data)) + }); + } + + /** + * Uninstall and de-initialize validator module + */ + function _uninstallValidator(address validator, bytes memory data) internal { + (address prev, bytes memory disableModuleData) = abi.decode(data, (address, bytes)); + $validators.pop({ account: msg.sender, prevEntry: prev, popEntry: validator }); + + // De-Initialize Validator Module via Safe + _execute({ + safe: msg.sender, + target: validator, + value: 0, + callData: abi.encodeCall(IModule.onUninstall, (disableModuleData)) + }); + } + + /** + * Helper function that will calculate storage slot for + * validator address within the linked list in ValidatorStorageHelper + * and use Safe's getStorageAt() to read 32bytes from Safe's storage + */ + function _isValidatorInstalled(address validator) + internal + view + virtual + returns (bool isInstalled) + { + isInstalled = $validators.contains({ account: msg.sender, entry: validator }); + } + + function getValidatorPaginated( + address start, + uint256 pageSize + ) + external + view + virtual + returns (address[] memory array, address next) + { + return $validators.getEntriesPaginated({ + account: msg.sender, + start: start, + pageSize: pageSize + }); + } + + ///////////////////////////////////////////////////// + // Manage Executors + //////////////////////////////////////////////////// + + function _installExecutor(address executor, bytes memory data) internal { + SentinelListLib.SentinelList storage $executors = $moduleManager[msg.sender]._executors; + $executors.push(executor); + // Initialize Executor Module via Safe + _execute({ + safe: msg.sender, + target: executor, + value: 0, + callData: abi.encodeCall(IModule.onInstall, (data)) + }); + } + + function _uninstallExecutor(address executor, bytes calldata data) internal { + SentinelListLib.SentinelList storage $executors = $moduleManager[msg.sender]._executors; + (address prev, bytes memory disableModuleData) = abi.decode(data, (address, bytes)); + $executors.pop(prev, executor); + + // De-Initialize Executor Module via Safe + _execute({ + safe: msg.sender, + target: executor, + value: 0, + callData: abi.encodeCall(IModule.onUninstall, (disableModuleData)) + }); + } + + function _isExecutorInstalled(address executor) internal view virtual returns (bool) { + SentinelListLib.SentinelList storage $executors = $moduleManager[msg.sender]._executors; + return $executors.contains(executor); + } + + function getExecutorsPaginated( + address cursor, + uint256 size + ) + external + view + virtual + returns (address[] memory array, address next) + { + SentinelListLib.SentinelList storage $executors = $moduleManager[msg.sender]._executors; + return $executors.getEntriesPaginated(cursor, size); + } + + ///////////////////////////////////////////////////// + // Manage Fallback + //////////////////////////////////////////////////// + function _installFallbackHandler(address handler, bytes calldata initData) internal virtual { + ModuleManagerStorage storage $mms = $moduleManager[msg.sender]; + $mms.fallbackHandler = handler; + // Initialize Fallback Module via Safe + _execute({ + safe: msg.sender, + target: handler, + value: 0, + callData: abi.encodeCall(IModule.onInstall, (initData)) + }); + } + + function _uninstallFallbackHandler(address handler, bytes calldata initData) internal virtual { + ModuleManagerStorage storage $mms = $moduleManager[msg.sender]; + $mms.fallbackHandler = address(0); + // De-Initialize Fallback Module via Safe + _execute({ + safe: msg.sender, + target: handler, + value: 0, + callData: abi.encodeCall(IModule.onUninstall, (initData)) + }); + } + + function _getFallbackHandler() internal view virtual returns (address fallbackHandler) { + ModuleManagerStorage storage $mms = $moduleManager[msg.sender]; + return $mms.fallbackHandler; + } + + function _isFallbackHandlerInstalled(address _handler) internal view virtual returns (bool) { + return _getFallbackHandler() == _handler; + } + + function getActiveFallbackHandler() external view virtual returns (address) { + return _getFallbackHandler(); + } + + // FALLBACK + // solhint-disable-next-line no-complex-fallback + fallback() external payable override(Receiver) receiverFallback { + address handler = _getFallbackHandler(); + if (handler == address(0)) revert NoFallbackHandler(); + + bytes memory retData = _executeReturnData({ + safe: msg.sender, + target: handler, + value: msg.value, + callData: abi.encodePacked(msg.data, _msgSender()) // ERC2771 + }); + + // solhint-disable-next-line no-inline-assembly + assembly { + return(add(retData, 0x20), mload(retData)) + } + } +} diff --git a/src/accounts/safe/src/interfaces/ISafe.sol b/accounts/safe7579/src/interfaces/ISafe.sol similarity index 98% rename from src/accounts/safe/src/interfaces/ISafe.sol rename to accounts/safe7579/src/interfaces/ISafe.sol index bcd310d8..04c6b4a5 100644 --- a/src/accounts/safe/src/interfaces/ISafe.sol +++ b/accounts/safe7579/src/interfaces/ISafe.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: LGPL-3.0-only -pragma solidity >=0.7.0 <0.9.0; +pragma solidity ^0.8.0; interface ISafe { /** diff --git a/src/accounts/safe/src/interfaces/ISafeOp.sol b/accounts/safe7579/src/interfaces/ISafeOp.sol similarity index 100% rename from src/accounts/safe/src/interfaces/ISafeOp.sol rename to accounts/safe7579/src/interfaces/ISafeOp.sol diff --git a/accounts/safe7579/src/utils/Boostrap.sol b/accounts/safe7579/src/utils/Boostrap.sol new file mode 100644 index 00000000..46981a1b --- /dev/null +++ b/accounts/safe7579/src/utils/Boostrap.sol @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.21; + +import { ModuleManager } from "../core/ModuleManager.sol"; +import { HookManager } from "../core/HookManager.sol"; + +import { IModule } from "erc7579/interfaces/IERC7579Module.sol"; + +struct BootstrapConfig { + address module; + bytes data; +} + +contract Bootstrap is ModuleManager, HookManager { + function singleInitMSA(IModule validator, bytes calldata data) external { + // init validator + _installValidator(address(validator), data); + } + + /** + * This function is intended to be called by the MSA with a delegatecall. + * Make sure that the MSA already initilazed the linked lists in the ModuleManager prior to + * calling this function + */ + function initMSA( + BootstrapConfig[] calldata _validators, + BootstrapConfig[] calldata _executors, + BootstrapConfig calldata _hook, + BootstrapConfig calldata _fallback + ) + external + { + // init validators + for (uint256 i; i < _validators.length; i++) { + _installValidator(_validators[i].module, _validators[i].data); + } + + // init executors + for (uint256 i; i < _executors.length; i++) { + if (_executors[i].module == address(0)) continue; + _installExecutor(_executors[i].module, _executors[i].data); + } + + // init hook + if (_hook.module != address(0)) { + _installHook(_hook.module, _hook.data); + } + + // init fallback + if (_fallback.module != address(0)) { + _installFallbackHandler(_fallback.module, _fallback.data); + } + } + + function _getInitMSACalldata( + BootstrapConfig[] calldata _validators, + BootstrapConfig[] calldata _executors, + BootstrapConfig calldata _hook, + BootstrapConfig calldata _fallback + ) + external + view + returns (bytes memory init) + { + init = abi.encode( + address(this), abi.encodeCall(this.initMSA, (_validators, _executors, _hook, _fallback)) + ); + } +} diff --git a/accounts/safe7579/test/Base.t.sol b/accounts/safe7579/test/Base.t.sol new file mode 100644 index 00000000..70978819 --- /dev/null +++ b/accounts/safe7579/test/Base.t.sol @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import "forge-std/Test.sol"; +import { SafeERC7579 } from "src/SafeERC7579.sol"; +import { ModuleManager } from "src/core/ModuleManager.sol"; +import { MockValidator } from "./mocks/MockValidator.sol"; +import { MockExecutor } from "./mocks/MockExecutor.sol"; +import { MockFallback } from "./mocks/MockFallback.sol"; +import { MockTarget } from "@rhinestone/modulekit/src/mocks/MockTarget.sol"; + +import { Safe } from "@safe-global/safe-contracts/contracts/Safe.sol"; +import { LibClone } from "solady/src/utils/LibClone.sol"; + +import "./dependencies/EntryPoint.sol"; + +contract Bootstrap is ModuleManager { + function singleInitMSA( + address validator, + bytes calldata validatorData, + address executor, + bytes calldata executorData + ) + external + { + // init validator + _installValidator(address(validator), validatorData); + _installExecutor(executor, executorData); + } +} + +contract TestBaseUtil is Test { + // singletons + SafeERC7579 internal erc7579Mod; + Safe internal safeImpl; + Safe internal safe; + IEntryPoint internal entrypoint = IEntryPoint(ENTRYPOINT_ADDR); + + MockValidator internal defaultValidator; + MockExecutor internal defaultExecutor; + Bootstrap internal bootstrap; + + MockTarget internal target; + + Account internal signer1; + Account internal signer2; + + function setUp() public virtual { + // Set up EntryPoint + etchEntrypoint(); + + // Set up MSA and Factory + bootstrap = new Bootstrap(); + erc7579Mod = new SafeERC7579(); + safeImpl = new Safe(); + + signer1 = makeAccount("signer1"); + signer2 = makeAccount("signer2"); + + // Set up Modules + defaultExecutor = new MockExecutor(); + defaultValidator = new MockValidator(); + + // Set up Target for testing + target = new MockTarget(); + + (safe,) = safeSetup(); + vm.deal(address(safe), 100 ether); + } + + function safeSetup() internal returns (Safe clone, address _defaultValidator) { + clone = Safe(payable(LibClone.clone(address(safeImpl)))); + _defaultValidator = address(defaultValidator); + + address[] memory signers = new address[](2); + signers[0] = signer1.addr; + signers[1] = signer2.addr; + + clone.setup({ + _owners: signers, + _threshold: 2, + to: address(0), // optional delegatecall + data: "", + fallbackHandler: address(erc7579Mod), + paymentToken: address(0), // optional payment token + payment: 0, + paymentReceiver: payable(address(0)) // optional payment receiver + }); + + vm.startPrank(address(clone)); + clone.enableModule(address(erc7579Mod)); + erc7579Mod.initializeAccount( + abi.encode( + address(bootstrap), + abi.encodeCall( + Bootstrap.singleInitMSA, (_defaultValidator, "", address(defaultExecutor), "") + ) + ) + ); + vm.stopPrank(); + } + + function getNonce(address account, address validator) internal view returns (uint256 nonce) { + uint192 key = uint192(bytes24(bytes20(address(validator)))); + nonce = entrypoint.getNonce(address(account), key); + } + + function getDefaultUserOp() internal pure returns (PackedUserOperation memory userOp) { + userOp = PackedUserOperation({ + sender: address(0), + nonce: 0, + initCode: "", + callData: "", + accountGasLimits: bytes32(abi.encodePacked(uint128(2e6), uint128(2e6))), + preVerificationGas: 2e6, + gasFees: bytes32(abi.encodePacked(uint128(2e6), uint128(2e6))), + paymasterAndData: bytes(""), + signature: abi.encodePacked(hex"41414141") + }); + } +} diff --git a/accounts/safe7579/test/SafeERC7579.t.sol b/accounts/safe7579/test/SafeERC7579.t.sol new file mode 100644 index 00000000..fe8c6baa --- /dev/null +++ b/accounts/safe7579/test/SafeERC7579.t.sol @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import "erc7579/interfaces/IERC7579Account.sol"; +import "erc7579/lib/ModeLib.sol"; +import "erc7579/lib/ExecutionLib.sol"; +import { TestBaseUtil, MockTarget, MockFallback } from "./Base.t.sol"; + +contract MSATest is TestBaseUtil { + function setUp() public override { + super.setUp(); + } + + function test_execSingle() public { + // Create calldata for the account to execute + bytes memory setValueOnTarget = abi.encodeCall(MockTarget.set, 1337); + + // Encode the call into the calldata for the userOp + bytes memory userOpCalldata = abi.encodeCall( + IERC7579Account.execute, + ( + ModeLib.encodeSimpleSingle(), + ExecutionLib.encodeSingle(address(target), uint256(0), setValueOnTarget) + ) + ); + + // Get the account, initcode and nonce + uint256 nonce = getNonce(address(safe), address(defaultValidator)); + + // Create the userOp and add the data + PackedUserOperation memory userOp = getDefaultUserOp(); + userOp.sender = address(safe); + userOp.nonce = nonce; + userOp.initCode = ""; + userOp.callData = userOpCalldata; + + // Create userOps array + PackedUserOperation[] memory userOps = new PackedUserOperation[](1); + userOps[0] = userOp; + + // Send the userOp to the entrypoint + entrypoint.handleOps(userOps, payable(address(0x69))); + + // Assert that the value was set ie that execution was successful + assertTrue(target.value() == 1337); + } + + function test_execBatch() public { + // Create calldata for the account to execute + bytes memory setValueOnTarget = abi.encodeCall(MockTarget.set, 1337); + address target2 = address(0x420); + uint256 target2Amount = 1 wei; + + // Create the executions + Execution[] memory executions = new Execution[](2); + executions[0] = Execution({ target: address(target), value: 0, callData: setValueOnTarget }); + executions[1] = Execution({ target: address(target), value: 0, callData: setValueOnTarget }); + + // Encode the call into the calldata for the userOp + bytes memory userOpCalldata = abi.encodeCall( + IERC7579Account.execute, + (ModeLib.encodeSimpleBatch(), ExecutionLib.encodeBatch(executions)) + ); + + address account = address(safe); + uint256 nonce = getNonce(account, address(defaultValidator)); + + // Create the userOp and add the data + PackedUserOperation memory userOp = getDefaultUserOp(); + userOp.sender = address(account); + userOp.nonce = nonce; + userOp.initCode = ""; + userOp.callData = userOpCalldata; + + // Create userOps array + PackedUserOperation[] memory userOps = new PackedUserOperation[](1); + userOps[0] = userOp; + + // Send the userOp to the entrypoint + entrypoint.handleOps(userOps, payable(address(0x69))); + + // Assert that the value was set ie that execution was successful + assertTrue(target.value() == 1337); + } + + function test_execViaExecutor() public { + defaultExecutor.executeViaAccount( + IERC7579Account(address(safe)), + address(target), + 0, + abi.encodeWithSelector(MockTarget.set.selector, 1337) + ); + } + + function test_execBatchFromExecutor() public { + bytes memory setValueOnTarget = abi.encodeCall(MockTarget.set, 1338); + Execution[] memory executions = new Execution[](2); + executions[0] = Execution({ target: address(target), value: 0, callData: setValueOnTarget }); + executions[1] = Execution({ target: address(target), value: 0, callData: setValueOnTarget }); + bytes[] memory ret = defaultExecutor.execBatch({ + account: IERC7579Account(address(safe)), + execs: executions + }); + + assertEq(ret.length, 2); + assertEq(abi.decode(ret[0], (uint256)), 1338); + } + + function test_fallback() public { + MockFallback _fallback = new MockFallback(); + vm.prank(address(safe)); + IERC7579Account(address(safe)).installModule(3, address(_fallback), ""); + (uint256 ret, address erc2771Sender, address msgSender) = + MockFallback(address(safe)).target(1337); + + assertEq(ret, 1337); + assertEq(erc2771Sender, address(this)); + assertEq(msgSender, address(safe)); + } +} diff --git a/accounts/safe7579/test/dependencies/EntryPoint.sol b/accounts/safe7579/test/dependencies/EntryPoint.sol new file mode 100644 index 00000000..466d0093 --- /dev/null +++ b/accounts/safe7579/test/dependencies/EntryPoint.sol @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.21; + +import "account-abstraction/interfaces/IEntryPoint.sol"; +import { IEntryPoint } from "account-abstraction/interfaces/IEntryPoint.sol"; +import { EntryPoint, SenderCreator } from "account-abstraction/core/EntryPoint.sol"; +import { EntryPointSimulations } from "account-abstraction/core/EntryPointSimulations.sol"; + +contract EntryPointSimulationsPatch is EntryPointSimulations { + address _entrypointAddr = address(this); + + SenderCreator _newSenderCreator; + + function init(address entrypointAddr) public { + _entrypointAddr = entrypointAddr; + initSenderCreator(); + } + + function initSenderCreator() internal override { + //this is the address of the first contract created with CREATE by this address. + address createdObj = address( + uint160(uint256(keccak256(abi.encodePacked(hex"d694", _entrypointAddr, hex"01")))) + ); + _newSenderCreator = SenderCreator(createdObj); + } + + function senderCreator() internal view virtual override returns (SenderCreator) { + return _newSenderCreator; + } +} + +address constant ENTRYPOINT_ADDR = 0x0000000071727De22E5E9d8BAf0edAc6f37da032; + +function etchEntrypoint() returns (IEntryPoint) { + address payable entryPoint = payable(address(new EntryPointSimulationsPatch())); + etch(ENTRYPOINT_ADDR, entryPoint.code); + EntryPointSimulationsPatch(payable(ENTRYPOINT_ADDR)).init(entryPoint); + + return IEntryPoint(ENTRYPOINT_ADDR); +} + +import "forge-std/Vm.sol"; + +address constant VM_ADDR = 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D; + +function getAddr(uint256 pk) pure returns (address) { + return Vm(VM_ADDR).addr(pk); +} + +function sign(uint256 pk, bytes32 msgHash) pure returns (uint8 v, bytes32 r, bytes32 s) { + return Vm(VM_ADDR).sign(pk, msgHash); +} + +function etch(address target, bytes memory runtimeBytecode) { + Vm(VM_ADDR).etch(target, runtimeBytecode); +} + +function label(address _addr, string memory _label) { + Vm(VM_ADDR).label(_addr, _label); +} + +function expectEmit() { + Vm(VM_ADDR).expectEmit(); +} + +function recordLogs() { + Vm(VM_ADDR).recordLogs(); +} + +function getRecordedLogs() returns (VmSafe.Log[] memory) { + return Vm(VM_ADDR).getRecordedLogs(); +} + +function prank(address _addr) { + Vm(VM_ADDR).prank(_addr); +} diff --git a/accounts/safe7579/test/mocks/MockExecutor.sol b/accounts/safe7579/test/mocks/MockExecutor.sol new file mode 100644 index 00000000..04cec703 --- /dev/null +++ b/accounts/safe7579/test/mocks/MockExecutor.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import { IERC7579Account, Execution } from "erc7579/interfaces/IERC7579Account.sol"; +import { ExecutionLib } from "erc7579/lib/ExecutionLib.sol"; +import { ModeLib } from "erc7579/lib/ModeLib.sol"; +import { MockExecutor as MockExecutorBase } from "@rhinestone/modulekit/src/mocks/MockExecutor.sol"; + +contract MockExecutor is MockExecutorBase { + function executeViaAccount( + IERC7579Account account, + address target, + uint256 value, + bytes calldata callData + ) + external + returns (bytes[] memory returnData) + { + return account.executeFromExecutor( + ModeLib.encodeSimpleSingle(), ExecutionLib.encodeSingle(target, value, callData) + ); + } + + function execBatch( + IERC7579Account account, + Execution[] calldata execs + ) + external + returns (bytes[] memory returnData) + { + return account.executeFromExecutor( + ModeLib.encodeSimpleBatch(), ExecutionLib.encodeBatch(execs) + ); + } +} diff --git a/accounts/safe7579/test/mocks/MockFallback.sol b/accounts/safe7579/test/mocks/MockFallback.sol new file mode 100644 index 00000000..acb84d76 --- /dev/null +++ b/accounts/safe7579/test/mocks/MockFallback.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import { HandlerContext } from "@safe-global/safe-contracts/contracts/handler/HandlerContext.sol"; +import { MockFallback as MockFallbackBase } from "@rhinestone/modulekit/src/mocks/MockFallback.sol"; + +contract MockFallback is MockFallbackBase, HandlerContext { + function target(uint256 value) + external + returns (uint256 _value, address erc2771Sender, address msgSender) + { + _value = value; + erc2771Sender = _msgSender(); + msgSender = msg.sender; + } +} diff --git a/accounts/safe7579/test/mocks/MockValidator.sol b/accounts/safe7579/test/mocks/MockValidator.sol new file mode 100644 index 00000000..d11cbd01 --- /dev/null +++ b/accounts/safe7579/test/mocks/MockValidator.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import { PackedUserOperation } from "erc7579/interfaces/IERC7579Module.sol"; +import { MockValidator as MockValidatorBase } from + "@rhinestone/modulekit/src/mocks/MockValidator.sol"; + +contract MockValidator is MockValidatorBase { + function validateUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash + ) + external + override + returns (ValidationData) + { + bytes4 execSelector = bytes4(userOp.callData[:4]); + + return VALIDATION_SUCCESS; + } +} diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 00000000..55603dfa --- /dev/null +++ b/examples/README.md @@ -0,0 +1,35 @@ +## ModuleKit Examples + +**Example modules built using the ModuleKit** + +Modules: + +- AutoSavings +- AutoSend +- ColdStorage +- Deadman Switch +- Dollar Cost Averaging +- ERC1271 PreHash Validator +- Multi Factor Authentication +- ECDSA Validator (OwnableValidator) +- Scheduled Transactions +- Automated Token Revocation +- Webauthn Validator + +## Usage as part of ModuleKit + +### Install dependencies + +```shell +pnpm install +``` + +### Testing modules + +```shell +pnpm test -r +``` + +## Learn more + +For more information, check out the [ModuleKit documentation](https://docs.rhinestone.wtf/modulekit). diff --git a/examples/foundry.toml b/examples/foundry.toml new file mode 100644 index 00000000..8e068472 --- /dev/null +++ b/examples/foundry.toml @@ -0,0 +1,19 @@ + +[profile.default] +src = "src" +out = "out" +libs = ["lib"] +fs_permissions = [{ access = "read", path = "out-optimized" }] +allow_paths = ["*", "/"] + +[fmt] +bracket_spacing = true +int_types = "long" +line_length = 100 +multiline_func_header = "all" +number_underscore = "thousands" +quote_style = "double" +tab_width = 4 +wrap_comments = true + +# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options diff --git a/examples/package.json b/examples/package.json new file mode 100644 index 00000000..a2cfb2c9 --- /dev/null +++ b/examples/package.json @@ -0,0 +1,70 @@ +{ + "name": "@rhinestone/modulekit-examples", + "description": "ModuleKit Examples", + "license": "MIT", + "version": "0.1.0", + "author": { + "name": "zeroknots.eth", + "url": "https://rhinestone.wtf" + }, + "bugs": { + "url": "https://github.com/rhinestonewtf/modulekit/issues" + }, + "devDependencies": { + "@openzeppelin/contracts": "5.0.1", + "@rhinestone/modulekit": "workspace:*", + "@rhinestone/safe7579": "workspace:*", + "@rhinestone/sessionkeymanager": "workspace:*", + "@prb/math": "^4.0.2", + "erc4337-validation": "github:rhinestonewtf/erc4337-validation", + "@ERC4337/account-abstraction": "github:kopy-kat/account-abstraction#develop", + "@safe-global/safe-contracts": "^1.4.1", + "@ERC4337/account-abstraction-v0.6": "github:eth-infinitism/account-abstraction#v0.6.0", + "forge-std": "github:foundry-rs/forge-std", + "ds-test": "github:dapphub/ds-test", + "erc7579": "github:erc7579/erc7579-implementation", + "sentinellist": "github:zeroknots/sentinellist", + "solady": "github:vectorized/solady", + "solarray": "github:sablier-labs/solarray", + "solmate": "github:transmissions11/solmate", + "solhint": "^4.1.1", + "prettier": "^2.8.8" + }, + "files": [ + "artifacts", + "src", + "test/utils", + "CHANGELOG.md", + "LICENSE-GPL.md" + ], + "keywords": [ + "blockchain", + "ethereum", + "foundry", + "smart-contracts", + "solidity", + "web3" + ], + "publishConfig": { + "access": "public" + }, + "repository": "github.com/rhinestonewtf/modulekit", + "scripts": { + "fmt": "forge fmt", + "build": "forge build", + "build:optimized": "FOUNDRY_PROFILE=optimized forge build", + "build:smt": "FOUNDRY_PROFILE=smt forge build", + "clean": "rm -rf artifacts broadcast cache docs out out-optimized out-svg", + "gas:report": "forge test --gas-report --mp \"./test/integration/**/*.sol\" --nmt \"test(Fuzz)?_RevertWhen_\\w{1,}?\"", + "gas:snapshot": "forge snapshot --mp \"./test/integration/**/*.sol\" --nmt \"test(Fuzz)?_RevertWhen_\\w{1,}?\"", + "gas:snapshot:optimized": "pnpm run build:optimized && FOUNDRY_PROFILE=test-optimized forge snapshot --mp \"./test/integration/**/*.sol\" --nmt \"test(Fork)?(Fuzz)?_RevertWhen_\\w{1,}?\"", + "lint": "pnpm run lint:sol && bun run prettier:check", + "lint:sol": "forge fmt --check && pnpm solhint \"{script,src,test}/**/*.sol\"", + "prepack": "pnpm install", + "prettier:check": "prettier --check \"**/*.{json,md,svg,yml}\"", + "prettier:write": "prettier --write \"**/*.{json,md,svg,yml}\"", + "test": "forge test", + "test:lite": "FOUNDRY_PROFILE=lite forge test", + "test:optimized": "pnpm run build:optimized && FOUNDRY_PROFILE=test-optimized forge test" + } +} diff --git a/examples/remappings.txt b/examples/remappings.txt new file mode 100644 index 00000000..d9eda49b --- /dev/null +++ b/examples/remappings.txt @@ -0,0 +1,15 @@ +ds-test/=node_modules/ds-test/src/ +forge-std/=node_modules/forge-std/src/ +account-abstraction/=node_modules/@ERC4337/account-abstraction/contracts/ +account-abstraction-v0.6/=node_modules/@ERC4337/account-abstraction-v0.6/contracts/ +@openzeppelin/=node_modules/@openzeppelin/ +erc7579/=node_modules/erc7579/src/ +sentinellist/=node_modules/sentinellist/src/ +solmate/=node_modules/solmate/src/ +solady/=node_modules/solady/ +solarray/=node_modules/solarray/src/ +@rhinestone/=node_modules/@rhinestone/ +@safe-global/=node_modules/@safe-global/ +erc4337-validation/=node_modules/erc4337-validation/src/ +@ERC4337/=node_modules/@ERC4337/ +@prb/math/=node_modules/@prb/math/ diff --git a/examples/src/AutoSavings/AutoSavings.sol b/examples/src/AutoSavings/AutoSavings.sol new file mode 100644 index 00000000..9969b744 --- /dev/null +++ b/examples/src/AutoSavings/AutoSavings.sol @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import { ERC20Integration, ERC4626Integration } from "@rhinestone/modulekit/src/Integrations.sol"; +import { IERC20 } from "forge-std/interfaces/IERC20.sol"; +import { IERC4626 } from "forge-std/interfaces/IERC4626.sol"; +import { UniswapV3Integration } from "@rhinestone/modulekit/src/Integrations.sol"; +import { Execution } from "@rhinestone/modulekit/src/Accounts.sol"; +import { ERC7579ExecutorBase, SessionKeyBase } from "@rhinestone/modulekit/src/Modules.sol"; + +contract AutoSavingToVault is ERC7579ExecutorBase, SessionKeyBase { + struct Params { + address token; + uint256 amountReceived; + } + + struct ScopedAccess { + address sessionKeySigner; + address onlyToken; + uint256 maxAmount; + } + + struct Config { + uint16 percentage; // percentage to be saved to the vault + address vault; + uint128 sqrtPriceLimitX96; + } + + using ERC4626Integration for *; + + mapping(address account => mapping(address token => Config)) internal _config; + + function getConfig(address account, address token) public view returns (Config memory) { + return _config[account][token]; + } + + function setConfig(address token, Config memory config) public { + // TODO check for min / max sqrtPriceLimitX96 + _config[msg.sender][token] = config; + } + + function onInstall(bytes calldata data) external override { + if (data.length == 0) return; + (address[] memory tokens, Config[] memory log) = abi.decode(data, (address[], Config[])); + + for (uint256 i; i < tokens.length; i++) { + _config[msg.sender][tokens[i]] = log[i]; + } + } + + function onUninstall(bytes calldata data) external override { } + + function calcDepositAmount( + uint256 amountReceived, + uint256 percentage + ) + public + pure + returns (uint256) + { + return amountReceived * percentage / 100; + } + + function autoSave(Params calldata params) external { + // get vault that was configured for this token + Config memory conf = _config[msg.sender][params.token]; + IERC4626 vault = IERC4626(conf.vault); + + // calc amount that is subject to be saved + uint256 amountIn = calcDepositAmount(params.amountReceived, conf.percentage); + IERC20 tokenToSave; + + // if underlying asset is not the same as the token, add a swap + address underlying = vault.asset(); + if (params.token != underlying) { + Execution[] memory swap = UniswapV3Integration.approveAndSwap({ + smartAccount: msg.sender, + tokenIn: IERC20(params.token), + tokenOut: IERC20(underlying), + amountIn: amountIn, + sqrtPriceLimitX96: conf.sqrtPriceLimitX96 + }); + + // execute swap on account + bytes[] memory results = _execute(swap); + // get return data of swap, and set it as amountIn. + // this will be the actual amount that is subject to be saved + amountIn = abi.decode(results[1], (uint256)); + // change tokenToSave to underlying + tokenToSave = IERC20(underlying); + } else { + tokenToSave = IERC20(params.token); + } // set tokenToSave to params.token since no swap was needed + + // approve and deposit to vault + Execution[] memory approveAndDeposit = new Execution[](2); + approveAndDeposit[0] = ERC20Integration.approve(tokenToSave, address(vault), amountIn); + approveAndDeposit[1] = ERC4626Integration.deposit(vault, amountIn, msg.sender); + + // execute deposit to vault on account + _execute(approveAndDeposit); + } + + function validateSessionParams( + address destinationContract, + uint256 callValue, + bytes calldata callData, + bytes calldata _sessionKeyData, + bytes calldata /*_callSpecificData*/ + ) + public + virtual + override + onlyFunctionSig(this.autoSave.selector, bytes4(callData[:4])) + onlyZeroValue(callValue) + onlyThis(destinationContract) + returns (address) + { + ScopedAccess memory access = abi.decode(_sessionKeyData, (ScopedAccess)); + Params memory params = abi.decode(callData[4:], (Params)); + + if (params.token != access.onlyToken) { + revert InvalidRecipient(); + } + + if (params.amountReceived > access.maxAmount) { + revert InvalidRecipient(); + } + + return access.sessionKeySigner; + } + + function isModuleType(uint256 typeID) external pure override returns (bool) { + return typeID == TYPE_EXECUTOR; + } + + function isInitialized(address smartAccount) external view returns (bool) { } + + function name() external pure virtual returns (string memory) { + return "AutoSaving"; + } + + function version() external pure virtual returns (string memory) { + return "0.0.1"; + } +} diff --git a/examples/src/AutoSend/AutoSend.sol b/examples/src/AutoSend/AutoSend.sol new file mode 100644 index 00000000..a517bd4f --- /dev/null +++ b/examples/src/AutoSend/AutoSend.sol @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import { IERC20 } from "forge-std/interfaces/IERC20.sol"; +import { IERC7579Account } from "@rhinestone/modulekit/src/Accounts.sol"; +import { ERC7579ExecutorBase, SessionKeyBase } from "@rhinestone/modulekit/src/Modules.sol"; +import { ModeLib } from "erc7579/lib/ModeLib.sol"; +import { ExecutionLib } from "erc7579/lib/ExecutionLib.sol"; + +contract AutoSendSessionKey is ERC7579ExecutorBase, SessionKeyBase { + struct ExecutorAccess { + address sessionKeySigner; + address token; + address receiver; + } + + struct SpentLog { + uint128 spent; + uint128 maxAmount; + } + + struct Params { + address token; + address receiver; + uint128 amount; + } + + mapping(address account => mapping(address token => SpentLog)) internal _log; + + function encode(ExecutorAccess memory transaction) public pure returns (bytes memory) { + return abi.encode(transaction); + } + + function getSpentLog(address account, address token) public view returns (SpentLog memory) { + return _log[account][token]; + } + + function autoSend(Params calldata params) external { + IERC7579Account smartAccount = IERC7579Account(msg.sender); + + SpentLog storage log = _log[msg.sender][params.token]; + + uint128 newSpent = log.spent + params.amount; + if (newSpent > log.maxAmount) { + revert InvalidAmount(); + } + log.spent = newSpent; + + smartAccount.executeFromExecutor( + ModeLib.encodeSimpleSingle(), + ExecutionLib.encodeSingle( + params.token, 0, abi.encodeCall(IERC20.transfer, (params.receiver, params.amount)) + ) + ); + } + + function validateSessionParams( + address destinationContract, + uint256 callValue, + bytes calldata callData, + bytes calldata _sessionKeyData, + bytes calldata /*_callSpecificData*/ + ) + public + virtual + override + returns (address) + { + ExecutorAccess memory access = abi.decode(_sessionKeyData, (ExecutorAccess)); + + bytes4 targetSelector = bytes4(callData[:4]); + Params memory params = abi.decode(callData[4:], (Params)); + if (targetSelector != this.autoSend.selector) { + revert InvalidMethod(targetSelector); + } + + if (params.receiver != access.receiver) { + revert InvalidRecipient(); + } + + if (destinationContract != address(this)) { + revert InvalidTarget(); + } + + if (params.token != access.token) { + revert InvalidTarget(); + } + + if (callValue != 0) { + revert InvalidValue(); + } + + return access.sessionKeySigner; + } + + function onInstall(bytes calldata data) external override { + (address[] memory tokens, SpentLog[] memory log) = abi.decode(data, (address[], SpentLog[])); + + for (uint256 i; i < tokens.length; i++) { + _log[msg.sender][tokens[i]] = log[i]; + } + } + + function onUninstall(bytes calldata data) external override { } + + function isModuleType(uint256 typeID) external pure override returns (bool) { + return typeID == TYPE_EXECUTOR; + } + + function isInitialized(address smartAccount) external view returns (bool) { } + + function name() external pure virtual returns (string memory) { + return "AutoSend"; + } + + function version() external pure virtual returns (string memory) { + return "0.0.1"; + } +} diff --git a/examples/src/ColdStorage/ColdStorageExecutor.sol b/examples/src/ColdStorage/ColdStorageExecutor.sol new file mode 100644 index 00000000..5b8b1cf4 --- /dev/null +++ b/examples/src/ColdStorage/ColdStorageExecutor.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import { IERC7579Account } from "@rhinestone/modulekit/src/Accounts.sol"; +import { ERC7579ExecutorBase } from "@rhinestone/modulekit/src/Modules.sol"; +import { ModeLib } from "erc7579/lib/ModeLib.sol"; +import { ExecutionLib } from "erc7579/lib/ExecutionLib.sol"; + +contract ColdStorageExecutor is ERC7579ExecutorBase { + error UnauthorizedAccess(); + + mapping(address subAccount => address owner) private _subAccountOwner; + + function executeOnSubAccount(address subAccount, bytes calldata callData) external payable { + if (msg.sender != _subAccountOwner[subAccount]) { + revert UnauthorizedAccess(); + } + + IERC7579Account(subAccount).executeFromExecutor(ModeLib.encodeSimpleSingle(), callData); + } + + function onInstall(bytes calldata data) external override { + address owner = address(bytes20(data[0:20])); + _subAccountOwner[msg.sender] = owner; + } + + function onUninstall(bytes calldata) external override { + delete _subAccountOwner[msg.sender]; + } + + function isModuleType(uint256 typeID) external pure override returns (bool) { + return typeID == TYPE_EXECUTOR; + } + + function isInitialized(address smartAccount) external view returns (bool) { + return _subAccountOwner[smartAccount] != address(0); + } +} diff --git a/examples/src/ColdStorage/ColdStorageHook.sol b/examples/src/ColdStorage/ColdStorageHook.sol new file mode 100644 index 00000000..9978f357 --- /dev/null +++ b/examples/src/ColdStorage/ColdStorageHook.sol @@ -0,0 +1,283 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.19; + +import { IERC721 } from "forge-std/interfaces/IERC721.sol"; +import { IERC20 } from "forge-std/interfaces/IERC20.sol"; + +import { EnumerableMap } from "@openzeppelin/contracts/utils/structs/EnumerableMap.sol"; +import { ERC7579HookDestruct } from "@rhinestone/modulekit/src/modules/ERC7579HookDestruct.sol"; +import { Execution } from "@rhinestone/modulekit/src/Accounts.sol"; + +contract ColdStorageHook is ERC7579HookDestruct { + error UnsupportedExecution(); + error UnauthorizedAccess(); + error InvalidExecutionHash(bytes32 executionHash); + + using EnumerableMap for EnumerableMap.Bytes32ToBytes32Map; + + bytes32 internal constant PASS = keccak256("pass"); + + struct VaultConfig { + uint128 waitPeriod; + address owner; + } + + mapping(address subAccount => VaultConfig) internal vaultConfig; + mapping(address subAccount => EnumerableMap.Bytes32ToBytes32Map) internal executions; + + event ExecutionRequested( + address indexed subAccount, + address target, + uint256 value, + bytes callData, + uint256 executeAfter + ); + + event ExecutionExecuted( + address indexed subAccount, address target, uint256 value, bytes callData + ); + + function checkHash( + address account, + Execution calldata exec + ) + external + view + returns (bytes32 executionHash, bytes32 entry) + { + executionHash = _execDigestMemory(exec.target, exec.value, exec.callData); + bool success; + (success, entry) = executions[account].tryGet(executionHash); + } + + function _getTokenTxReceiver(bytes calldata callData) + internal + pure + returns (address receiver) + { + bytes4 functionSig = bytes4(callData[0:4]); + bytes calldata params = callData[4:]; + if (functionSig == IERC20.transfer.selector) { + (receiver,) = abi.decode(params, (address, uint256)); + } else if (functionSig == IERC20.transferFrom.selector) { + (, receiver,) = abi.decode(params, (address, address, uint256)); + } else if (functionSig == IERC721.transferFrom.selector) { + (, receiver,) = abi.decode(params, (address, address, uint256)); + } + } + + /** + * Function that must be triggered from subaccount. + * requests an execution to happen in the future + */ + function requestTimelockedExecution( + Execution calldata _exec, + uint256 additionalWait + ) + external + { + VaultConfig memory _config = vaultConfig[msg.sender]; + bytes32 executionHash = _execDigest(_exec.target, _exec.value, _exec.callData); + + if (_exec.callData.length != 0) { + // check that transaction is only a token transfer + address tokenReceiver = _getTokenTxReceiver(_exec.callData); + if (tokenReceiver != _config.owner) { + // Else check that transaction is to setWaitPeriod + if (bytes4(_exec.callData[0:4]) != this.setWaitPeriod.selector) { + revert("Invalid receiver transfer"); + } + } + } else { + if (_exec.target != _config.owner) { + revert("Invalid receiver transfer"); + } + } + + uint256 executeAfter = uint256(block.timestamp + _config.waitPeriod + additionalWait); + bytes32 entry = bytes32(executeAfter); + + // write executionHash to storage + executions[msg.sender].set(executionHash, entry); + + emit ExecutionRequested(msg.sender, _exec.target, _exec.value, _exec.callData, executeAfter); + } + + function setWaitPeriod(uint256 waitPeriod) external { + if (waitPeriod == 0) { + revert("Wait period cannot be 0"); + } + vaultConfig[msg.sender].waitPeriod = uint128(waitPeriod); + } + + function _execDigest( + address to, + uint256 value, + bytes calldata callData + ) + internal + pure + returns (bytes32) + { + bytes memory _callData = callData; + return _execDigestMemory(to, value, _callData); + } + + function _execDigestMemory( + address to, + uint256 value, + bytes memory callData + ) + internal + pure + returns (bytes32 digest) + { + digest = keccak256(abi.encodePacked(to, value, callData)); + } + + function onInstall(bytes calldata data) external override { + VaultConfig storage _config = vaultConfig[msg.sender]; + (_config.waitPeriod, _config.owner) = abi.decode(data, (uint128, address)); + } + + function onUninstall(bytes calldata data) external override { + delete vaultConfig[msg.sender].waitPeriod; + delete vaultConfig[msg.sender].owner; + } + + function onPostCheck(bytes calldata hookData) + internal + virtual + override + returns (bool success) + { + if ( + keccak256(hookData) == keccak256(abi.encode(this.requestTimelockedExecution.selector)) + || keccak256(hookData) == keccak256(abi.encode(PASS)) + ) { + return true; + } + + return false; + } + + function onExecute( + address msgSender, + address target, + uint256 value, + bytes calldata callData + ) + internal + virtual + override + returns (bytes memory hookData) + { + revert UnsupportedExecution(); + } + + function onExecuteBatch( + address msgSender, + Execution[] calldata + ) + internal + virtual + override + returns (bytes memory hookData) + { + revert UnsupportedExecution(); + } + + function onExecuteFromExecutor( + address msgSender, + address target, + uint256 value, + bytes calldata callData + ) + internal + virtual + override + returns (bytes memory hookData) + { + bytes4 functionSig; + + if (callData.length >= 4) { + functionSig = bytes4(callData[0:4]); + } + + // check if call is a requestTimelockedExecution + if (target == address(this) && functionSig == this.requestTimelockedExecution.selector) { + return abi.encode(this.requestTimelockedExecution.selector); + } else { + bytes32 executionHash = _execDigestMemory(target, value, callData); + (bool success, bytes32 entry) = executions[msg.sender].tryGet(executionHash); + + if (!success) revert InvalidExecutionHash(executionHash); + + uint256 requestTimeStamp = uint256(entry); + if (requestTimeStamp > block.timestamp) revert UnauthorizedAccess(); + + emit ExecutionExecuted(msg.sender, target, value, callData); + + return abi.encode(PASS); + } + } + + function onExecuteBatchFromExecutor( + address msgSender, + Execution[] calldata + ) + internal + virtual + override + returns (bytes memory hookData) + { + revert UnsupportedExecution(); + } + + function onInstallModule( + address msgSender, + uint256 moduleType, + address module, + bytes calldata initData + ) + internal + virtual + override + returns (bytes memory hookData) + { + revert UnsupportedExecution(); + } + + function onUninstallModule( + address msgSender, + uint256 moduleType, + address module, + bytes calldata deInitData + ) + internal + virtual + override + returns (bytes memory hookData) + { + revert UnsupportedExecution(); + } + + function getLockTime(address subAccount) public view returns (uint256) { + return vaultConfig[subAccount].waitPeriod; + } + + function version() external pure virtual returns (string memory) { + return "1.0.0"; + } + + function name() external pure virtual returns (string memory) { + return "ColdStorageHook"; + } + + function isModuleType(uint256 isType) external pure virtual override returns (bool) { + return isType == TYPE_HOOK; + } + + function isInitialized(address smartAccount) external view returns (bool) { } +} diff --git a/examples/src/ColdStorage/FlashloanCallback.sol b/examples/src/ColdStorage/FlashloanCallback.sol new file mode 100644 index 00000000..d5d79382 --- /dev/null +++ b/examples/src/ColdStorage/FlashloanCallback.sol @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import { IFallbackMethod } from "@rhinestone/modulekit/src/core/ExtensibleFallbackHandler.sol"; + +import { ERC7579ExecutorBase } from "@rhinestone/modulekit/src/Modules.sol"; +import "./interfaces/Flashloan.sol"; + +contract FlashloanCallback is IFallbackMethod, ERC7579ExecutorBase { + address immutable FALLBACK_HANDLER; + + mapping(address account => uint256) public nonce; + + constructor(address fallbackHandler) { + FALLBACK_HANDLER = fallbackHandler; + } + + function handle( + address borrower, + address sender, + uint256 value, + bytes calldata data + ) + external + override + returns (bytes memory result) + { + if (data.length < 4) revert(); + if (msg.sender != FALLBACK_HANDLER) revert(); + + bytes4 selector = bytes4(data[0:4]); + + if (selector == IERC3156FlashBorrower.onFlashLoan.selector) { + ( + address lender, + address token, + uint256 value, + uint256 fee, + bytes memory tokenGatedAction + ) = abi.decode(data[4:], (address, address, uint256, uint256, bytes)); + _onFlashloan(borrower, lender, token, value, fee, tokenGatedAction); + return abi.encode(keccak256("ERC3156FlashBorrower.onFlashLoan")); + } + } + + function _onFlashloan( + address borrower, + address lender, + address token, + uint256 value, + uint256 fee, + bytes memory tokenGatedAction + ) + internal + { + (FlashLoanType flashLoanType, bytes memory signature, bytes memory callData) = + abi.decode(tokenGatedAction, (FlashLoanType, bytes, bytes)); + bytes32 hash = getTokengatedTxHash(callData, nonce[borrower]); + // TODO signature + (bool success,) = borrower.call(callData); + if (!success) revert(); + nonce[borrower]++; + } + + function getTokengatedTxHash( + bytes memory transaction, + uint256 _nonce + ) + public + view + returns (bytes32) + { + return keccak256(abi.encodePacked(transaction, _nonce)); + } + + function onInstall(bytes calldata data) external override { } + + function onUninstall(bytes calldata data) external override { } + + function version() external pure virtual returns (string memory) { + return "1.0.0"; + } + + function name() external pure virtual returns (string memory) { + return "FlashloanCallback"; + } + + function isModuleType(uint256 isType) external pure virtual override returns (bool) { + return isType == TYPE_EXECUTOR; + } + + function isInitialized(address smartAccount) external view returns (bool) { } +} diff --git a/examples/src/ColdStorage/FlashloanLender.sol b/examples/src/ColdStorage/FlashloanLender.sol new file mode 100644 index 00000000..a7da4aab --- /dev/null +++ b/examples/src/ColdStorage/FlashloanLender.sol @@ -0,0 +1,186 @@ +import "forge-std/interfaces/IERC20.sol"; +import "forge-std/interfaces/IERC721.sol"; + +import { IFallbackMethod } from "@rhinestone/modulekit/src/core/ExtensibleFallbackHandler.sol"; +import { ERC7579ExecutorBase } from "@rhinestone/modulekit/src/Modules.sol"; +import "./interfaces/Flashloan.sol"; + +pragma solidity ^0.8.20; + +contract FlashloanLender is IFallbackMethod, ERC7579ExecutorBase { + // using ERC7579ExecutorLib for address; + + address immutable FALLBACK_HANDLER; + + mapping(address account => uint256) public nonce; + + constructor(address fallbackHandler) { + FALLBACK_HANDLER = fallbackHandler; + } + + function handle( + address account, + address sender, + uint256 value, + bytes calldata data + ) + external + override + returns (bytes memory result) + { + if (data.length < 4) revert(); + + if (msg.sender != FALLBACK_HANDLER) revert(); + bytes4 functionSig = bytes4(data[0:4]); + if (functionSig == IERC6682.availableForFlashLoan.selector) { + (address token, uint256 tokenId) = abi.decode(data[4:], (address, uint256)); + result = abi.encode(_availableForFlashLoanERC721(account, token, tokenId)); + } else if (functionSig == IERC6682.flashFee.selector) { + (address token, uint256 tokenId) = abi.decode(data[4:], (address, uint256)); + result = abi.encode(_flashFee(account, token, tokenId)); + } else if (functionSig == IERC6682.flashFeeToken.selector) { + result = abi.encode(_flashFeeToken(account)); + } else if (functionSig == IERC3156FlashLender.flashLoan.selector) { + ( + IERC3156FlashBorrower borrower, + address token, + uint256 tokenId, + bytes memory flashloanData + ) = abi.decode(data[4:], (IERC3156FlashBorrower, address, uint256, bytes)); + return abi.encode(_flashLoan(account, borrower, token, tokenId, flashloanData)); + } + } + + /** + * @notice Executes a flash loan by lending an NFT and collecting a fee. + * + * @param account Address of the lender. + * @param borrower Address of the borrower implementing IERC3156FlashBorrower. + * @param token Address of the ERC721 token contract. + * @param value ID of the NFT. + * @param data Arbitrary data provided by the borrower. + * @return True if the flash loan was successful, false otherwise. + * + * @dev this is using ERC6682 and modulekit executorManger to lend the token out + */ + function _flashLoan( + address account, + IERC3156FlashBorrower borrower, + address token, + uint256 value, + bytes memory data + ) + internal + returns (bool) + { + (FlashLoanType flashLoanType,,) = abi.decode(data, (FlashLoanType, bytes, bytes)); + + if (flashLoanType == FlashLoanType.ERC721) { + _execute( + msg.sender, + address(token), + 0, + abi.encodeCall(IERC721.transferFrom, (address(account), address(borrower), value)) + ); + } + // TODO impl ERC20 + + // trigger callback on borrrower + bool success = borrower.onFlashLoan(account, token, value, 0, data) + == keccak256("ERC3156FlashBorrower.onFlashLoan"); + if (!success) revert(); + + // check that token was sent back + if (!_availableForFlashLoanERC721({ account: account, token: token, tokenId: value })) { + revert(); + } + return true; + } + + /** + * @notice Retrieves the borrower fee for a specific NFT. + * @param account The address of the lender. + * @param token Address of the ERC721 token contract. + * @param tokenId ID of the NFT. + * @return total Fee amount for the specified NFT. + */ + function _flashFee( + address account, + address token, + uint256 tokenId + ) + internal + view + returns (uint256 total) + { + // uint256 tokenOwnerFee = _tokenOwnerFee(account, token, tokenId); + // total = tokenOwnerFee + calcDevFee(tokenOwnerFee, FEE_PERCENTAGE); + } + + /** + * @notice Retrieves the token used for collecting flash loan fees for a specific account. + * @param account The address of the lender. + * @return Address of the ERC20 token used for fees. + */ + function _flashFeeToken(address account) internal view returns (address) { } + + /** + * @notice Retrieves the borrower fee for a specific NFT. + * @param account The address of the lender. + * @param token Address of the ERC721 token contract. + * @param tokenId ID of the NFT. + * @return fee amount for the specified NFT. + */ + function _tokenOwnerFee( + address account, + address token, + uint256 tokenId + ) + internal + view + returns (uint256 fee) + { + // fee = _feePerToken[account][token][tokenId]; + } + + /** + * @notice Checks if a specific NFT is available for flash loan. + * @param account The address of the potential lender. + * @param token Address of the ERC721 token contract. + * @param tokenId ID of the NFT. + * @return hasToken if the NFT is available for flash loan, false otherwise. + */ + function _availableForFlashLoanERC721( + address account, + address token, + uint256 tokenId + ) + internal + view + returns (bool hasToken) + { + try IERC721(token).ownerOf(tokenId) returns (address holder) { + hasToken = holder == address(account); + } catch { + hasToken = false; + } + } + + function onInstall(bytes calldata data) external override { } + + function onUninstall(bytes calldata data) external override { } + + function version() external pure virtual returns (string memory) { + return "1.0.0"; + } + + function name() external pure virtual returns (string memory) { + return "FlashloanLender"; + } + + function isModuleType(uint256 isType) external pure virtual override returns (bool) { + return isType == TYPE_EXECUTOR; + } + + function isInitialized(address smartAccount) external view returns (bool) { } +} diff --git a/examples/src/ColdStorage/interfaces/Flashloan.sol b/examples/src/ColdStorage/interfaces/Flashloan.sol new file mode 100644 index 00000000..b0b18da0 --- /dev/null +++ b/examples/src/ColdStorage/interfaces/Flashloan.sol @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.21; + +import { IERC20 } from "forge-std/interfaces/IERC20.sol"; +import { IERC721 } from "forge-std/interfaces/IERC721.sol"; + +enum FlashLoanType { + ERC20, + ERC721 +} + +interface IERC6682 { + function flashFeeToken() external view returns (address); + function flashFee(address token, uint256 tokenId) external view returns (uint256); + function availableForFlashLoan(address token, uint256 tokenId) external view returns (bool); +} + +/** + * @dev Interface of the ERC3156 FlashLender, as defined in + * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156]. + */ +interface IERC3156FlashLender { + /** + * @dev The amount of currency available to be lended. + * @param token The loan currency. + * @return The amount of `token` that can be borrowed. + */ + function maxFlashLoan(address token) external view returns (uint256); + + /** + * @dev The fee to be charged for a given loan. + * @param token The loan currency. + * @param amount The amount of tokens lent. + * @return The amount of `token` to be charged for the loan, on top of the returned principal. + */ + function flashFee(address token, uint256 amount) external view returns (uint256); + + /** + * @dev Initiate a flash loan. + * @param receiver The receiver of the tokens in the loan, and the receiver of the callback. + * @param token The loan currency. + * @param amount The amount of tokens lent. + * @param data Arbitrary data structure, intended to contain user-defined parameters. + */ + function flashLoan( + IERC3156FlashBorrower receiver, + address token, + uint256 amount, + bytes calldata data + ) + external + returns (bool); +} + +/** + * @dev Interface of the ERC3156 FlashBorrower, as defined in + * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156]. + */ +interface IERC3156FlashBorrower { + /** + * @dev Receive a flash loan. + * @param initiator The initiator of the loan. + * @param token The loan currency. + * @param amount The amount of tokens lent. + * @param fee The additional amount of tokens to repay. + * @param data Arbitrary data structure, intended to contain user-defined parameters. + * @return The keccak256 hash of "ERC3156FlashBorrower.onFlashLoan" + */ + function onFlashLoan( + address initiator, + address token, + uint256 amount, + uint256 fee, + bytes calldata data + ) + external + returns (bytes32); +} diff --git a/examples/src/DeadmanSwitch/DeadmanSwitch.sol b/examples/src/DeadmanSwitch/DeadmanSwitch.sol new file mode 100644 index 00000000..0eeee9b2 --- /dev/null +++ b/examples/src/DeadmanSwitch/DeadmanSwitch.sol @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.21; + +import { ERC7579ValidatorBase, ERC7579HookBase } from "@rhinestone/modulekit/src/Modules.sol"; +import { PackedUserOperation } from "@rhinestone/modulekit/src/ModuleKit.sol"; +import { SignatureCheckerLib } from "solady/src/utils/SignatureCheckerLib.sol"; +import { ECDSA } from "solady/src/utils/ECDSA.sol"; + +contract DeadmanSwitch is ERC7579HookBase, ERC7579ValidatorBase { + using SignatureCheckerLib for address; + + struct DeadmanSwitchStorage { + uint48 lastAccess; + uint48 timeout; + address nominee; + } + + mapping(address account => DeadmanSwitchStorage config) private _lastAccess; + + event Recovery(address account, address nominee); + + error MissingCondition(); + + function onInstall(bytes calldata data) external { + if (data.length == 0) return; + (address nominee, uint48 timeout) = abi.decode(data, (address, uint48)); + DeadmanSwitchStorage storage config = _lastAccess[msg.sender]; + + config.lastAccess = uint48(block.timestamp); + config.timeout = timeout; + config.nominee = nominee; + } + + function lastAccess(address account) external view returns (uint48) { + return _lastAccess[account].lastAccess; + } + + function onUninstall(bytes calldata) external override { + delete _lastAccess[msg.sender]; + } + + function name() external pure returns (string memory) { + return "DeadmanSwitch"; + } + + function version() external pure returns (string memory) { + return "0.0.1"; + } + + function isModuleType(uint256 typeID) external pure override returns (bool) { + return typeID == TYPE_HOOK; + } + + function isInitialized(address smartAccount) external view returns (bool) { } + + function preCheck(address, bytes calldata) external returns (bytes memory) { + DeadmanSwitchStorage storage config = _lastAccess[msg.sender]; + config.lastAccess = uint48(block.timestamp); + } + + function postCheck(bytes calldata) external pure returns (bool success) { + success = true; + } + + function validateUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash + ) + external + view + override + returns (ValidationData) + { + DeadmanSwitchStorage memory config = _lastAccess[userOp.sender]; + if (config.nominee == address(0)) return VALIDATION_FAILED; + bool sigValid = config.nominee.isValidSignatureNow({ + hash: ECDSA.toEthSignedMessageHash(userOpHash), + signature: userOp.signature + }); + + return _packValidationData({ + sigFailed: !sigValid, + validAfter: config.lastAccess + config.timeout, + validUntil: type(uint48).max + }); + } + + function isValidSignatureWithSender( + address, + bytes32, + bytes calldata + ) + external + pure + override + returns (bytes4) + { + return EIP1271_FAILED; + } +} diff --git a/examples/src/DollarCostAverage/DollarCostAverage.sol b/examples/src/DollarCostAverage/DollarCostAverage.sol new file mode 100644 index 00000000..a5fc7888 --- /dev/null +++ b/examples/src/DollarCostAverage/DollarCostAverage.sol @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import { IERC20 } from "forge-std/interfaces/IERC20.sol"; +import { UniswapV3Integration } from "@rhinestone/modulekit/src/integrations/uniswap/v3/Uniswap.sol"; +import { Execution, IERC7579Account } from "@rhinestone/modulekit/src/Accounts.sol"; +import { ERC7579ExecutorBase, SessionKeyBase } from "@rhinestone/modulekit/src/Modules.sol"; +import { ModeLib } from "erc7579/lib/ModeLib.sol"; +import { ExecutionLib } from "erc7579/lib/ExecutionLib.sol"; + +contract DollarCostAverage is ERC7579ExecutorBase, SessionKeyBase { + struct ScopedAccess { + address sessionKeySigner; + address onlyTokenIn; + address onlyTokenOut; + uint256 maxAmount; + } + + struct SpentLog { + uint128 spent; + uint128 maxAmount; + } + + struct Params { + address tokenIn; + address tokenOut; + uint128 amount; + } + + error InvalidParams(); + + mapping(address account => mapping(address token => SpentLog)) internal _log; + + function dca(Params calldata params) external { + IERC7579Account smartAccount = IERC7579Account(msg.sender); + + Execution[] memory executions = UniswapV3Integration.approveAndSwap({ + smartAccount: msg.sender, + tokenIn: IERC20(params.tokenIn), + tokenOut: IERC20(params.tokenOut), + amountIn: params.amount, + sqrtPriceLimitX96: 0 // TODO fix this + }); + + _log[msg.sender][params.tokenIn].spent += params.amount; + + smartAccount.executeFromExecutor( + ModeLib.encodeSimpleBatch(), ExecutionLib.encodeBatch(executions) + ); + } + + function validateSessionParams( + address destinationContract, + uint256 callValue, + bytes calldata callData, + bytes calldata _sessionKeyData, + bytes calldata /*_callSpecificData*/ + ) + public + virtual + override + onlyFunctionSig(this.dca.selector, bytes4(callData[:4])) + onlyZeroValue(callValue) + onlyThis(destinationContract) + returns (address) + { + ScopedAccess memory access = abi.decode(_sessionKeyData, (ScopedAccess)); + Params memory params = abi.decode(callData[4:], (Params)); + + if (params.tokenIn != access.onlyTokenIn) revert InvalidParams(); + if (params.tokenOut != access.onlyTokenOut) revert InvalidParams(); + if (params.amount > access.maxAmount) revert InvalidParams(); + + return access.sessionKeySigner; + } + + function onInstall(bytes calldata data) external override { + (address[] memory tokens, SpentLog[] memory log) = abi.decode(data, (address[], SpentLog[])); + + for (uint256 i; i < tokens.length; i++) { + _log[msg.sender][tokens[i]] = log[i]; + } + } + + function onUninstall(bytes calldata data) external override { } + + function encode(ScopedAccess memory transaction) public pure returns (bytes memory) { + return abi.encode(transaction); + } + + function getSpentLog(address account, address token) public view returns (SpentLog memory) { + return _log[account][token]; + } + + function isModuleType(uint256 typeID) external pure override returns (bool) { + return typeID == TYPE_EXECUTOR; + } + + function isInitialized(address smartAccount) external view returns (bool) { } + + function name() external pure virtual returns (string memory) { + return "DollarCostAverage"; + } + + function version() external pure virtual returns (string memory) { + return "0.0.1"; + } +} diff --git a/examples/src/ERC1271PreHash/ERC1271PrehashValidator.sol b/examples/src/ERC1271PreHash/ERC1271PrehashValidator.sol new file mode 100644 index 00000000..6f505ce9 --- /dev/null +++ b/examples/src/ERC1271PreHash/ERC1271PrehashValidator.sol @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.19; + +import { ERC7579ValidatorBase } from "@rhinestone/modulekit/src/modules/ERC7579ValidatorBase.sol"; +import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; +import { PackedUserOperation } from "@rhinestone/modulekit/src/external/ERC4337.sol"; + +contract ERC1271PrehashValidator is ERC7579ValidatorBase { + using EnumerableSet for EnumerableSet.Bytes32Set; + + mapping(address account => EnumerableSet.Bytes32Set) internal _validHashes; + + function addHash(bytes32 _hash) external { + _validHashes[msg.sender].add(_hash); + } + + function removeHash(bytes32 _hash) external { + _validHashes[msg.sender].remove(_hash); + } + + function isHash(address account, bytes32 _hash) public view returns (bool) { + return _validHashes[account].contains(_hash); + } + + function validateUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash + ) + external + virtual + override + returns (ValidationData) + { + return VALIDATION_FAILED; + } + + function isValidSignatureWithSender( + address sender, + bytes32 hash, + bytes calldata data + ) + external + view + virtual + override + returns (bytes4) + { + if (keccak256(data) != hash) return EIP1271_FAILED; + if (isHash(sender, hash)) { + return EIP1271_SUCCESS; + } else { + return EIP1271_FAILED; + } + } + + function version() external pure virtual returns (string memory) { + return "1.0.0"; + } + + function name() external pure virtual returns (string memory) { + return "ERC1271PrehashValidator"; + } + + function isModuleType(uint256 isType) external pure virtual override returns (bool) { + return isType == TYPE_VALIDATOR; + } + + function isInitialized(address smartAccount) external view returns (bool) { } + + function onInstall(bytes calldata data) external override { + if (data.length == 0) return; + + bytes32[] memory hashes = abi.decode(data, (bytes32[])); + for (uint256 i; i < hashes.length; i++) { + _validHashes[msg.sender].add(hashes[i]); + } + } + + function onUninstall(bytes calldata data) external override { } +} diff --git a/examples/src/MultiFactor/ECDSAFactor.sol b/examples/src/MultiFactor/ECDSAFactor.sol new file mode 100644 index 00000000..22078c77 --- /dev/null +++ b/examples/src/MultiFactor/ECDSAFactor.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import { ECDSA } from "solady/src/utils/ECDSA.sol"; +import { ERC7579ValidatorBase } from "@rhinestone/modulekit/src/Modules.sol"; + +abstract contract ECDSAFactor is ERC7579ValidatorBase { + struct FactorConfig { + address signer; + uint48 validAfter; + uint48 validBefore; + } + + mapping(address smartAccount => FactorConfig ecdsaConfig) public ecdsaFactorConfig; + + function setECDSAFactor(FactorConfig calldata config) external { + ecdsaFactorConfig[msg.sender] = config; + } + + function _ecdsaSet(address smartAccount) internal view returns (bool) { + return ecdsaFactorConfig[smartAccount].signer != address(0); + } + + function _isValidSignature( + bytes32 userOpHash, + bytes memory signature + ) + internal + view + returns (bool validSig) + { + FactorConfig memory config = ecdsaFactorConfig[msg.sender]; + validSig = + config.signer == ECDSA.recover(ECDSA.toEthSignedMessageHash(userOpHash), signature); + } + + function _checkSignature( + bytes32 userOpHash, + bytes memory signature + ) + internal + view + returns (ValidationData _packedData) + { + FactorConfig memory config = ecdsaFactorConfig[msg.sender]; + bool validSig = + config.signer == ECDSA.recover(ECDSA.toEthSignedMessageHash(userOpHash), signature); + return _packValidationData(!validSig, config.validBefore, config.validAfter); + } +} diff --git a/examples/src/MultiFactor/MultiFactor.sol b/examples/src/MultiFactor/MultiFactor.sol new file mode 100644 index 00000000..843f5b10 --- /dev/null +++ b/examples/src/MultiFactor/MultiFactor.sol @@ -0,0 +1,367 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import { ERC7579ValidatorBase } from "@rhinestone/modulekit/src/Modules.sol"; +import { IERC7579Module } from "@rhinestone/modulekit/src/external/ERC7579.sol"; +import { IERC7579Account, Execution } from "@rhinestone/modulekit/src/Accounts.sol"; +import { PackedUserOperation } from "@rhinestone/modulekit/src/external/ERC4337.sol"; +import { LibSort } from "solady/src/utils/LibSort.sol"; +import { ECDSAFactor } from "./ECDSAFactor.sol"; +import { ExecutionLib } from "erc7579/lib/ExecutionLib.sol"; +import { ModeLib } from "erc7579/lib/ModeLib.sol"; + +struct ConfigData { + address subValidator; + bytes initData; +} + +contract MultiFactor is ERC7579ValidatorBase, ECDSAFactor { + using LibSort for *; + + error InvalidThreshold(uint256 length, uint256 threshold); + error ValidatorIsAlreadyUsed(address smartaccount, address validator); + error InvalidParams(); + error InvalidParamsLength(); + + uint256 constant MIN_THRESHOLD = 2; + + struct MultiFactorConfig { + uint8 threshold; + address[] subValidators; + } + + mapping(address smartAccount => MultiFactorConfig configuration) internal multiFactorConfig; + + function validateUserOp( + PackedUserOperation memory userOp, + bytes32 userOpHash + ) + external + virtual + override + returns (ValidationData) + { + // todo: slice index into sigs to save calldata + // decode the selection data from userOp signature + (uint256[] memory validatorIndextoUse, bytes[] memory signatures) = + abi.decode(userOp.signature, (uint256[], bytes[])); + + MultiFactorConfig storage config = multiFactorConfig[userOp.sender]; + + // a uniquified list of validators must be created for this. so that the frontend / user can + // not select the same validator multiple times + // not that this assumes that the subvalidators in storage are unique + validatorIndextoUse.sort(); + validatorIndextoUse.uniquifySorted(); + // check that the number of signatures matches the number of validators + // check validatorIndextoUse length is higher or equal to threshold. + // should a smaller value be provided, the security assumption that a multifactor validator + // is void + uint256 validatorToUseCount = validatorIndextoUse.length; + if (validatorToUseCount < config.threshold || validatorToUseCount != signatures.length) { + return VALIDATION_FAILED; + } + + // initialize the min values + uint256 validUntil; + uint256 validAfter; + // Iterate over the selected validators and validate the userOp. + for (uint256 i; i < validatorToUseCount; i++) { + ERC7579ValidatorBase _validator = + ERC7579ValidatorBase(config.subValidators[validatorIndextoUse[i]]); + + // Since userOp.signature had the validatorIndexToUse encoded, we need to clean up the + // signature field, before passing it to the validator + ValidationData _validationData; + // if the validator is this contract, we can use the local ECDAFactor implementation + if (address(_validator) == address(this)) { + _validationData = _checkSignature(userOpHash, signatures[i]); + } else { + userOp.signature = signatures[i]; + _validationData = _validator.validateUserOp(userOp, userOpHash); + } + + // destructuring the individual return values from the subvalidator + // using uint256 to avoid padding gas + (bool sigFailed, uint256 _validUntil, uint256 _validAfter) = + _unpackValidationData(_validationData); + + // update the min values + if (_validUntil < validUntil) validUntil = _validUntil; + if (_validAfter > validAfter) validAfter = _validAfter; + + // if any of the validators failed, the Validation is INVALID. + // Terminate the entire validation process and return the result + // returning the max values here + if (sigFailed) { + return _packValidationData({ + sigFailed: true, + validUntil: uint48(validUntil), + validAfter: uint48(validAfter) + }); + } + } + + // if we reach this point, all validators have passed and we can return the validation data + return _packValidationData({ + sigFailed: false, + validUntil: uint48(validUntil), + validAfter: uint48(validAfter) + }); + } + + function isValidSignatureWithSender( + address sender, + bytes32 hash, + bytes calldata data + ) + external + view + virtual + override + returns (bytes4) + { + // destructure data into validatorIndexToUse and signature + // TODO: slice this with packed / calldata + (uint256[] memory validatorIndextoUse, bytes[] memory signatures) = + abi.decode(data, (uint256[], bytes[])); + MultiFactorConfig storage config = multiFactorConfig[msg.sender]; + + // a uniquified list of validators MUST be crated for this. so that the frontend / user can + // not select the same validator multiple times + validatorIndextoUse.sort(); + validatorIndextoUse.uniquifySorted(); + // check that the number of signatures matches the number of validators + // check validatorIndextoUse length is higher or equal to threshold. + // should a smaller value be provided, the security assumption that a multifactor validator + // is void + uint256 validatorToUseCount = validatorIndextoUse.length; + if (validatorToUseCount < config.threshold || validatorToUseCount != signatures.length) { + return EIP1271_FAILED; + } + + // iterate over subValidators[] + for (uint256 i; i < validatorToUseCount; i++) { + ERC7579ValidatorBase _validator = + ERC7579ValidatorBase(config.subValidators[validatorIndextoUse[i]]); + + // check if local ECSDSA should be used + if (useLocalECDSAFactor(address(_validator))) { + // return EIP1271_FAILED if the signature is invalid + if (!_isValidSignature(hash, signatures[i])) return EIP1271_FAILED; + } else { + // get ERC1271 return value from subvalidator + bytes4 subValidatorERC1271 = + _validator.isValidSignatureWithSender(sender, hash, signatures[i]); + // check if return value is ERC1271 magic value. if not, return fail + if (subValidatorERC1271 != EIP1271_SUCCESS) return EIP1271_FAILED; + } + } + + // if we got to this stage, all subvalidators were able to correctly validate their + // signatures + return EIP1271_SUCCESS; + } + + /** + * Helper function that will call `onInstall` on selected subvalidators + * @dev If a subvalidator is already used by the smart account, this function will revert, as + * configuring the validator in a new setting could brick the account + * @param _smartAccount smartaccount address for which the MFA is used + * @param subValidators list of subvalidators to be configured on the account + * @param datas init datas for the subvalidators + */ + function _initSubValidator( + address _smartAccount, + address[] memory subValidators, + bytes[] memory datas + ) + internal + { + IERC7579Account smartAccount = IERC7579Account(_smartAccount); + uint256 length = subValidators.length; + + bool noInitData = datas.length == 0; + if (length != datas.length && noInitData) revert InvalidParams(); + Execution[] memory subValidatorInits = new Execution[](length); + // iterate over subValidators[] + for (uint256 i; i < length; i++) { + address subValidator = subValidators[i]; + + // should the selected subvalidator be address(this), the user is intending to use the + // ECDSA recover feature + // available in ECDSAFactor. + if (subValidator == address(this)) { + subValidatorInits[i] = Execution({ + target: address(this), + value: 0, + callData: abi.encodeCall( + ECDSAFactor.setECDSAFactor, (abi.decode(datas[i], (FactorConfig))) + ) + }); + } + // only allow the installation of subvalidators, if the validator module is not + // already installed on the account + else if (!smartAccount.isModuleInstalled(TYPE_VALIDATOR, subValidator, "")) { + if (datas[i].length != 0) { + // this is NOT installing the module on the account, but rather initing it + subValidatorInits[i] = Execution({ + target: subValidator, + value: 0, + callData: abi.encodeCall(IERC7579Module.onInstall, (datas[i])) + }); + } + } + } + + // execute batched transaction that will initialize the subValidators + smartAccount.executeFromExecutor( + ModeLib.encodeSimpleBatch(), ExecutionLib.encodeBatch(subValidatorInits) + ); + } + + function _deinitSubValidator( + address _smartAccount, + address[] memory subValidators, + bytes[] memory deInitDatas + ) + internal + { + uint256 length = deInitDatas.length; + + // Ensure that the deinit data length matches with the number of currently configured + // subvalidators. + // Every subvalidator MUST be de-initialized to prevert weird states + Execution[] memory subValidatorInits = new Execution[](length); + + // Iterate over all currently configured subvalidators and prepare a batched exec to de-init + // them + for (uint256 i; i < length; i++) { + address subValidator = subValidators[i]; + // should the selected subvalidator be address(this), the user is intending to remove + // the ECDSA recover feature available in ECDSAFactor. + if (subValidator == address(this)) { + // null out all values + FactorConfig memory ecdsaConfig = + FactorConfig({ signer: address(0), validAfter: 0, validBefore: 0 }); + subValidatorInits[i] = Execution({ + target: address(this), + value: 0, + callData: abi.encodeCall(ECDSAFactor.setECDSAFactor, (ecdsaConfig)) + }); + } else { + if (deInitDatas[i].length != 0) { + // this is NOT uninstalling the module on the account, but rather + // de-initializeing + subValidatorInits[i] = Execution({ + target: subValidator, + value: 0, + callData: abi.encodeCall(IERC7579Module.onUninstall, (deInitDatas[i])) + }); + } + } + } + + // execute batched transaction that will de-initialize the subValidators + IERC7579Account(_smartAccount).executeFromExecutor( + ModeLib.encodeSimpleBatch(), ExecutionLib.encodeBatch(subValidatorInits) + ); + } + + // TODO: 1 add registry check for subValidators. + // This should also make sure that the subValidator is actually a validator + function _setConfig( + address[] memory subValidators, + bytes[] memory deInitDatas, + bytes[] memory initDatas, + uint8 threshold + ) + internal + { + // sort and uniquify the subValidators + // Should a user provide the same validators multiple times, the security assumption that a + // multifactor validator brings can be bypassed + subValidators.sort(); + subValidators.uniquifySorted(); + uint256 length = subValidators.length; + if (length < threshold && threshold >= MIN_THRESHOLD) { + revert InvalidThreshold(length, threshold); + } + if (length != initDatas.length) revert InvalidParamsLength(); + if (length != deInitDatas.length) revert InvalidParamsLength(); + _deinitSubValidator(msg.sender, subValidators, deInitDatas); + _initSubValidator(msg.sender, subValidators, initDatas); + + MultiFactorConfig storage config = multiFactorConfig[msg.sender]; + config.subValidators = subValidators; + config.threshold = threshold; + } + + function setConfig( + address[] memory subValidators, + bytes[] memory deInitDatas, + bytes[] memory initDatas, + uint8 threshold + ) + external + { + _setConfig(subValidators, deInitDatas, initDatas, threshold); + } + + function onInstall(bytes calldata data) external { + // check if module is already initialized + if (data.length == 0) return; + if (multiFactorConfig[msg.sender].threshold != 0) revert("Already Initialized"); + + // TODO: slice this with packed / calldata + ( + address[] memory subValidators, + bytes[] memory deInitDatas, + bytes[] memory initDatas, + uint8 threshold + ) = abi.decode(data, (address[], bytes[], bytes[], uint8)); + + _setConfig(subValidators, deInitDatas, initDatas, threshold); + } + + function onUninstall(bytes calldata deInit) external { + // TODO: slice this with packed / calldata + bytes[] memory deInitDatas; + if (deInit.length != 0) { + (deInitDatas) = abi.decode(deInit, (bytes[])); + } + MultiFactorConfig storage config = multiFactorConfig[msg.sender]; + _deinitSubValidator(msg.sender, config.subValidators, deInitDatas); + config.subValidators = new address[](0); + config.threshold = 0; + } + + function getMultiFactorConfig(address smartAccount) + external + view + returns (MultiFactorConfig memory) + { + return multiFactorConfig[smartAccount]; + } + + function isModuleType(uint256 typeID) external pure returns (bool) { + if (typeID == TYPE_VALIDATOR) return true; + if (typeID == TYPE_EXECUTOR) return true; + } + + function useLocalECDSAFactor(address validator) internal view returns (bool) { + return validator == address(this); + } + + function name() external pure returns (string memory) { + return "MultiFactor"; + } + + function version() external pure returns (string memory) { + return "0.0.1"; + } + + function isInitialized(address smartAccount) external view returns (bool) { + return multiFactorConfig[msg.sender].threshold != 0; + } +} diff --git a/examples/src/OwnableValidator/OwnableValidator.sol b/examples/src/OwnableValidator/OwnableValidator.sol new file mode 100644 index 00000000..3e3086ff --- /dev/null +++ b/examples/src/OwnableValidator/OwnableValidator.sol @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.23; + +import { ERC7579ValidatorBase } from "@rhinestone/modulekit/src/Modules.sol"; +import { PackedUserOperation } from "@rhinestone/modulekit/src/external/ERC4337.sol"; + +import { SignatureCheckerLib } from "solady/src/utils/SignatureCheckerLib.sol"; +import { ECDSA } from "solady/src/utils/ECDSA.sol"; + +contract OwnableValidator is ERC7579ValidatorBase { + using SignatureCheckerLib for address; + + mapping(address subAccout => address owner) public owners; + + function onInstall(bytes calldata data) external override { + if (data.length == 0) return; + address owner = abi.decode(data, (address)); + owners[msg.sender] = owner; + } + + function onUninstall(bytes calldata) external override { + delete owners[msg.sender]; + } + + function validateUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash + ) + external + view + override + returns (ValidationData) + { + bool validSig = owners[userOp.sender].isValidSignatureNow( + ECDSA.toEthSignedMessageHash(userOpHash), userOp.signature + ); + return _packValidationData(!validSig, type(uint48).max, 0); + } + + function isValidSignatureWithSender( + address, + bytes32 hash, + bytes calldata data + ) + external + view + override + returns (bytes4) + { + address owner = owners[msg.sender]; + return SignatureCheckerLib.isValidSignatureNowCalldata(owner, hash, data) + ? EIP1271_SUCCESS + : EIP1271_FAILED; + } + + function name() external pure returns (string memory) { + return "OwnableValidator"; + } + + function version() external pure returns (string memory) { + return "0.0.1"; + } + + function isModuleType(uint256 typeID) external pure override returns (bool) { + return typeID == TYPE_VALIDATOR; + } + + function isInitialized(address smartAccount) external view returns (bool) { } +} diff --git a/examples/src/ScheduledTransactions/ScheduledOrders.sol b/examples/src/ScheduledTransactions/ScheduledOrders.sol new file mode 100644 index 00000000..3310da84 --- /dev/null +++ b/examples/src/ScheduledTransactions/ScheduledOrders.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import { IERC7579Account, Execution } from "@rhinestone/modulekit/src/Accounts.sol"; +import { SchedulingBase } from "./SchedulingBase.sol"; +import { UniswapV3Integration } from "@rhinestone/modulekit/src/Integrations.sol"; +import { IERC20 } from "forge-std/interfaces/IERC20.sol"; +import { ModeLib } from "erc7579/lib/ModeLib.sol"; +import { ExecutionLib } from "erc7579/lib/ExecutionLib.sol"; + +contract ScheduledOrders is SchedulingBase { + function executeOrder(uint256 jobId) external override canExecute(jobId) { + ExecutionConfig storage executionConfig = _executionLog[msg.sender][jobId]; + + // decode from execution tokenIn, tokenOut and amount in + (address tokenIn, address tokenOut, uint256 amountIn, uint160 sqrtPriceLimitX96) = + abi.decode(executionConfig.executionData, (address, address, uint256, uint160)); + + Execution[] memory executions = UniswapV3Integration.approveAndSwap({ + smartAccount: msg.sender, + tokenIn: IERC20(tokenIn), + tokenOut: IERC20(tokenOut), + amountIn: amountIn, + sqrtPriceLimitX96: sqrtPriceLimitX96 + }); + + executionConfig.lastExecutionTime = uint48(block.timestamp); + executionConfig.numberOfExecutionsCompleted += 1; + + IERC7579Account(msg.sender).executeFromExecutor( + ModeLib.encodeSimpleBatch(), ExecutionLib.encodeBatch(executions) + ); + + emit ExecutionTriggered(msg.sender, jobId); + } + + function name() external pure virtual returns (string memory) { + return "Scheduled Orders"; + } + + function version() external pure virtual returns (string memory) { + return "0.0.1"; + } +} diff --git a/examples/src/ScheduledTransactions/ScheduledTransfers.sol b/examples/src/ScheduledTransactions/ScheduledTransfers.sol new file mode 100644 index 00000000..40b8f8f4 --- /dev/null +++ b/examples/src/ScheduledTransactions/ScheduledTransfers.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import { IERC7579Account, Execution } from "@rhinestone/modulekit/src/Accounts.sol"; +import { SchedulingBase } from "./SchedulingBase.sol"; +import { ModeLib } from "erc7579/lib/ModeLib.sol"; +import { ExecutionLib } from "erc7579/lib/ExecutionLib.sol"; + +contract ScheduledTransfers is SchedulingBase { + function executeOrder(uint256 jobId) external override canExecute(jobId) { + ExecutionConfig storage executionConfig = _executionLog[msg.sender][jobId]; + + Execution memory execution = abi.decode(executionConfig.executionData, (Execution)); + + executionConfig.lastExecutionTime = uint48(block.timestamp); + executionConfig.numberOfExecutionsCompleted += 1; + + IERC7579Account(msg.sender).executeFromExecutor( + ModeLib.encodeSimpleSingle(), + ExecutionLib.encodeSingle(execution.target, execution.value, execution.callData) + ); + + emit ExecutionTriggered(msg.sender, jobId); + } + + function name() external pure virtual returns (string memory) { + return "Scheduled Transfers"; + } + + function version() external pure virtual returns (string memory) { + return "0.0.1"; + } +} diff --git a/examples/src/ScheduledTransactions/SchedulingBase.sol b/examples/src/ScheduledTransactions/SchedulingBase.sol new file mode 100644 index 00000000..22c2cc31 --- /dev/null +++ b/examples/src/ScheduledTransactions/SchedulingBase.sol @@ -0,0 +1,188 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import { IERC20 } from "forge-std/interfaces/IERC20.sol"; +import { IERC7579Account } from "@rhinestone/modulekit/src/Accounts.sol"; +import { ERC7579ExecutorBase, SessionKeyBase } from "@rhinestone/modulekit/src/Modules.sol"; + +abstract contract SchedulingBase is ERC7579ExecutorBase, SessionKeyBase { + error InvalidExecution(); + error InvalidInstall(); + error InvalidJob(); + + event ExecutionAdded(address indexed smartAccount, uint256 indexed jobId); + event ExecutionTriggered(address indexed smartAccount, uint256 indexed jobId); + event ExecutionStatusUpdated(address indexed smartAccount, uint256 indexed jobId); + event ExecutionsCancelled(address indexed smartAccount); + + mapping(address smartAccount => mapping(uint256 jobId => ExecutionConfig)) internal + _executionLog; + + mapping(address smartAccount => uint256 jobCount) internal _accountJobCount; + + struct ExecutionConfig { + uint48 executeInterval; + uint16 numberOfExecutions; + uint16 numberOfExecutionsCompleted; + uint48 startDate; + bool isEnabled; + uint48 lastExecutionTime; + bytes executionData; + } + + struct ExecutorAccess { + address sessionKeySigner; + uint256 jobId; + } + + function _isExecutionValid(uint256 jobId) internal view { + ExecutionConfig storage executionConfig = _executionLog[msg.sender][jobId]; + + if (!executionConfig.isEnabled) { + revert InvalidExecution(); + } + + if (executionConfig.lastExecutionTime + executionConfig.executeInterval < block.timestamp) { + revert InvalidExecution(); + } + if (executionConfig.numberOfExecutionsCompleted >= executionConfig.numberOfExecutions) { + revert InvalidExecution(); + } + if (executionConfig.startDate > block.timestamp) { + revert InvalidExecution(); + } + } + + modifier canExecute(uint256 jobId) { + _isExecutionValid(jobId); + _; + } + + // abstract methohd to be implemented by the inheriting contract + function executeOrder(uint256 jobId) external virtual; + + function _createExecution(ExecutionConfig calldata data) internal { + uint256 jobId = _accountJobCount[msg.sender] + 1; + _accountJobCount[msg.sender]++; + + _executionLog[msg.sender][jobId] = ExecutionConfig({ + numberOfExecutionsCompleted: 0, + isEnabled: true, + lastExecutionTime: 0, + executeInterval: data.executeInterval, + numberOfExecutions: data.numberOfExecutions, + startDate: data.startDate, + executionData: data.executionData + }); + + emit ExecutionAdded(msg.sender, jobId); + } + + function addOrder(ExecutionConfig calldata executionConfig) external { + _createExecution(executionConfig); + } + + function toggleOrder(uint256 jobId) external { + ExecutionConfig storage executionConfig = _executionLog[msg.sender][jobId]; + executionConfig.isEnabled = !executionConfig.isEnabled; + emit ExecutionStatusUpdated(msg.sender, jobId); + } + + function validateSessionParams( + address destinationContract, + uint256 callValue, + bytes calldata callData, + bytes calldata _sessionKeyData, + bytes calldata /*_callSpecificData*/ + ) + external + view + virtual + override + returns (address) + { + ExecutorAccess memory access = abi.decode(_sessionKeyData, (ExecutorAccess)); + + bytes4 targetSelector = bytes4(callData[:4]); + + uint256 jobId = abi.decode(callData[4:], (uint256)); + if (targetSelector != this.executeOrder.selector) { + revert InvalidMethod(targetSelector); + } + + if (jobId != access.jobId) { + revert InvalidJob(); + } + + if (destinationContract != address(this)) { + revert InvalidRecipient(); + } + + if (callValue != 0) { + revert InvalidValue(); + } + + return access.sessionKeySigner; + } + + function onInstall(bytes calldata data) external override { + if (_accountJobCount[msg.sender] != 0) { + revert InvalidInstall(); + } + + ( + uint48 executeInterval, + uint16 numberOfExecutions, + uint48 startDate, + bytes memory executionData + ) = abi.decode(data, (uint48, uint16, uint48, bytes)); + + uint256 jobId = _accountJobCount[msg.sender] + 1; + _accountJobCount[msg.sender]++; + + _executionLog[msg.sender][jobId] = ExecutionConfig({ + numberOfExecutionsCompleted: 0, + isEnabled: true, + lastExecutionTime: 0, + executeInterval: executeInterval, + numberOfExecutions: numberOfExecutions, + startDate: startDate, + executionData: executionData + }); + + emit ExecutionAdded(msg.sender, jobId); + } + + function getAccountJobDetails( + address smartAccount, + uint256 jobId + ) + external + view + returns (ExecutionConfig memory) + { + return _executionLog[smartAccount][jobId]; + } + + function getAccountJobCount(address smartAccount) external view returns (uint256) { + return _accountJobCount[smartAccount]; + } + + function onUninstall(bytes calldata) external { + uint256 count = _accountJobCount[msg.sender]; + for (uint256 i = 1; i <= count; i++) { + delete _executionLog[msg.sender][i]; + } + _accountJobCount[msg.sender] = 0; + + emit ExecutionsCancelled(msg.sender); + } + + function isModuleType(uint256 typeID) external pure override returns (bool) { + return typeID == TYPE_EXECUTOR; + } + + function isInitialized(address smartAccount) external view returns (bool) { + return _accountJobCount[smartAccount] != 0; + } +} diff --git a/examples/src/TokenRevocation/ERC20Revocation.sol b/examples/src/TokenRevocation/ERC20Revocation.sol new file mode 100644 index 00000000..d0d910ae --- /dev/null +++ b/examples/src/TokenRevocation/ERC20Revocation.sol @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import { SessionKeyBase } from "@rhinestone/modulekit/src/Modules.sol"; +import { IERC20 } from "forge-std/interfaces/IERC20.sol"; +import { IERC721 } from "forge-std/interfaces/IERC721.sol"; + +contract ERC20Revocation is SessionKeyBase { + enum TokenType { + ERC20, + ERC721 + } + + struct Token { + address token; + TokenType tokenType; + address sessionKeySigner; + } + + error InvalidToken(); + error NotZero(); + + function encode(Token memory transaction) public pure returns (bytes memory) { + return abi.encode(transaction); + } + + function validateSessionParams( + address to, + uint256 value, + bytes calldata callData, + bytes calldata sessionKeyData, + bytes calldata /*_callSpecificData*/ + ) + external + returns (address) + { + Token memory transaction = abi.decode(sessionKeyData, (Token)); + bytes4 targetSelector = bytes4(callData[:4]); + + if (transaction.token != to) revert InvalidToken(); + if (value != 0) revert InvalidValue(); + if (transaction.tokenType == TokenType.ERC20) { + _validateERC20(targetSelector, callData); + } else if (transaction.tokenType == TokenType.ERC721) { + _validateERC721(targetSelector, callData); + } else { + revert InvalidToken(); + } + + return transaction.sessionKeySigner; + } + + function _validateERC20(bytes4 targetSelector, bytes calldata callData) internal pure { + // handle ERC20 + if (targetSelector == IERC20.approve.selector) { + (, uint256 amount) = abi.decode(callData[4:], (address, uint256)); // (spender, + // amount) + if (amount != 0) revert NotZero(); + } else { + revert InvalidMethod(targetSelector); + } + } + + function _validateERC721(bytes4 targetSelector, bytes calldata callData) internal pure { + // Handle ERC721 + if (targetSelector == IERC721.approve.selector) { + (address spender,) = abi.decode(callData[4:], (address, uint256)); // (spender,tokenId) + if (spender != address(0)) revert NotZero(); + } else if (targetSelector == IERC721.setApprovalForAll.selector) { + (, bool approved) = abi.decode(callData[4:], (address, bool)); // (spender, + // approved) + if (approved) revert NotZero(); + } else { + revert InvalidMethod(targetSelector); + } + } + + function onInstall(bytes calldata data) external { } + + function onUninstall(bytes calldata data) external { } + + function isModuleType(uint256 typeID) external pure override returns (bool) { + return typeID == TYPE_EXECUTOR; + } + + function isInitialized(address smartAccount) external view returns (bool) { } + + function name() external pure virtual returns (string memory) { + return "AutoSaving"; + } + + function version() external pure virtual returns (string memory) { + return "0.0.1"; + } +} diff --git a/examples/src/WebauthnValidator/WebauthnValidator.sol b/examples/src/WebauthnValidator/WebauthnValidator.sol new file mode 100644 index 00000000..d29250c3 --- /dev/null +++ b/examples/src/WebauthnValidator/WebauthnValidator.sol @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.19; + +import { WebAuthnLib } from "./utils/WebAuthNLib.sol"; +import { ERC7579ValidatorBase } from "@rhinestone/modulekit/src/Modules.sol"; +import { + PackedUserOperation, UserOperationLib +} from "@rhinestone/modulekit/src/external/ERC4337.sol"; + +struct PassKeyId { + uint256 pubKeyX; + uint256 pubKeyY; + string keyId; +} + +contract WebAuthnValidator is ERC7579ValidatorBase { + using UserOperationLib for PackedUserOperation; + + error NoPassKeyRegisteredForSmartAccount(address smartAccount); + error AlreadyInitedForSmartAccount(address smartAccount); + + event NewPassKeyRegistered(address indexed smartAccount, string keyId); + + mapping(address account => PassKeyId passkeyConfig) public smartAccountPassKeys; + + function onInstall(bytes calldata data) external override { + PassKeyId memory passkey = abi.decode(data, (PassKeyId)); + smartAccountPassKeys[msg.sender] = passkey; + } + + function onUninstall(bytes calldata) external override { + _removePassKey(); + } + + function getAuthorizedKey(address account) public view returns (PassKeyId memory passkey) { + passkey = smartAccountPassKeys[account]; + } + + function _removePassKey() internal { + smartAccountPassKeys[msg.sender] = PassKeyId(0, 0, ""); + } + + function validateUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash + ) + external + override + returns (ValidationData) + { + ( + , + bytes memory authenticatorData, + bytes1 authenticatorDataFlagMask, + bytes memory clientData, + uint256 clientChallengeDataOffset, + uint256[2] memory rs + ) = abi.decode(userOp.signature, (bytes32, bytes, bytes1, bytes, uint256, uint256[2])); + + PassKeyId memory passKey = smartAccountPassKeys[userOp.getSender()]; + require(passKey.pubKeyX != 0 && passKey.pubKeyY != 0, "Key not found"); + uint256[2] memory Q = [passKey.pubKeyX, passKey.pubKeyY]; + bool isValidSignature = WebAuthnLib.checkSignature( + authenticatorData, + authenticatorDataFlagMask, + clientData, + userOpHash, + clientChallengeDataOffset, + rs, + Q + ); + + return _packValidationData(!isValidSignature, 0, type(uint48).max); + } + + function isValidSignatureWithSender( + address, + bytes32, + bytes calldata + ) + external + view + virtual + override + returns (bytes4) + { + return EIP1271_FAILED; + } + + function name() external pure returns (string memory) { + return "WebAuthnValidator"; + } + + function version() external pure returns (string memory) { + return "0.0.1"; + } + + function isModuleType(uint256 typeID) external pure override returns (bool) { + return typeID == TYPE_VALIDATOR; + } + + function isInitialized(address smartAccount) external view returns (bool) { } +} diff --git a/examples/src/WebauthnValidator/utils/Base64URL.sol b/examples/src/WebauthnValidator/utils/Base64URL.sol new file mode 100644 index 00000000..9a85cd33 --- /dev/null +++ b/examples/src/WebauthnValidator/utils/Base64URL.sol @@ -0,0 +1,97 @@ +/* solhint-disable */ +// SPDX-License-Identifier: MIT +// from OpenZeppelin Contracts (last updated v4.7.0) (utils/Base64.sol) + +pragma solidity ^0.8.19; + +/** + * @dev Provides a set of functions to operate with Base64 strings. + * + * _Available since v4.5._ + */ +library Base64URL { + /** + * @dev Base64 Encoding/Decoding Table + */ + string internal constant _TABLE = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; + + /** + * @dev Converts a `bytes` to its Bytes64 `string` representation. + */ + function encode32(bytes memory data) internal pure returns (string memory) { + /** + * Inspired by Brecht Devos (Brechtpd) implementation - MIT licence + * https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol + */ + if (data.length == 0) return ""; + + // Loads the table into memory + string memory table = _TABLE; + + // Encoding takes 3 bytes chunks of binary data from `bytes` data parameter + // and split into 4 numbers of 6 bits. + // The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up + // - `data.length + 2` -> Round up + // - `/ 3` -> Number of 3-bytes chunks + // - `4 *` -> 4 characters for each chunk + //string memory result = new string(4 * ((data.length + 2) / 3)); + string memory result = new string(4 * ((data.length + 2) / 3) - 1); + + /// @solidity memory-safe-assembly + // @solhint-disable-next-line no-inline-assembly + assembly { + // Prepare the lookup table (skip the first "length" byte) + let tablePtr := add(table, 1) + + // Prepare result pointer, jump over length + let resultPtr := add(result, 32) + + // Run over the input, 3 bytes at a time + for { + let dataPtr := data + let endPtr := add(data, mload(data)) + } lt(dataPtr, endPtr) { } { + // Advance 3 bytes + dataPtr := add(dataPtr, 3) + let input := mload(dataPtr) + + // To write each character, shift the 3 bytes (18 bits) chunk + // 4 times in blocks of 6 bits for each character (18, 12, 6, 0) + // and apply logical AND with 0x3F which is the number of + // the previous character in the ASCII table prior to the Base64 Table + // The result is then added to the table to get the character to write, + // and finally write it in the result pointer but with a left shift + // of 256 (1 byte) - 8 (1 ASCII char) = 248 bits + + mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + } + + /* + // When data `bytes` is not exactly 3 bytes long + // it is padded with `=` characters at the end + switch mod(mload(data), 3) + case 1 { + mstore8(sub(resultPtr, 1), 0x3d) + mstore8(sub(resultPtr, 2), 0x3d) + } + case 2 { + mstore8(sub(resultPtr, 1), 0x3d) + } + */ + } + + return result; + } +} +/* solhint-enable */ diff --git a/examples/src/WebauthnValidator/utils/EllipticCurve.sol b/examples/src/WebauthnValidator/utils/EllipticCurve.sol new file mode 100644 index 00000000..3d1f7998 --- /dev/null +++ b/examples/src/WebauthnValidator/utils/EllipticCurve.sol @@ -0,0 +1,1096 @@ +/* solhint-disable */ +//********************************************************************************************/ +// ___ _ ___ _ _ _ _ +// | __| _ ___ __| |_ / __|_ _ _ _ _ __| |_ ___ | | (_) |__ +// | _| '_/ -_|_-< ' \ | (__| '_| || | '_ \ _/ _ \ | |__| | '_ \ +// |_||_| \___/__/_||_| \___|_| \_, | .__/\__\___/ |____|_|_.__/ +// |__/|_| +///* Copyright (C) 2022 - Renaud Dubois - This file is part of FCL (Fresh CryptoLib) project +///* License: This software is licensed under MIT License +///* This Code may be reused including license and copyright notice. +///* See LICENSE file at the root folder of the project. +///* FILE: FCL_elliptic.sol +///* +///* +///* DESCRIPTION: modified XYZZ system coordinates for EVM elliptic point multiplication +///* optimization +///* +//**************************************************************************************/ +//* WARNING: this code SHALL not be used for non prime order curves for security reasons. +// Code is optimized for a=-3 only curves with prime order, constant like -1, -2 shall be replaced +// if ever used for other curve than sec256R1 +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +library EllipticCurveP256 { + // Set parameters for curve sec256r1. + + //curve prime field modulus + uint256 constant p = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF; + //short weierstrass first coefficient + uint256 constant a = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC; + //short weierstrass second coefficient + uint256 constant b = 0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B; + //generating point affine coordinates + uint256 constant gx = 0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296; + uint256 constant gy = 0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5; + //curve order (number of points) + uint256 constant n = 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551; + /* -2 mod p constant, used to speed up inversion and doubling (avoid negation)*/ + uint256 constant minus_2 = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFD; + /* -2 mod n constant, used to speed up inversion*/ + uint256 constant minus_2modn = + 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC63254F; + + uint256 constant minus_1 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + + /** + * /* inversion mod n via a^(n-2), use of precompiled using little Fermat theorem + */ + function FCL_nModInv(uint256 u) internal returns (uint256 result) { + uint256[6] memory pointer; + assembly { + // Define length of base, exponent and modulus. 0x20 == 32 bytes + mstore(pointer, 0x20) + mstore(add(pointer, 0x20), 0x20) + mstore(add(pointer, 0x40), 0x20) + // Define variables base, exponent and modulus + mstore(add(pointer, 0x60), u) + mstore(add(pointer, 0x80), minus_2modn) + mstore(add(pointer, 0xa0), n) + + // Call the precompiled contract 0x05 = ModExp + if iszero(call(not(0), 0x05, 0, pointer, 0xc0, pointer, 0x20)) { revert(0, 0) } + result := mload(pointer) + } + } + + /** + * /* @dev inversion mod nusing little Fermat theorem via a^(n-2), use of precompiled + */ + function FCL_pModInv(uint256 u) internal returns (uint256 result) { + uint256[6] memory pointer; + assembly { + // Define length of base, exponent and modulus. 0x20 == 32 bytes + mstore(pointer, 0x20) + mstore(add(pointer, 0x20), 0x20) + mstore(add(pointer, 0x40), 0x20) + // Define variables base, exponent and modulus + mstore(add(pointer, 0x60), u) + mstore(add(pointer, 0x80), minus_2) + mstore(add(pointer, 0xa0), p) + + // Call the precompiled contract 0x05 = ModExp + if iszero(call(not(0), 0x05, 0, pointer, 0xc0, pointer, 0x20)) { revert(0, 0) } + result := mload(pointer) + } + } + + /** + * /* @dev Convert from affine rep to XYZZ rep + */ + function ecAff_SetZZ(uint256 x0, uint256 y0) internal pure returns (uint256[4] memory P) { + unchecked { + P[2] = 1; //ZZ + P[3] = 1; //ZZZ + P[0] = x0; + P[1] = y0; + } + } + + /** + * /* @dev Convert from XYZZ rep to affine rep + */ + /* https://hyperelliptic.org/EFD/g1p/auto-shortw-xyzz-3.html#addition-add-2008-s*/ + function ecZZ_SetAff( + uint256 x, + uint256 y, + uint256 zz, + uint256 zzz + ) + internal + returns (uint256 x1, uint256 y1) + { + uint256 zzzInv = FCL_pModInv(zzz); //1/zzz + y1 = mulmod(y, zzzInv, p); //Y/zzz + uint256 _b = mulmod(zz, zzzInv, p); //1/z + zzzInv = mulmod(_b, _b, p); //1/zz + x1 = mulmod(x, zzzInv, p); //X/zz + } + + /** + * /* @dev Sutherland2008 doubling + */ + /* The "dbl-2008-s-1" doubling formulas */ + + function ecZZ_Dbl( + uint256 x, + uint256 y, + uint256 zz, + uint256 zzz + ) + internal + pure + returns (uint256 P0, uint256 P1, uint256 P2, uint256 P3) + { + unchecked { + assembly { + P0 := mulmod(2, y, p) //U = 2*Y1 + P2 := mulmod(P0, P0, p) // V=U^2 + P3 := mulmod(x, P2, p) // S = X1*V + P1 := mulmod(P0, P2, p) // W=UV + P2 := mulmod(P2, zz, p) //zz3=V*ZZ1 + zz := mulmod(3, mulmod(addmod(x, sub(p, zz), p), addmod(x, zz, p), p), p) //M=3*(X1-ZZ1)*(X1+ZZ1) + P0 := addmod(mulmod(zz, zz, p), mulmod(minus_2, P3, p), p) //X3=M^2-2S + x := mulmod(zz, addmod(P3, sub(p, P0), p), p) //M(S-X3) + P3 := mulmod(P1, zzz, p) //zzz3=W*zzz1 + P1 := addmod(x, sub(p, mulmod(P1, y, p)), p) //Y3= M(S-X3)-W*Y1 + } + } + return (P0, P1, P2, P3); + } + + /** + * @dev Sutherland2008 add a ZZ point with a normalized point and greedy formulae + * warning: assume that P1(x1,y1)!=P2(x2,y2), true in multiplication loop with prime order + * (cofactor 1) + */ + + //tbd: return -x1 and -Y1 in double to avoid two substractions + function ecZZ_AddN( + uint256 x1, + uint256 y1, + uint256 zz1, + uint256 zzz1, + uint256 x2, + uint256 y2 + ) + internal + pure + returns (uint256 P0, uint256 P1, uint256 P2, uint256 P3) + { + unchecked { + if (y1 == 0) { + return (x2, y2, 1, 1); + } + + assembly { + y1 := sub(p, y1) + y2 := addmod(mulmod(y2, zzz1, p), y1, p) + x2 := addmod(mulmod(x2, zz1, p), sub(p, x1), p) + P0 := mulmod(x2, x2, p) //PP = P^2 + P1 := mulmod(P0, x2, p) //PPP = P*PP + P2 := mulmod(zz1, P0, p) ////ZZ3 = ZZ1*PP + P3 := mulmod(zzz1, P1, p) ////ZZZ3 = ZZZ1*PPP + zz1 := mulmod(x1, P0, p) //Q = X1*PP + P0 := addmod(addmod(mulmod(y2, y2, p), sub(p, P1), p), mulmod(minus_2, zz1, p), p) //R^2-PPP-2*Q + P1 := addmod(mulmod(addmod(zz1, sub(p, P0), p), y2, p), mulmod(y1, P1, p), p) //R*(Q-X3) + } + //end assembly + } //end unchecked + return (P0, P1, P2, P3); + } + + /** + * @dev Return the zero curve in XYZZ coordinates. + */ + function ecZZ_SetZero() internal pure returns (uint256 x, uint256 y, uint256 zz, uint256 zzz) { + return (0, 0, 0, 0); + } + + /** + * @dev Check if point is the neutral of the curve + */ + function ecZZ_IsZero( + uint256 x0, + uint256 y0, + uint256 zz0, + uint256 zzz0 + ) + internal + pure + returns (bool) + { + if ((y0 == 0)) { + return true; + } + return false; + } + + /** + * @dev Return the zero curve in affine coordinates. Compatible with the double formulae (no + * special case) + */ + function ecAff_SetZero() internal pure returns (uint256 x, uint256 y) { + return (0, 0); + } + + /** + * @dev Check if the curve is the zero curve in affine rep. + */ + function ecAff_IsZero(uint256 x, uint256 y) internal pure returns (bool flag) { + return (y == 0); + } + + /** + * @dev Check if a point in affine coordinates is on the curve (reject Neutral that is indeed on + * the curve). + */ + function ecAff_isOnCurve(uint256 x, uint256 y) internal pure returns (bool) { + if (0 == x || x == p || 0 == y || y == p) { + return false; + } + unchecked { + uint256 LHS = mulmod(y, y, p); // y^2 + uint256 RHS = addmod(mulmod(mulmod(x, x, p), x, p), mulmod(x, a, p), p); // x^3+ax + RHS = addmod(RHS, b, p); // x^3 + a*x + b + + return LHS == RHS; + } + } + + /** + * @dev Add two elliptic curve points in affine coordinates. + */ + function ecAff_add( + uint256 x0, + uint256 y0, + uint256 x1, + uint256 y1 + ) + internal + returns (uint256, uint256) + { + uint256 zz0; + uint256 zzz0; + + if (ecAff_IsZero(x0, y0)) return (x1, y1); + if (ecAff_IsZero(x1, y1)) return (x0, y0); + + (x0, y0, zz0, zzz0) = ecZZ_AddN(x0, y0, 1, 1, x1, y1); + + return ecZZ_SetAff(x0, y0, zz0, zzz0); + } + + /** + * @dev Computation of uG+vQ using Strauss-Shamir's trick, G basepoint, Q public key + */ + function ecZZ_mulmuladd_S_asm( + uint256 Q0, + uint256 Q1, //affine rep for input point Q + uint256 scalar_u, + uint256 scalar_v + ) + internal + returns (uint256 X) + { + uint256 zz; + uint256 zzz; + uint256 Y; + uint256 index = 255; + uint256[6] memory T; + uint256 H0; + uint256 H1; + + unchecked { + if (scalar_u == 0 && scalar_v == 0) return 0; + + (H0, H1) = ecAff_add(gx, gy, Q0, Q1); //will not work if Q=P, obvious forbidden private + // key + + /* + while( ( ((scalar_u>>index)&1)+2*((scalar_v>>index)&1) ) ==0){ + index=index-1; + } + */ + + assembly { + for { + let T4 := + add(shl(1, and(shr(index, scalar_v), 1)), and(shr(index, scalar_u), 1)) + } eq(T4, 0) { + index := sub(index, 1) + T4 := add(shl(1, and(shr(index, scalar_v), 1)), and(shr(index, scalar_u), 1)) + } { } + zz := add(shl(1, and(shr(index, scalar_v), 1)), and(shr(index, scalar_u), 1)) + + if eq(zz, 1) { + X := gx + Y := gy + } + if eq(zz, 2) { + X := Q0 + Y := Q1 + } + if eq(zz, 3) { + X := H0 + Y := H1 + } + + index := sub(index, 1) + zz := 1 + zzz := 1 + + for { } gt(minus_1, index) { index := sub(index, 1) } { + // inlined EcZZ_Dbl + let T1 := mulmod(2, Y, p) //U = 2*Y1, y free + let T2 := mulmod(T1, T1, p) // V=U^2 + let T3 := mulmod(X, T2, p) // S = X1*V + T1 := mulmod(T1, T2, p) // W=UV + let T4 := mulmod(3, mulmod(addmod(X, sub(p, zz), p), addmod(X, zz, p), p), p) //M=3*(X1-ZZ1)*(X1+ZZ1) + zzz := mulmod(T1, zzz, p) //zzz3=W*zzz1 + zz := mulmod(T2, zz, p) //zz3=V*ZZ1, V free + + X := addmod(mulmod(T4, T4, p), mulmod(minus_2, T3, p), p) //X3=M^2-2S + //T2:=mulmod(T4,addmod(T3, sub(p, X),p),p)//M(S-X3) + T2 := mulmod(T4, addmod(X, sub(p, T3), p), p) //-M(S-X3)=M(X3-S) + + //Y:= addmod(T2, sub(p, mulmod(T1, Y ,p)),p )//Y3= M(S-X3)-W*Y1 + Y := addmod(mulmod(T1, Y, p), T2, p) //-Y3= W*Y1-M(S-X3), we replace Y by -Y to + // avoid a sub in ecAdd + + { + //value of dibit + T4 := + add(shl(1, and(shr(index, scalar_v), 1)), and(shr(index, scalar_u), 1)) + + if iszero(T4) { + Y := sub(p, Y) //restore the -Y inversion + continue + } // if T4!=0 + + if eq(T4, 1) { + T1 := gx + T2 := gy + } + if eq(T4, 2) { + T1 := Q0 + T2 := Q1 + } + if eq(T4, 3) { + T1 := H0 + T2 := H1 + } + if eq(zz, 0) { + X := T1 + Y := T2 + zz := 1 + zzz := 1 + continue + } + // inlined EcZZ_AddN + + //T3:=sub(p, Y) + //T3:=Y + let y2 := addmod(mulmod(T2, zzz, p), Y, p) //R + T2 := addmod(mulmod(T1, zz, p), sub(p, X), p) //P + + //special extremely rare case accumulator where EcAdd is replaced by EcDbl, + // no need to optimize + // this + //todo : construct edge vector case + if eq(y2, 0) { + if eq(T2, 0) { + T1 := mulmod(minus_2, Y, p) //U = 2*Y1, y free + T2 := mulmod(T1, T1, p) // V=U^2 + T3 := mulmod(X, T2, p) // S = X1*V + + let TT1 := mulmod(T1, T2, p) // W=UV + y2 := addmod(X, zz, p) + TT1 := addmod(X, sub(p, zz), p) + y2 := mulmod(y2, TT1, p) //(X-ZZ)(X+ZZ) + T4 := mulmod(3, y2, p) //M + + zzz := mulmod(TT1, zzz, p) //zzz3=W*zzz1 + zz := mulmod(T2, zz, p) //zz3=V*ZZ1, V free + + X := addmod(mulmod(T4, T4, p), mulmod(minus_2, T3, p), p) //X3=M^2-2S + T2 := mulmod(T4, addmod(T3, sub(p, X), p), p) //M(S-X3) + + Y := addmod(T2, mulmod(T1, Y, p), p) //Y3= M(S-X3)-W*Y1 + + continue + } + } + + T4 := mulmod(T2, T2, p) //PP + let TT1 := mulmod(T4, T2, p) //PPP, this one could be spared, but adding + // this register spare gas + zz := mulmod(zz, T4, p) + zzz := mulmod(zzz, TT1, p) //zz3=V*ZZ1 + let TT2 := mulmod(X, T4, p) + T4 := + addmod( + addmod(mulmod(y2, y2, p), sub(p, TT1), p), mulmod(minus_2, TT2, p), p + ) + Y := addmod(mulmod(addmod(TT2, sub(p, T4), p), y2, p), mulmod(Y, TT1, p), p) + + X := T4 + } + } //end loop + mstore(add(T, 0x60), zz) + //(X,Y)=ecZZ_SetAff(X,Y,zz, zzz); + //T[0] = inverseModp_Hard(T[0], p); //1/zzz, inline modular inversion using + // precompile: + // Define length of base, exponent and modulus. 0x20 == 32 bytes + mstore(T, 0x20) + mstore(add(T, 0x20), 0x20) + mstore(add(T, 0x40), 0x20) + // Define variables base, exponent and modulus + //mstore(add(pointer, 0x60), u) + mstore(add(T, 0x80), minus_2) + mstore(add(T, 0xa0), p) + + // Call the precompiled contract 0x05 = ModExp + if iszero(call(not(0), 0x05, 0, T, 0xc0, T, 0x20)) { revert(0, 0) } + + //Y:=mulmod(Y,zzz,p)//Y/zzz + //zz :=mulmod(zz, mload(T),p) //1/z + //zz:= mulmod(zz,zz,p) //1/zz + X := mulmod(X, mload(T), p) //X/zz + } //end assembly + } //end unchecked + + return X; + } + + //8 dimensions Shamir's trick, using precomputations stored in Shamir8, stored as Bytecode of + // an external + //contract at given address dataPointer + //(thx to Lakhdar https://github.com/Kelvyne for EVM storage explanations and tricks) + // the external tool to generate tables from public key is in the /sage directory + function ecZZ_mulmuladd_S8_extcode( + uint256 scalar_u, + uint256 scalar_v, + address dataPointer + ) + internal + returns (uint256 X /*, uint Y*/ ) + { + unchecked { + uint256 zz; // third and coordinates of the point + + uint256[6] memory T; + zz = 256; //start index + + while (T[0] == 0) { + zz = zz - 1; + //tbd case of msb octobit is null + T[0] = 64 + * ( + 128 * ((scalar_v >> zz) & 1) + 64 * ((scalar_v >> (zz - 64)) & 1) + + 32 * ((scalar_v >> (zz - 128)) & 1) + 16 * ((scalar_v >> (zz - 192)) & 1) + + 8 * ((scalar_u >> zz) & 1) + 4 * ((scalar_u >> (zz - 64)) & 1) + + 2 * ((scalar_u >> (zz - 128)) & 1) + ((scalar_u >> (zz - 192)) & 1) + ); + } + assembly { + extcodecopy(dataPointer, T, mload(T), 64) + + X := mload(T) + let Y := mload(add(T, 32)) + let zzz := 1 + zz := 1 + + //loop over 1/4 of scalars thx to Shamir's trick over 8 points + for { let index := 254 } gt(index, 191) { index := add(index, 191) } { + { + let TT1 := mulmod(2, Y, p) //U = 2*Y1, y free + let T2 := mulmod(TT1, TT1, p) // V=U^2 + let T3 := mulmod(X, T2, p) // S = X1*V + let T1 := mulmod(TT1, T2, p) // W=UV + let T4 := + mulmod(3, mulmod(addmod(X, sub(p, zz), p), addmod(X, zz, p), p), p) //M=3*(X1-ZZ1)*(X1+ZZ1) + zzz := mulmod(T1, zzz, p) //zzz3=W*zzz1 + zz := mulmod(T2, zz, p) //zz3=V*ZZ1, V free + + X := addmod(mulmod(T4, T4, p), mulmod(minus_2, T3, p), p) //X3=M^2-2S + //T2:=mulmod(T4,addmod(T3, sub(p, X),p),p)//M(S-X3) + let T5 := mulmod(T4, addmod(X, sub(p, T3), p), p) //-M(S-X3)=M(X3-S) + + //Y:= addmod(T2, sub(p, mulmod(T1, Y ,p)),p )//Y3= M(S-X3)-W*Y1 + Y := addmod(mulmod(T1, Y, p), T5, p) //-Y3= W*Y1-M(S-X3), we replace Y by -Y + // to avoid a sub in + // ecAdd + + /* compute element to access in precomputed table */ + } + { + let T4 := + add( + shl(13, and(shr(index, scalar_v), 1)), + shl(9, and(shr(index, scalar_u), 1)) + ) + let index2 := sub(index, 64) + let T3 := + add( + T4, + add( + shl(12, and(shr(index2, scalar_v), 1)), + shl(8, and(shr(index2, scalar_u), 1)) + ) + ) + let index3 := sub(index2, 64) + let T2 := + add( + T3, + add( + shl(11, and(shr(index3, scalar_v), 1)), + shl(7, and(shr(index3, scalar_u), 1)) + ) + ) + index := sub(index3, 64) + let T1 := + add( + T2, + add( + shl(10, and(shr(index, scalar_v), 1)), + shl(6, and(shr(index, scalar_u), 1)) + ) + ) + + //index:=add(index,192), restore index, interleaved with loop + + //tbd: check validity of formulae with (0,1) to remove conditional jump + if iszero(T1) { + Y := sub(p, Y) + + continue + } + extcodecopy(dataPointer, T, T1, 64) + } + + { + /* Access to precomputed table using extcodecopy hack */ + + // inlined EcZZ_AddN + if iszero(zz) { + X := mload(T) + Y := mload(add(T, 32)) + zz := 1 + zzz := 1 + + continue + } + + let y2 := addmod(mulmod(mload(add(T, 32)), zzz, p), Y, p) + let T2 := addmod(mulmod(mload(T), zz, p), sub(p, X), p) + + //special case ecAdd(P,P)=EcDbl + if eq(y2, 0) { + if eq(T2, 0) { + let T1 := mulmod(minus_2, Y, p) //U = 2*Y1, y free + T2 := mulmod(T1, T1, p) // V=U^2 + let T3 := mulmod(X, T2, p) // S = X1*V + + let TT1 := mulmod(T1, T2, p) // W=UV + y2 := addmod(X, zz, p) + TT1 := addmod(X, sub(p, zz), p) + y2 := mulmod(y2, TT1, p) //(X-ZZ)(X+ZZ) + let T4 := mulmod(3, y2, p) //M + + zzz := mulmod(TT1, zzz, p) //zzz3=W*zzz1 + zz := mulmod(T2, zz, p) //zz3=V*ZZ1, V free + + X := addmod(mulmod(T4, T4, p), mulmod(minus_2, T3, p), p) //X3=M^2-2S + T2 := mulmod(T4, addmod(T3, sub(p, X), p), p) //M(S-X3) + + Y := addmod(T2, mulmod(T1, Y, p), p) //Y3= M(S-X3)-W*Y1 + + continue + } + } + + let T4 := mulmod(T2, T2, p) + let T1 := mulmod(T4, T2, p) // + zz := mulmod(zz, T4, p) + //zzz3=V*ZZ1 + zzz := mulmod(zzz, T1, p) // W=UV/ + let zz1 := mulmod(X, T4, p) + X := + addmod(addmod(mulmod(y2, y2, p), sub(p, T1), p), mulmod(minus_2, zz1, p), p) + Y := addmod(mulmod(addmod(zz1, sub(p, X), p), y2, p), mulmod(Y, T1, p), p) + } + } //end loop + mstore(add(T, 0x60), zz) + + //(X,Y)=ecZZ_SetAff(X,Y,zz, zzz); + //T[0] = inverseModp_Hard(T[0], p); //1/zzz, inline modular inversion using + // precompile: + // Define length of base, exponent and modulus. 0x20 == 32 bytes + mstore(T, 0x20) + mstore(add(T, 0x20), 0x20) + mstore(add(T, 0x40), 0x20) + // Define variables base, exponent and modulus + //mstore(add(pointer, 0x60), u) + mstore(add(T, 0x80), minus_2) + mstore(add(T, 0xa0), p) + + // Call the precompiled contract 0x05 = ModExp + if iszero(call(not(0), 0x05, 0, T, 0xc0, T, 0x20)) { revert(0, 0) } + + zz := mload(T) + X := mulmod(X, zz, p) //X/zz + } + } //end unchecked + } + + //8 dimensions Shamir's trick, using precomputations stored in Shamir8, stored as Bytecode of + // an external + //contract at given address dataPointer + //(thx to Lakhdar https://github.com/Kelvyne for EVM storage explanations and tricks) + // the external tool to generate tables from public key is in the /sage directory + function ecZZ_mulmuladd_S8_hackmem( + uint256 scalar_u, + uint256 scalar_v, + uint256 dataPointer + ) + internal + returns (uint256 X /*, uint Y*/ ) + { + unchecked { + uint256 zz; // third and coordinates of the point + + uint256[6] memory T; + zz = 256; //start index + + while (T[0] == 0) { + zz = zz - 1; + //tbd case of msb octobit is null + T[0] = 64 + * ( + 128 * ((scalar_v >> zz) & 1) + 64 * ((scalar_v >> (zz - 64)) & 1) + + 32 * ((scalar_v >> (zz - 128)) & 1) + 16 * ((scalar_v >> (zz - 192)) & 1) + + 8 * ((scalar_u >> zz) & 1) + 4 * ((scalar_u >> (zz - 64)) & 1) + + 2 * ((scalar_u >> (zz - 128)) & 1) + ((scalar_u >> (zz - 192)) & 1) + ); + } + assembly { + extcodecopy(dataPointer, T, mload(T), 64) + + X := mload(T) + let Y := mload(add(T, 32)) + let zzz := 1 + zz := 1 + + //loop over 1/4 of scalars thx to Shamir's trick over 8 points + for { let index := 254 } gt(index, 191) { index := add(index, 191) } { + { + let TT1 := mulmod(2, Y, p) //U = 2*Y1, y free + let T2 := mulmod(TT1, TT1, p) // V=U^2 + let T3 := mulmod(X, T2, p) // S = X1*V + let T1 := mulmod(TT1, T2, p) // W=UV + let T4 := + mulmod(3, mulmod(addmod(X, sub(p, zz), p), addmod(X, zz, p), p), p) //M=3*(X1-ZZ1)*(X1+ZZ1) + zzz := mulmod(T1, zzz, p) //zzz3=W*zzz1 + zz := mulmod(T2, zz, p) //zz3=V*ZZ1, V free + + X := addmod(mulmod(T4, T4, p), mulmod(minus_2, T3, p), p) //X3=M^2-2S + //T2:=mulmod(T4,addmod(T3, sub(p, X),p),p)//M(S-X3) + let T5 := mulmod(T4, addmod(X, sub(p, T3), p), p) //-M(S-X3)=M(X3-S) + + //Y:= addmod(T2, sub(p, mulmod(T1, Y ,p)),p )//Y3= M(S-X3)-W*Y1 + Y := addmod(mulmod(T1, Y, p), T5, p) //-Y3= W*Y1-M(S-X3), we replace Y by -Y + // to avoid a sub in + // ecAdd + + /* compute element to access in precomputed table */ + } + { + let T4 := + add( + shl(13, and(shr(index, scalar_v), 1)), + shl(9, and(shr(index, scalar_u), 1)) + ) + let index2 := sub(index, 64) + let T3 := + add( + T4, + add( + shl(12, and(shr(index2, scalar_v), 1)), + shl(8, and(shr(index2, scalar_u), 1)) + ) + ) + let index3 := sub(index2, 64) + let T2 := + add( + T3, + add( + shl(11, and(shr(index3, scalar_v), 1)), + shl(7, and(shr(index3, scalar_u), 1)) + ) + ) + index := sub(index3, 64) + let T1 := + add( + T2, + add( + shl(10, and(shr(index, scalar_v), 1)), + shl(6, and(shr(index, scalar_u), 1)) + ) + ) + + //index:=add(index,192), restore index, interleaved with loop + + //tbd: check validity of formulae with (0,1) to remove conditional jump + if iszero(T1) { + Y := sub(p, Y) + + continue + } + codecopy(T, add(dataPointer, T1), 64) + } + + { + /* Access to precomputed table using extcodecopy hack */ + + // inlined EcZZ_AddN + if iszero(zz) { + X := mload(T) + Y := mload(add(T, 32)) + zz := 1 + zzz := 1 + + continue + } + + let y2 := addmod(mulmod(mload(add(T, 32)), zzz, p), Y, p) + let T2 := addmod(mulmod(mload(T), zz, p), sub(p, X), p) + + //special case ecAdd(P,P)=EcDbl + if eq(y2, 0) { + if eq(T2, 0) { + let T1 := mulmod(minus_2, Y, p) //U = 2*Y1, y free + T2 := mulmod(T1, T1, p) // V=U^2 + let T3 := mulmod(X, T2, p) // S = X1*V + + let TT1 := mulmod(T1, T2, p) // W=UV + y2 := addmod(X, zz, p) + TT1 := addmod(X, sub(p, zz), p) + y2 := mulmod(y2, TT1, p) //(X-ZZ)(X+ZZ) + let T4 := mulmod(3, y2, p) //M + + zzz := mulmod(TT1, zzz, p) //zzz3=W*zzz1 + zz := mulmod(T2, zz, p) //zz3=V*ZZ1, V free + + X := addmod(mulmod(T4, T4, p), mulmod(minus_2, T3, p), p) //X3=M^2-2S + T2 := mulmod(T4, addmod(T3, sub(p, X), p), p) //M(S-X3) + + Y := addmod(T2, mulmod(T1, Y, p), p) //Y3= M(S-X3)-W*Y1 + + continue + } + } + + let T4 := mulmod(T2, T2, p) + let T1 := mulmod(T4, T2, p) // + zz := mulmod(zz, T4, p) + //zzz3=V*ZZ1 + zzz := mulmod(zzz, T1, p) // W=UV/ + let zz1 := mulmod(X, T4, p) + X := + addmod(addmod(mulmod(y2, y2, p), sub(p, T1), p), mulmod(minus_2, zz1, p), p) + Y := addmod(mulmod(addmod(zz1, sub(p, X), p), y2, p), mulmod(Y, T1, p), p) + } + } //end loop + mstore(add(T, 0x60), zz) + + //(X,Y)=ecZZ_SetAff(X,Y,zz, zzz); + //T[0] = inverseModp_Hard(T[0], p); //1/zzz, inline modular inversion using + // precompile: + // Define length of base, exponent and modulus. 0x20 == 32 bytes + mstore(T, 0x20) + mstore(add(T, 0x20), 0x20) + mstore(add(T, 0x40), 0x20) + // Define variables base, exponent and modulus + //mstore(add(pointer, 0x60), u) + mstore(add(T, 0x80), minus_2) + mstore(add(T, 0xa0), p) + + // Call the precompiled contract 0x05 = ModExp + if iszero(call(not(0), 0x05, 0, T, 0xc0, T, 0x20)) { revert(0, 0) } + + zz := mload(T) + X := mulmod(X, zz, p) //X/zz + } + } //end unchecked + } + + // improving the extcodecopy trick : append array at end of contract + function ecZZ_mulmuladd_S8_hackmem_back( + uint256 scalar_u, + uint256 scalar_v, + uint256 dataPointer + ) + internal + returns (uint256 X /*, uint Y*/ ) + { + uint256 zz; // third and coordinates of the point + + uint256[6] memory T; + zz = 256; //start index + + unchecked { + while (T[0] == 0) { + zz = zz - 1; + //tbd case of msb octobit is null + T[0] = 64 + * ( + 128 * ((scalar_v >> zz) & 1) + 64 * ((scalar_v >> (zz - 64)) & 1) + + 32 * ((scalar_v >> (zz - 128)) & 1) + 16 * ((scalar_v >> (zz - 192)) & 1) + + 8 * ((scalar_u >> zz) & 1) + 4 * ((scalar_u >> (zz - 64)) & 1) + + 2 * ((scalar_u >> (zz - 128)) & 1) + ((scalar_u >> (zz - 192)) & 1) + ); + } + assembly { + codecopy(T, add(mload(T), dataPointer), 64) + X := mload(T) + let Y := mload(add(T, 32)) + let zzz := 1 + zz := 1 + + //loop over 1/4 of scalars thx to Shamir's trick over 8 points + for { let index := 254 } gt(index, 191) { index := add(index, 191) } { + let T1 := mulmod(2, Y, p) //U = 2*Y1, y free + let T2 := mulmod(T1, T1, p) // V=U^2 + let T3 := mulmod(X, T2, p) // S = X1*V + T1 := mulmod(T1, T2, p) // W=UV + let T4 := mulmod(3, mulmod(addmod(X, sub(p, zz), p), addmod(X, zz, p), p), p) //M=3*(X1-ZZ1)*(X1+ZZ1) + zzz := mulmod(T1, zzz, p) //zzz3=W*zzz1 + zz := mulmod(T2, zz, p) //zz3=V*ZZ1, V free + + X := addmod(mulmod(T4, T4, p), mulmod(minus_2, T3, p), p) //X3=M^2-2S + //T2:=mulmod(T4,addmod(T3, sub(p, X),p),p)//M(S-X3) + T2 := mulmod(T4, addmod(X, sub(p, T3), p), p) //-M(S-X3)=M(X3-S) + + //Y:= addmod(T2, sub(p, mulmod(T1, Y ,p)),p )//Y3= M(S-X3)-W*Y1 + Y := addmod(mulmod(T1, Y, p), T2, p) //-Y3= W*Y1-M(S-X3), we replace Y by -Y to + // avoid a sub in ecAdd + + /* compute element to access in precomputed table */ + + T4 := + add(shl(13, and(shr(index, scalar_v), 1)), shl(9, and(shr(index, scalar_u), 1))) + index := sub(index, 64) + T4 := + add( + T4, + add( + shl(12, and(shr(index, scalar_v), 1)), + shl(8, and(shr(index, scalar_u), 1)) + ) + ) + index := sub(index, 64) + T4 := + add( + T4, + add( + shl(11, and(shr(index, scalar_v), 1)), + shl(7, and(shr(index, scalar_u), 1)) + ) + ) + index := sub(index, 64) + T4 := + add( + T4, + add( + shl(10, and(shr(index, scalar_v), 1)), + shl(6, and(shr(index, scalar_u), 1)) + ) + ) + //index:=add(index,192), restore index, interleaved with loop + + //tbd: check validity of formulae with (0,1) to remove conditional jump + if iszero(T4) { + Y := sub(p, Y) + + continue + } + { + /* Access to precomputed table using codecopy hack */ + codecopy(T, add(T4, dataPointer), 64) + + // inlined EcZZ_AddN + + let y2 := addmod(mulmod(mload(add(T, 32)), zzz, p), Y, p) + T2 := addmod(mulmod(mload(T), zz, p), sub(p, X), p) + T4 := mulmod(T2, T2, p) + T1 := mulmod(T4, T2, p) + T2 := mulmod(zz, T4, p) // W=UV + zzz := mulmod(zzz, T1, p) //zz3=V*ZZ1 + let zz1 := mulmod(X, T4, p) + T4 := + addmod(addmod(mulmod(y2, y2, p), sub(p, T1), p), mulmod(minus_2, zz1, p), p) + Y := addmod(mulmod(addmod(zz1, sub(p, T4), p), y2, p), mulmod(Y, T1, p), p) + zz := T2 + X := T4 + } + } //end loop + mstore(add(T, 0x60), zz) + + //(X,Y)=ecZZ_SetAff(X,Y,zz, zzz); + //T[0] = inverseModp_Hard(T[0], p); //1/zzz, inline modular inversion using + // precompile: + // Define length of base, exponent and modulus. 0x20 == 32 bytes + mstore(T, 0x20) + mstore(add(T, 0x20), 0x20) + mstore(add(T, 0x40), 0x20) + // Define variables base, exponent and modulus + //mstore(add(pointer, 0x60), u) + mstore(add(T, 0x80), minus_2) + mstore(add(T, 0xa0), p) + + // Call the precompiled contract 0x05 = ModExp + if iszero(call(not(0), 0x05, 0, T, 0xc0, T, 0x20)) { revert(0, 0) } + + zz := mload(T) + X := mulmod(X, zz, p) //X/zz + } + } //end unchecked + } + + /** + * @dev ECDSA verification, given , signature, and public key. + */ + function ecdsa_verify( + bytes32 message, + uint256[2] calldata rs, + uint256[2] calldata Q + ) + internal + returns (bool) + { + if (rs[0] == 0 || rs[0] >= n || rs[1] == 0 || rs[1] >= n) { + return false; + } + + if (!ecAff_isOnCurve(Q[0], Q[1])) { + return false; + } + + uint256 sInv = FCL_nModInv(rs[1]); + + uint256 scalar_u = mulmod(uint256(message), sInv, n); + uint256 scalar_v = mulmod(rs[0], sInv, n); + uint256 x1; + + x1 = ecZZ_mulmuladd_S_asm(Q[0], Q[1], scalar_u, scalar_v); + assembly { + x1 := addmod(x1, sub(n, calldataload(rs)), n) + } + //return true; + return x1 == 0; + } + + /** + * @dev ECDSA verification, given , signature, and public key. + */ + function ecdsa_verify_mem( + bytes32 message, + uint256[2] memory rs, + uint256[2] memory Q + ) + internal + returns (bool) + { + if (rs[0] == 0 || rs[0] >= n || rs[1] == 0 || rs[1] >= n) { + return false; + } + + if (!ecAff_isOnCurve(Q[0], Q[1])) { + return false; + } + + uint256 sInv = FCL_nModInv(rs[1]); + + uint256 scalar_u = mulmod(uint256(message), sInv, n); + uint256 scalar_v = mulmod(rs[0], sInv, n); + uint256 x1; + + x1 = ecZZ_mulmuladd_S_asm(Q[0], Q[1], scalar_u, scalar_v); + + uint256 _rs0 = rs[0]; + assembly { + x1 := addmod(x1, sub(n, _rs0), n) + } + //return true; + return x1 == 0; + } + + /** + * @dev ECDSA verification using a precomputed table of multiples of P and Q stored in contract + * at address Shamir8 + * generation of contract bytecode for precomputations is done using sagemath code + * (see sage directory, WebAuthn_precompute.sage) + */ + function ecdsa_precomputed_verify( + bytes32 message, + uint256[2] calldata rs, + address Shamir8 + ) + internal + returns (bool) + { + if (rs[0] == 0 || rs[0] >= n || rs[1] == 0) { + return false; + } + /* Q is pushed via bytecode assumed to be correct + if (!isOnCurve(Q[0], Q[1])) { + return false; + }*/ + + uint256 sInv = FCL_nModInv(rs[1]); + //uint sInv =2; + + uint256 X; + + //Shamir 8 dimensions + X = ecZZ_mulmuladd_S8_extcode( + mulmod(uint256(message), sInv, n), mulmod(rs[0], sInv, n), Shamir8 + ); + + assembly { + X := addmod(X, sub(n, calldataload(rs)), n) + } + + return X == 0; + } //end ecdsa_precomputed_verify() + + /** + * @dev ECDSA verification using a precomputed table of multiples of P and Q appended at end of + * contract at address + * endcontract + * generation of contract bytecode for precomputations is done using sagemath code + * (see sage directory, WebAuthn_precompute.sage) + */ + function ecdsa_precomputed_hackmem( + bytes32 message, + uint256[2] calldata rs, + uint256 endcontract + ) + internal + returns (bool) + { + if (rs[0] == 0 || rs[0] >= n || rs[1] == 0) { + return false; + } + /* Q is pushed via bytecode assumed to be correct + if (!isOnCurve(Q[0], Q[1])) { + return false; + }*/ + + uint256 sInv = FCL_nModInv(rs[1]); + uint256 X; + + //Shamir 8 dimensions + X = ecZZ_mulmuladd_S8_hackmem( + mulmod(uint256(message), sInv, n), mulmod(rs[0], sInv, n), endcontract + ); + + assembly { + X := addmod(X, sub(n, calldataload(rs)), n) + } + return X == 0; + } //end ecdsa_precomputed_verify() +} //EOF +/* solhint-enable */ diff --git a/examples/src/WebauthnValidator/utils/WebAuthNLib.sol b/examples/src/WebauthnValidator/utils/WebAuthNLib.sol new file mode 100644 index 00000000..93201506 --- /dev/null +++ b/examples/src/WebauthnValidator/utils/WebAuthNLib.sol @@ -0,0 +1,187 @@ +/* solhint-disable */ +//********************************************************************************************/ +// ___ _ ___ _ _ _ _ +// | __| _ ___ __| |_ / __|_ _ _ _ _ __| |_ ___ | | (_) |__ +// | _| '_/ -_|_-< ' \ | (__| '_| || | '_ \ _/ _ \ | |__| | '_ \ +// |_||_| \___/__/_||_| \___|_| \_, | .__/\__\___/ |____|_|_.__/ +// |__/|_| +///* Copyright (C) 2022 - Renaud Dubois - This file is part of FCL (Fresh CryptoLib) project +///* License: This software is licensed under MIT License +///* This Code may be reused including license and copyright notice. +///* See LICENSE file at the root folder of the project. +///* FILE: FCL_elliptic.sol +///* +///* +///* DESCRIPTION: Implementation of the WebAuthn Authentication mechanism +///* https://www.w3.org/TR/webauthn-2/#sctn-intro +///* Original code extracted from https://github.com/btchip/Webauthn.sol +//**************************************************************************************/ +//* WARNING: this code SHALL not be used for non prime order curves for security reasons. +// Code is optimized for a=-3 only curves with prime order, constant like -1, -2 shall be replaced +// if ever used for other curve than sec256R1 +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import { Base64URL } from "./Base64URL.sol"; +import { EllipticCurveP256 } from "./EllipticCurve.sol"; + +library WebAuthnLib { + error InvalidAuthenticatorData(); + error InvalidClientData(); + error InvalidSignature(); + + function WebAuthn_format( + bytes memory authenticatorData, + bytes1 authenticatorDataFlagMask, + bytes memory clientData, + bytes32 clientChallenge, + uint256 clientChallengeDataOffset, + uint256[2] memory rs + ) + internal + view + returns (bytes32 result) + { + // Let the caller check if User Presence (0x01) or User Verification (0x04) are set + { + if ((authenticatorData[32] & authenticatorDataFlagMask) != authenticatorDataFlagMask) { + revert InvalidAuthenticatorData(); + } + // Verify that clientData commits to the expected client challenge + string memory challengeEncoded = Base64URL.encode32(abi.encodePacked(clientChallenge)); + + // previous implementation that used bytes calldata clientData + // bytes memory challengeExtracted = new bytes( + // bytes(challengeEncoded).length + // ); + + // // Extract challenge from clientData + // assembly { + // calldatacopy( + // add(challengeExtracted, 32), + // add(clientData.offset, clientChallengeDataOffset), + // mload(challengeExtracted) + // ) + // } + + // bytes32 more; //=keccak256(abi.encodePacked(challengeExtracted)); + // assembly { + // more := keccak256( + // add(challengeExtracted, 32), + // mload(challengeExtracted) + // ) + // } + + // TODO: extract challenge from clientData and compare to clientChallenge + bytes32 more = keccak256(abi.encodePacked(challengeEncoded)); + + if (keccak256(abi.encodePacked(bytes(challengeEncoded))) != more) { + revert InvalidClientData(); + } + } //avoid stack full + + // Verify the signature over sha256(authenticatorData || sha256(clientData)) + // bytes memory verifyData = new bytes(authenticatorData.length + 32); + + // // get authenticatorData + // assembly { + // mstore(add(verifyData, 32), authenticatorData) + // } + + bytes32 more = sha256(clientData); + // uint _authenticatorLength = authenticatorData.length; + // assembly { + // mstore(add(verifyData, add(_authenticatorLength, 32)), more) + // } + + bytes memory verifyData = abi.encodePacked(authenticatorData, more); + + return sha256(verifyData); + } + + function checkSignature( + bytes memory authenticatorData, + bytes1 authenticatorDataFlagMask, + bytes memory clientData, + bytes32 clientChallenge, + uint256 clientChallengeDataOffset, + uint256[2] memory rs, + uint256[2] memory Q + ) + internal + returns (bool) + { + // Let the caller check if User Presence (0x01) or User Verification (0x04) are set + + bytes32 message = WebAuthnLib.WebAuthn_format( + authenticatorData, + authenticatorDataFlagMask, + clientData, + clientChallenge, + clientChallengeDataOffset, + rs + ); + + bool result = EllipticCurveP256.ecdsa_verify_mem(message, rs, Q); + + return result; + } + + function checkSignature_prec( + bytes calldata authenticatorData, + bytes1 authenticatorDataFlagMask, + bytes calldata clientData, + bytes32 clientChallenge, + uint256 clientChallengeDataOffset, + uint256[2] calldata rs, + address dataPointer + ) + internal + returns (bool) + { + // Let the caller check if User Presence (0x01) or User Verification (0x04) are set + + bytes32 message = WebAuthnLib.WebAuthn_format( + authenticatorData, + authenticatorDataFlagMask, + clientData, + clientChallenge, + clientChallengeDataOffset, + rs + ); + + bool result = EllipticCurveP256.ecdsa_precomputed_verify(message, rs, dataPointer); + + return result; + } + + //beware that this implementation will not be compliant with EOF + function checkSignature_hackmem( + bytes calldata authenticatorData, + bytes1 authenticatorDataFlagMask, + bytes calldata clientData, + bytes32 clientChallenge, + uint256 clientChallengeDataOffset, + uint256[2] calldata rs, + uint256 dataPointer + ) + internal + returns (bool) + { + // Let the caller check if User Presence (0x01) or User Verification (0x04) are set + + bytes32 message = WebAuthnLib.WebAuthn_format( + authenticatorData, + authenticatorDataFlagMask, + clientData, + clientChallenge, + clientChallengeDataOffset, + rs + ); + + bool result = EllipticCurveP256.ecdsa_precomputed_hackmem(message, rs, dataPointer); + + return result; + } +} +/* solhint-enable */ diff --git a/examples/test/AutoSavings/AutoSavings.t.sol b/examples/test/AutoSavings/AutoSavings.t.sol new file mode 100644 index 00000000..0905bab6 --- /dev/null +++ b/examples/test/AutoSavings/AutoSavings.t.sol @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import "forge-std/Test.sol"; +import "@rhinestone/modulekit/src/ModuleKit.sol"; +import "@rhinestone/modulekit/src/Helpers.sol"; +import "@rhinestone/modulekit/src/Core.sol"; +import "solmate/test/utils/mocks/MockERC20.sol"; +import "solmate/test/utils/mocks/MockERC4626.sol"; +import { AutoSavingToVault } from "src/AutoSavings/AutoSavings.sol"; + +import { MODULE_TYPE_EXECUTOR } from "@rhinestone/modulekit/src/external/ERC7579.sol"; + +contract AutoSavingsTest is RhinestoneModuleKit, Test { + using ModuleKitHelpers for *; + using ModuleKitSCM for *; + using ModuleKitUserOp for *; + + AccountInstance internal instance; + AutoSavingToVault internal autosavings; + + MockERC20 internal tokenIn; + MockERC20 internal tokenOut; + MockERC4626 internal vault1; + MockERC4626 internal vault2; + + bytes internal sessionKeyData; + + Account internal signer = makeAccount("signer"); + + bytes32 internal sessionKeyDigest; + + function setUp() public { + instance = makeAccountInstance("instance"); + vm.warp(17_999_999); + + autosavings = new AutoSavingToVault(); + tokenIn = new MockERC20("USDC", "USDC", 18); + vm.label(address(tokenIn), "USDC"); + tokenIn.mint(instance.account, 1_000_000); + tokenOut = new MockERC20("wETH", "wETH", 18); + vm.label(address(tokenIn), "wETH"); + tokenOut.mint(instance.account, 1_000_000); + + vault1 = new MockERC4626(tokenIn, "vUSDC", "vUSDC"); + vault2 = new MockERC4626(tokenOut, "vwETH", "vwETH"); + + sessionKeyData = abi.encode( + AutoSavingToVault.ScopedAccess({ + sessionKeySigner: signer.addr, + onlyToken: address(tokenIn), + maxAmount: 10_000 ** 18 + }) + ); + + (, sessionKeyDigest) = instance.installSessionKey({ + sessionKeyModule: address(autosavings), + validUntil: uint48(block.timestamp + 7 days), + validAfter: uint48(block.timestamp - 7 days), + sessionKeyData: sessionKeyData, + txValidator: address(instance.defaultValidator) + }); + + AutoSavingToVault.Config memory savingForToken = AutoSavingToVault.Config({ + percentage: 100, // 100 = 1% + vault: address(vault2), + sqrtPriceLimitX96: 0 + }); + instance.installModule({ + moduleTypeId: MODULE_TYPE_EXECUTOR, + module: address(autosavings), + data: "" + }); + vm.prank(instance.account); + autosavings.setConfig({ token: address(tokenIn), config: savingForToken }); + } + + modifier whenModuleIsCalled() { + _; + } + + function test_WhenSignerIsInvalid() external whenModuleIsCalled { + // It should not validate + // It should execute deposit + } + + function test_WhenSignerIsValid() external whenModuleIsCalled { + // It should deposit + AutoSavingToVault.Params memory params = + AutoSavingToVault.Params({ token: address(tokenIn), amountReceived: 100 }); + instance.getExecOps({ + target: address(autosavings), + value: 0, + callData: abi.encodeCall(AutoSavingToVault.autoSave, (params)), + sessionKeyDigest: sessionKeyDigest, + sessionKeySignature: ecdsaSign(signer.key, sessionKeyDigest), + txValidator: address(instance.defaultValidator) + }).execUserOps(); + // It should deposit correct percentage + // It should update spending limit + } + + function test_WhenDepositAmountLargerThanMax() external whenModuleIsCalled { + // It should revert + } +} diff --git a/examples/test/AutoSavings/AutoSavings.tree b/examples/test/AutoSavings/AutoSavings.tree new file mode 100644 index 00000000..5473898b --- /dev/null +++ b/examples/test/AutoSavings/AutoSavings.tree @@ -0,0 +1,11 @@ +AutoSavingsTest +└─ When Module is Called + ├─ When signer is invalid + │ ├─ It should successfully validate + │ └─ It should execute deposit + ├─ When signer is valid + │ ├─ It should deposit + │ ├─ It should deposit correct percentage + │ └─ It should update spending limit + └─ When deposit amount larger than max + └─ It should revert diff --git a/examples/test/AutoSend/AutoSend.t.sol b/examples/test/AutoSend/AutoSend.t.sol new file mode 100644 index 00000000..f8e29840 --- /dev/null +++ b/examples/test/AutoSend/AutoSend.t.sol @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import "forge-std/Test.sol"; +import "@rhinestone/modulekit/src/ModuleKit.sol"; +import "@rhinestone/modulekit/src/Modules.sol"; +import "@rhinestone/modulekit/src/Mocks.sol"; +import { AutoSendSessionKey } from "src/AutoSend/AutoSend.sol"; +import { SignatureCheckerLib } from "solady/src/utils/SignatureCheckerLib.sol"; +import { Solarray } from "solarray/Solarray.sol"; +import { MODULE_TYPE_EXECUTOR } from "@rhinestone/modulekit/src/external/ERC7579.sol"; + +contract AutoSendTest is RhinestoneModuleKit, Test { + using ModuleKitHelpers for *; + using ModuleKitUserOp for *; + using ModuleKitSCM for *; + + AccountInstance internal instance; + + AutoSendSessionKey internal sessionValidator; + bytes32 internal sessionValidatorDigest; + MockTarget internal target; + MockERC20 internal token; + + address internal recipient; + + address keySigner1; + uint256 keySignerPk1; + + function setUp() public { + instance = makeAccountInstance("1"); + vm.deal(instance.account, 1 ether); + + token = new MockERC20(); + token.initialize("Mock Token", "MTK", 18); + deal(address(token), instance.account, 100 ether); + + sessionValidator = new AutoSendSessionKey(); + target = new MockTarget(); + recipient = makeAddr("recipient"); + + (keySigner1, keySignerPk1) = makeAddrAndKey("KeySigner1"); + + AutoSendSessionKey.ExecutorAccess memory _tx1 = AutoSendSessionKey.ExecutorAccess({ + sessionKeySigner: keySigner1, + token: address(token), + receiver: recipient + }); + + (, sessionValidatorDigest) = instance.installSessionKey({ + sessionKeyModule: (address(sessionValidator)), + validUntil: type(uint48).max, + validAfter: 0, + sessionKeyData: sessionValidator.encode(_tx1), + txValidator: address(instance.defaultValidator) + }); + + // params for executor install + address[] memory tokens = Solarray.addresses(address(token)); + AutoSendSessionKey.SpentLog[] memory logs = new AutoSendSessionKey.SpentLog[](1); + logs[0] = AutoSendSessionKey.SpentLog({ spent: 0, maxAmount: 100 }); + + instance.installModule({ + moduleTypeId: MODULE_TYPE_EXECUTOR, + module: address(sessionValidator), + data: abi.encode(tokens, logs) + }); + } + + function test_transferBatch() public { + AutoSendSessionKey.Params memory params = + AutoSendSessionKey.Params({ token: address(token), receiver: recipient, amount: 33 }); + + address[] memory targets = + Solarray.addresses(address(sessionValidator), address(sessionValidator)); + uint256[] memory values = Solarray.uint256s(uint256(0), uint256(0)); + bytes[] memory calldatas = Solarray.bytess( + abi.encodeCall(AutoSendSessionKey.autoSend, (params)), + abi.encodeCall(AutoSendSessionKey.autoSend, (params)) + ); + + bytes32[] memory sessionKeyDigests = + Solarray.bytes32s(sessionValidatorDigest, sessionValidatorDigest); + + bytes[] memory sessionKeySignatures = Solarray.bytess( + sign(keySignerPk1, sessionValidatorDigest), sign(keySignerPk1, sessionValidatorDigest) + ); + instance.getExecOps({ + targets: targets, + values: values, + callDatas: calldatas, + sessionKeyDigests: sessionKeyDigests, + sessionKeySignatures: sessionKeySignatures, + txValidator: address(instance.defaultValidator) + }).execUserOps(); + + assertEq(token.balanceOf(recipient), 66); + + AutoSendSessionKey.SpentLog memory log = + sessionValidator.getSpentLog(instance.account, address(token)); + + assertEq(log.spent, 66); + assertEq(log.maxAmount, 100); + } + + function sign(uint256 privKey, bytes32 digest) internal returns (bytes memory) { + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privKey, digest); + return abi.encodePacked(r, s, v); + } + + function test_transferSingle() public { + AutoSendSessionKey.Params memory params = + AutoSendSessionKey.Params({ token: address(token), receiver: recipient, amount: 33 }); + bytes memory sig = sign(keySignerPk1, sessionValidatorDigest); + + bool isValid = + SignatureCheckerLib.isValidSignatureNow(keySigner1, sessionValidatorDigest, sig); + + assertTrue(isValid); + instance.getExecOps({ + target: address(sessionValidator), + value: 0, + callData: abi.encodeCall(AutoSendSessionKey.autoSend, (params)), + sessionKeyDigest: sessionValidatorDigest, + sessionKeySignature: sig, + txValidator: address(instance.defaultValidator) + }).execUserOps(); + + assertEq(token.balanceOf(recipient), 33); + } +} diff --git a/examples/test/DeadmanSwitch/DeadmanSwitch.t.sol b/examples/test/DeadmanSwitch/DeadmanSwitch.t.sol new file mode 100644 index 00000000..3d12fb4b --- /dev/null +++ b/examples/test/DeadmanSwitch/DeadmanSwitch.t.sol @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.21; + +import "forge-std/Test.sol"; +import "@rhinestone/modulekit/src/ModuleKit.sol"; +import "@rhinestone/modulekit/src/Helpers.sol"; +import "@rhinestone/modulekit/src/Core.sol"; +import "solmate/test/utils/mocks/MockERC20.sol"; +import { + MODULE_TYPE_VALIDATOR, MODULE_TYPE_HOOK +} from "@rhinestone/modulekit/src/external/ERC7579.sol"; + +import "src/DeadmanSwitch/DeadmanSwitch.sol"; +import "forge-std/interfaces/IERC20.sol"; +import { ECDSA } from "solady/src/utils/ECDSA.sol"; + +contract DeadmanSwitchTest is RhinestoneModuleKit, Test { + using ModuleKitHelpers for *; + using ModuleKitUserOp for *; + + AccountInstance internal instance; + DeadmanSwitch internal dms; + + Account internal nominee; + MockERC20 internal token; + uint48 timeout; + + function setUp() public { + vm.warp(100); + + instance = makeAccountInstance("Deadman"); + nominee = makeAccount("Nominee"); + token = new MockERC20("USDC", "USDC", 18); + vm.label(address(token), "USDC"); + token.mint(instance.account, 1_000_000); + + dms = new DeadmanSwitch(); + + timeout = uint48(block.timestamp + 128 days); + bytes memory initData = abi.encode(nominee.addr, timeout); + instance.installModule({ + moduleTypeId: MODULE_TYPE_VALIDATOR, + module: address(dms), + data: initData + }); + instance.installModule({ moduleTypeId: MODULE_TYPE_HOOK, module: address(dms), data: "" }); + } + + function test_ShouldNeverRevertHook() external { + // It should never revert Hook + + instance.exec({ + target: address(token), + value: 0, + callData: abi.encodeCall(IERC20.transfer, (makeAddr("somebody"), 1000)) + }); + + vm.warp(timeout + 1 days); + + instance.exec({ + target: address(token), + value: 0, + callData: abi.encodeCall(IERC20.transfer, (makeAddr("somebody"), 1000)) + }); + + assertEq(token.balanceOf(instance.account), 998_000); + assertEq(token.balanceOf(makeAddr("somebody")), 2000); + } + + function test_WhenAccountIsUsed() public { + // It should set lastAccess + vm.warp(block.timestamp + 1 days); + uint256 lastAccess = block.timestamp; + + // It should never revert Hook + + instance.exec({ + target: address(token), + value: 0, + callData: abi.encodeCall(IERC20.transfer, (makeAddr("somebody"), 1000)) + }); + + assertEq(dms.lastAccess(instance.account), lastAccess); + } + + function signHash(uint256 privKey, bytes32 digest) internal returns (bytes memory) { + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privKey, ECDSA.toEthSignedMessageHash(digest)); + return abi.encodePacked(r, s, v); + } + + function test_WhenValidatorIsUsedAndTimeoutNotReached() external { + test_WhenAccountIsUsed(); + + uint256 balanceOfAccount = token.balanceOf(instance.account); + UserOpData memory userOpData = instance.getExecOps({ + target: address(token), + value: 0, + callData: abi.encodeCall(IERC20.transfer, (nominee.addr, balanceOfAccount)), + txValidator: address(dms) + }); + userOpData.userOp.signature = signHash(nominee.key, userOpData.userOpHash); + address recover = ECDSA.recover( + ECDSA.toEthSignedMessageHash(userOpData.userOpHash), userOpData.userOp.signature + ); + assertEq(recover, nominee.addr); + vm.expectRevert(); + userOpData.execUserOps(); + + // balance should not be changed + assertEq(token.balanceOf(instance.account), balanceOfAccount); + } + + function test_WhenValidatorIsUsedAndTimeoutIsReached() external { + test_WhenAccountIsUsed(); + + vm.warp(timeout + 2 days); + + uint256 balanceOfAccount = token.balanceOf(instance.account); + + UserOpData memory userOpData = instance.getExecOps({ + target: address(token), + value: 0, + callData: abi.encodeCall(IERC20.transfer, (nominee.addr, balanceOfAccount)), + txValidator: address(dms) + }); + userOpData.userOp.signature = signHash(nominee.key, userOpData.userOpHash); + address recover = ECDSA.recover( + ECDSA.toEthSignedMessageHash(userOpData.userOpHash), userOpData.userOp.signature + ); + assertEq(recover, nominee.addr); + userOpData.execUserOps(); + + // balance should not be changed + assertEq(token.balanceOf(instance.account), 0); + assertEq(token.balanceOf(nominee.addr), balanceOfAccount); + } +} diff --git a/examples/test/DeadmanSwitch/DeadmanSwitch.tree b/examples/test/DeadmanSwitch/DeadmanSwitch.tree new file mode 100644 index 00000000..198cf761 --- /dev/null +++ b/examples/test/DeadmanSwitch/DeadmanSwitch.tree @@ -0,0 +1,8 @@ +DeadmanSwitchTest +├─ It should never revert Hook +├─ When account is used +│ └─ It should set lastAccess +├─ When validator is used and timeout not reached +│ └─ It should revert +└─ When validator is used and timeout is reached + └─ It should allow nominee to execute diff --git a/examples/test/MultiFactor/MultiFactor.t.sol b/examples/test/MultiFactor/MultiFactor.t.sol new file mode 100644 index 00000000..c18b3b17 --- /dev/null +++ b/examples/test/MultiFactor/MultiFactor.t.sol @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import "forge-std/Test.sol"; +import "@rhinestone/modulekit/src/ModuleKit.sol"; +import "@rhinestone/modulekit/src/Modules.sol"; +import "@rhinestone/modulekit/src/Mocks.sol"; + +import { MultiFactor, ECDSAFactor } from "src/MultiFactor/MultiFactor.sol"; +import { SignatureCheckerLib } from "solady/src/utils/SignatureCheckerLib.sol"; +import { ECDSA } from "solady/src/utils/ECDSA.sol"; +import { Solarray } from "solarray/Solarray.sol"; + +import { + MODULE_TYPE_VALIDATOR, + MODULE_TYPE_EXECUTOR +} from "@rhinestone/modulekit/src/external/ERC7579.sol"; + +contract DemoValidator is MockValidator { + mapping(address account => bool isInitialized) public initialized; + + error AlreadyInstalled(); + + function onInstall(bytes calldata data) external override { + if (data.length == 0) revert("empty data"); + // TODO: + // if (initialized[msg.sender]) revert AlreadyInstalled(); + initialized[msg.sender] = true; + } + + function onUninstall(bytes calldata data) external override { + if (data.length == 0) revert("empty data"); + initialized[msg.sender] = false; + } +} + +contract MultiFactorTest is RhinestoneModuleKit, Test { + using ModuleKitHelpers for *; + using ModuleKitUserOp for *; + using ModuleKitSCM for *; + + AccountInstance internal instance; + + MockTarget internal target; + MockERC20 internal token; + + DemoValidator internal validator1; + DemoValidator internal validator2; + + Account internal signer; + + MultiFactor internal mfa; + + address internal recipient; + + function setUp() public { + instance = makeAccountInstance("1"); + vm.deal(instance.account, 1 ether); + + signer = makeAccount("signer"); + + mfa = new MultiFactor(); + + validator1 = new DemoValidator(); + validator2 = new DemoValidator(); + + token = new MockERC20(); + token.initialize("Mock Token", "MTK", 18); + deal(address(token), instance.account, 100 ether); + } + + modifier initMFA() { + initAccount(); + _; + } + + function initAccount() internal { + instance.installModule({ + moduleTypeId: MODULE_TYPE_VALIDATOR, + module: address(mfa), + data: "" + }); + instance.installModule({ moduleTypeId: MODULE_TYPE_EXECUTOR, module: address(mfa), data: "" }); + configMFA(); + } + + function configMFA() public { + address[] memory validators = Solarray.addresses(address(validator1), address(validator2)); + bytes[] memory initDatas = Solarray.bytess(abi.encode(true), abi.encode(true)); + bytes[] memory deInitDatas = Solarray.bytess("", ""); + vm.prank(instance.account); + mfa.setConfig(validators, deInitDatas, initDatas, 2); + + assertTrue(validator1.initialized(instance.account)); + assertTrue(validator2.initialized(instance.account)); + } + + function test_Transaction() public initMFA { + // prepare signature + uint256[] memory validatorIds = Solarray.uint256s(0, 1); + bytes[] memory signatures = Solarray.bytess("", ""); + + bytes memory signature = abi.encode(validatorIds, signatures); + + // prepare userOp + UserOpData memory userOpData = instance.getExecOps({ + target: address(token), + value: 0, + callData: abi.encodeWithSelector(MockERC20.transfer.selector, recipient, 10 ether), + txValidator: address(mfa) + }); + + userOpData.userOp.signature = signature; + + userOpData.execUserOps(); + + assertEq(token.balanceOf(recipient), 10 ether); + } + + function init_localECDSA() public { + instance.installModule({ + moduleTypeId: MODULE_TYPE_VALIDATOR, + module: address(mfa), + data: "" + }); + instance.installModule({ moduleTypeId: MODULE_TYPE_EXECUTOR, module: address(mfa), data: "" }); + address[] memory validators = Solarray.addresses(address(mfa), address(validator2)); + ECDSAFactor.FactorConfig memory conf = ECDSAFactor.FactorConfig({ + signer: signer.addr, + validAfter: 0, + validBefore: type(uint48).max + }); + bytes[] memory initDatas = Solarray.bytess(abi.encode(conf), abi.encode(true)); + bytes[] memory deInitDatas = Solarray.bytess("", ""); + vm.prank(instance.account); + mfa.setConfig(validators, deInitDatas, initDatas, 2); + } + + function signHash(uint256 privKey, bytes32 digest) internal returns (bytes memory) { + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privKey, ECDSA.toEthSignedMessageHash(digest)); + return abi.encodePacked(r, s, v); + } + + function test_withLocalEC() public { + init_localECDSA(); + // prepare signature + uint256[] memory validatorIds = Solarray.uint256s(0, 1); + + // prepare userOp + UserOpData memory userOpData = instance.getExecOps({ + target: address(token), + value: 0, + callData: abi.encodeWithSelector(MockERC20.transfer.selector, recipient, 10 ether), + txValidator: address(mfa) + }); + bytes[] memory signatures = Solarray.bytess(signHash(signer.key, userOpData.userOpHash), ""); + + bytes memory signature = abi.encode(validatorIds, signatures); + + userOpData.userOp.signature = signature; + + userOpData.execUserOps(); + + assertEq(token.balanceOf(recipient), 10 ether); + } +} diff --git a/examples/test/TokenRevocation/ERC20Revocation.t.sol b/examples/test/TokenRevocation/ERC20Revocation.t.sol new file mode 100644 index 00000000..c69fc713 --- /dev/null +++ b/examples/test/TokenRevocation/ERC20Revocation.t.sol @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import "forge-std/Test.sol"; +import "@rhinestone/modulekit/src/ModuleKit.sol"; +import "@rhinestone/modulekit/src/Modules.sol"; +import "@rhinestone/modulekit/src/Mocks.sol"; +import { ERC20Revocation } from "src/TokenRevocation/ERC20Revocation.sol"; +import { SignatureCheckerLib } from "solady/src/utils/SignatureCheckerLib.sol"; +import { Solarray } from "solarray/Solarray.sol"; + +contract ERC20RevocationTest is RhinestoneModuleKit, Test { + using ModuleKitHelpers for *; + using ModuleKitUserOp for *; + using ModuleKitSCM for *; + + AccountInstance internal instance; + + ERC20Revocation internal sessionValidator; + bytes32 internal sessionValidatorDigest; + MockTarget internal target; + MockERC20 internal token; + + address internal recipient; + + address keySigner1; + uint256 keySignerPk1; + + function setUp() public { + instance = makeAccountInstance("1"); + vm.deal(instance.account, 1 ether); + + token = new MockERC20(); + token.initialize("Mock Token", "MTK", 18); + deal(address(token), instance.account, 100 ether); + + sessionValidator = new ERC20Revocation(); + target = new MockTarget(); + recipient = makeAddr("recipient"); + + (keySigner1, keySignerPk1) = makeAddrAndKey("KeySigner1"); + + ERC20Revocation.Token memory _tx1 = ERC20Revocation.Token({ + token: address(token), + tokenType: ERC20Revocation.TokenType.ERC20, + sessionKeySigner: keySigner1 + }); + UserOpData memory userOpData; + (userOpData, sessionValidatorDigest) = instance.installSessionKey({ + sessionKeyModule: (address(sessionValidator)), + validUntil: type(uint48).max, + validAfter: 0, + sessionKeyData: sessionValidator.encode(_tx1), + txValidator: address(instance.defaultValidator) + }); + + userOpData.execUserOps(); + + vm.prank(instance.account); + token.approve(recipient, 100); + } + + function test_transferBatch() public { + assertEq(token.allowance(instance.account, recipient), 100); + address[] memory targets = Solarray.addresses(address(token), address(token)); + uint256[] memory values = Solarray.uint256s(uint256(0), uint256(0)); + bytes[] memory calldatas = Solarray.bytess( + abi.encodeCall(MockERC20.approve, (recipient, 0)), + abi.encodeCall(MockERC20.approve, (makeAddr("foo"), 0)) + ); + + bytes32[] memory sessionKeyDigests = + Solarray.bytes32s(sessionValidatorDigest, sessionValidatorDigest); + + bytes[] memory sessionKeySignatures = Solarray.bytess( + sign(keySignerPk1, sessionValidatorDigest), sign(keySignerPk1, sessionValidatorDigest) + ); + instance.getExecOps({ + targets: targets, + values: values, + callDatas: calldatas, + sessionKeyDigests: sessionKeyDigests, + sessionKeySignatures: sessionKeySignatures, + txValidator: address(instance.defaultValidator) + }).execUserOps(); + + assertEq(token.allowance(instance.account, recipient), 0); + } + + function sign(uint256 privKey, bytes32 digest) internal returns (bytes memory) { + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privKey, digest); + return abi.encodePacked(r, s, v); + } + + function test_transferSingle() public { + assertEq(token.allowance(instance.account, recipient), 100); + bytes memory sig = sign(keySignerPk1, sessionValidatorDigest); + + bool isValid = + SignatureCheckerLib.isValidSignatureNow(keySigner1, sessionValidatorDigest, sig); + + assertTrue(isValid); + instance.getExecOps({ + target: address(token), + value: 0, + callData: abi.encodeCall(MockERC20.approve, (recipient, 0)), + sessionKeyDigest: sessionValidatorDigest, + sessionKeySignature: sig, + txValidator: address(instance.defaultValidator) + }).execUserOps(); + + assertEq(token.allowance(instance.account, recipient), 0); + } +} diff --git a/examples/test/coldstorage/ColdStorage.t.sol b/examples/test/coldstorage/ColdStorage.t.sol new file mode 100644 index 00000000..457daa7f --- /dev/null +++ b/examples/test/coldstorage/ColdStorage.t.sol @@ -0,0 +1,313 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import "forge-std/Test.sol"; +import "@rhinestone/modulekit/src/ModuleKit.sol"; +import "@rhinestone/modulekit/src/Modules.sol"; +import "@rhinestone/modulekit/src/Helpers.sol"; +import "@rhinestone/modulekit/src/core/ExtensibleFallbackHandler.sol"; +import "@rhinestone/sessionkeymanager/src/ISessionValidationModule.sol"; +import { + SessionData, + SessionKeyManagerLib +} from "@rhinestone/sessionkeymanager/src/SessionKeyManagerLib.sol"; +import "@rhinestone/modulekit/src/Mocks.sol"; +import { Solarray } from "solarray/Solarray.sol"; +import { ECDSA } from "solady/src/utils/ECDSA.sol"; + +import { IERC7579Account, Execution } from "@rhinestone/modulekit/src/Accounts.sol"; +import { FlashloanCallback } from "src/ColdStorage/FlashloanCallback.sol"; +import { FlashloanLender } from "src/ColdStorage/FlashloanLender.sol"; +import { ColdStorageHook } from "src/ColdStorage/ColdStorageHook.sol"; +import { ColdStorageExecutor } from "src/ColdStorage/ColdStorageExecutor.sol"; +import { OwnableValidator } from "src/OwnableValidator/OwnableValidator.sol"; + +import { ERC7579BootstrapConfig } from "@rhinestone/modulekit/src/external/ERC7579.sol"; + +import "src/ColdStorage/interfaces/Flashloan.sol"; +import "erc7579/lib/ExecutionLib.sol"; + +contract ColdStorageTest is RhinestoneModuleKit, Test { + using ModuleKitHelpers for *; + using ModuleKitUserOp for *; + using ECDSA for bytes32; + + MockERC20 internal token; + + // main account and dependencies + AccountInstance internal mainAccount; + FlashloanCallback internal flashloanCallback; + + // ColdStorage Account and dependencies + AccountInstance internal coldStorage; + FlashloanLender internal flashloanLender; + ColdStorageHook internal coldStorageHook; + ColdStorageExecutor internal coldStorageExecutor; + OwnableValidator internal ownableValidator; + + MockValidator internal mockValidator; + + Account owner; + + function setUp() public { + init(); + + flashloanLender = new FlashloanLender(address(coldStorage.aux.fallbackHandler)); + vm.label(address(flashloanLender), "flashloanLender"); + flashloanCallback = new FlashloanCallback(address(mainAccount.aux.fallbackHandler)); + vm.label(address(flashloanCallback), "flashloanCallback"); + ownableValidator = new OwnableValidator(); + vm.label(address(ownableValidator), "ownableValidator"); + mockValidator = new MockValidator(); + vm.label(address(mockValidator), "mockValidator"); + + coldStorageHook = new ColdStorageHook(); + vm.label(address(coldStorageHook), "coldStorageHook"); + + coldStorageExecutor = new ColdStorageExecutor(); + vm.label(address(coldStorageExecutor), "coldStorageExecutor"); + + owner = makeAccount("owner"); + _setupMainAccount(); + _setUpColdstorage(); + + deal(address(coldStorage.account), 100 ether); + deal(address(mainAccount.account), 100 ether); + + token = new MockERC20(); + token.initialize("Mock Token", "MTK", 18); + deal(address(token), mainAccount.account, 100 ether); + + vm.warp(1_799_999); + + mainAccount.exec({ + target: address(token), + value: 0, + callData: abi.encodeCall(IERC20.transfer, (address(coldStorage.account), 1 ether)) + }); + } + + function _setupMainAccount() public { + ExtensibleFallbackHandler.Params[] memory params = new ExtensibleFallbackHandler.Params[](1); + params[0] = ExtensibleFallbackHandler.Params({ + selector: IERC3156FlashBorrower.onFlashLoan.selector, + fallbackType: ExtensibleFallbackHandler.FallBackType.Dynamic, + handler: address(flashloanCallback) + }); + + ERC7579BootstrapConfig[] memory validators = + makeBootstrapConfig(address(ownableValidator), abi.encode(owner.addr)); + ERC7579BootstrapConfig[] memory executors = + makeBootstrapConfig(address(flashloanCallback), abi.encode("")); + ERC7579BootstrapConfig memory hook = _emptyConfig(); + ERC7579BootstrapConfig memory fallBack = + _makeBootstrapConfig(address(auxiliary.fallbackHandler), abi.encode(params)); + mainAccount = makeAccountInstance("mainAccount", validators, executors, hook, fallBack); + } + + function _setUpColdstorage() public { + ExtensibleFallbackHandler.Params[] memory params = new ExtensibleFallbackHandler.Params[](6); + params[0] = ExtensibleFallbackHandler.Params({ + selector: IERC3156FlashLender.maxFlashLoan.selector, + fallbackType: ExtensibleFallbackHandler.FallBackType.Static, + handler: address(flashloanLender) + }); + params[1] = ExtensibleFallbackHandler.Params({ + selector: IERC3156FlashLender.flashFee.selector, + fallbackType: ExtensibleFallbackHandler.FallBackType.Static, + handler: address(flashloanLender) + }); + params[2] = ExtensibleFallbackHandler.Params({ + selector: IERC3156FlashLender.flashLoan.selector, + fallbackType: ExtensibleFallbackHandler.FallBackType.Dynamic, + handler: address(flashloanLender) + }); + params[3] = ExtensibleFallbackHandler.Params({ + selector: IERC6682.flashFeeToken.selector, + fallbackType: ExtensibleFallbackHandler.FallBackType.Static, + handler: address(flashloanLender) + }); + params[4] = ExtensibleFallbackHandler.Params({ + selector: IERC6682.flashFee.selector, + fallbackType: ExtensibleFallbackHandler.FallBackType.Static, + handler: address(flashloanLender) + }); + params[5] = ExtensibleFallbackHandler.Params({ + selector: IERC6682.availableForFlashLoan.selector, + fallbackType: ExtensibleFallbackHandler.FallBackType.Static, + handler: address(flashloanLender) + }); + + ERC7579BootstrapConfig[] memory validators = + makeBootstrapConfig(address(ownableValidator), abi.encode(address(mainAccount.account))); + + address[] memory addresses = new address[](2); + bytes[] memory callData = new bytes[](2); + + addresses[0] = address(flashloanLender); + addresses[1] = address(coldStorageExecutor); + + callData[0] = abi.encode(""); + callData[1] = abi.encodePacked(address(mainAccount.account)); + + ERC7579BootstrapConfig[] memory executors = makeBootstrapConfig(addresses, callData); + + ERC7579BootstrapConfig memory hook = _makeBootstrapConfig( + address(coldStorageHook), abi.encode(uint128(7 days), address(mainAccount.account)) + ); + ERC7579BootstrapConfig memory fallBack = + _makeBootstrapConfig(address(auxiliary.fallbackHandler), abi.encode(params)); + + coldStorage = makeAccountInstance("coldStorage", validators, executors, hook, fallBack); + } + + function simulateDeposit() internal { + vm.prank(mainAccount.account); + token.transfer(coldStorage.account, 1 ether); + } + + function signHash(uint256 privKey, bytes32 digest) internal returns (bytes memory) { + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privKey, ECDSA.toEthSignedMessageHash(digest)); + return abi.encodePacked(r, s, v); + } + + function _deploySubAccount() private { + // todo: replace with modulekit function to deploy account + // create and exec an empty user op to deploy the sub account + UserOpData memory userOpData = + coldStorage.getExecOps(address(0), 0, "", address(ownableValidator)); + + bytes memory signature = signHash(owner.key, userOpData.userOpHash); + signature = abi.encodePacked(address(ownableValidator), signature); + userOpData.userOp.signature = signature; + coldStorage.expect4337Revert(); + userOpData.execUserOps(); + } + + function _requestWithdraw(Execution memory exec, uint256 additionalDelay) internal { + bytes memory subAccountCallData = ExecutionLib.encodeSingle( + address(coldStorageHook), + 0, + abi.encodeWithSelector( + ColdStorageHook.requestTimelockedExecution.selector, exec, additionalDelay + ) + ); + + UserOpData memory userOpData = mainAccount.getExecOps({ + target: address(coldStorageExecutor), + value: 0, + callData: abi.encodeWithSelector( + ColdStorageExecutor.executeOnSubAccount.selector, + address(coldStorage.account), + subAccountCallData + ), + txValidator: address(ownableValidator) + }); + + bytes memory signature = signHash(owner.key, userOpData.userOpHash); + address recover = + ECDSA.recover(ECDSA.toEthSignedMessageHash(userOpData.userOpHash), signature); + assertEq(recover, owner.addr); + userOpData.userOp.signature = signature; + userOpData.execUserOps(); + } + + function _execWithdraw(Execution memory exec) internal { + bytes memory subAccountCallData = + ExecutionLib.encodeSingle(exec.target, exec.value, exec.callData); + + UserOpData memory userOpData = mainAccount.getExecOps({ + target: address(coldStorageExecutor), + value: 0, + callData: abi.encodeWithSelector( + ColdStorageExecutor.executeOnSubAccount.selector, + address(coldStorage.account), + subAccountCallData + ), + txValidator: address(ownableValidator) + }); + bytes memory signature = signHash(owner.key, userOpData.userOpHash); + userOpData.userOp.signature = signature; + userOpData.execUserOps(); + } + + function test_withdraw() public { + uint256 prevBalance = token.balanceOf(address(mainAccount.account)); + uint256 amountToWithdraw = 100; + + _deploySubAccount(); + + Execution memory action = Execution({ + target: address(token), + value: 0, + callData: abi.encodeWithSelector( + MockERC20.transfer.selector, address(mainAccount.account), amountToWithdraw + ) + }); + + _requestWithdraw(action, 0); + + coldStorageHook.setWaitPeriod(7 days); + + vm.warp(block.timestamp + 8 days); + _execWithdraw(action); + + uint256 newBalance = token.balanceOf(address(mainAccount.account)); + assertEq(newBalance, prevBalance + amountToWithdraw); + } + + function test_setWaitPeriod() public { + _deploySubAccount(); + + uint256 newWaitPeriod = 2 days; + + Execution memory action = Execution({ + target: address(coldStorageHook), + value: 0, + callData: abi.encodeWithSelector(ColdStorageHook.setWaitPeriod.selector, (newWaitPeriod)) + }); + + _requestWithdraw(action, 0); + (bytes32 hash, bytes32 entry) = + coldStorageHook.checkHash(address(mainAccount.account), action); + + vm.warp(block.timestamp + 8 days); + _execWithdraw(action); + + Execution memory newAction = Execution({ + target: address(token), + value: 0, + callData: abi.encodeWithSelector( + MockERC20.transfer.selector, address(mainAccount.account), 100 + ) + }); + + _requestWithdraw(newAction, 0); + + vm.warp(block.timestamp + newWaitPeriod); + _execWithdraw(newAction); + + uint256 updatedWaitPeriod = coldStorageHook.getLockTime(address(coldStorage.account)); + assertEq(updatedWaitPeriod, uint128(newWaitPeriod)); + } + + function test_withdraw__With__NativeToken() public { + address target = address(mainAccount.account); + uint256 prevBalance = target.balance; + uint256 amountToWithdraw = 1 ether; + + vm.deal(address(coldStorage.account), 10 ether); + _deploySubAccount(); + + Execution memory action = + Execution({ target: target, value: amountToWithdraw, callData: "" }); + + _requestWithdraw(action, 0); + + vm.warp(block.timestamp + 8 days); + _execWithdraw(action); + + uint256 newBalance = target.balance; + assertTrue(newBalance > prevBalance); + } +} diff --git a/gas_calculations/.gitkeep b/gas_calculations/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/package.json b/package.json index 6bffb54f..0455470a 100644 --- a/package.json +++ b/package.json @@ -10,23 +10,17 @@ "bugs": { "url": "https://github.com/rhinestonewtf/modulekit/issues" }, - "dependencies": { - "@openzeppelin/contracts": "5.0.1", - "@prb/math": "^4.0.2", - "erc4337-validation": "github:rhinestonewtf/erc4337-validation" - }, + "workspaces": [ + "packages/**", + "accounts/**", + "examples/" + ], + "dependencies": {}, "devDependencies": { - "@rhinestone/sessionkeymanager": "github:rhinestonewtf/sessionkeymanager", - "@safe-global/safe-contracts": "^1.4.1", - "account-abstraction": "github:kopy-kat/account-abstraction#develop", - "account-abstraction-v0.6": "github:eth-infinitism/account-abstraction#v0.6.0", - "ds-test": "github:dapphub/ds-test", - "erc7579": "github:erc7579/erc7579-implementation", - "forge-std": "github:foundry-rs/forge-std", + "@rhinestone/sessionkeymanager": "workspace:*", + "@rhinestone/safe7579": "workspace:*", + "@rhinestone/modulekit": "workspace:*", "prettier": "^2.8.8", - "sentinellist": "github:zeroknots/sentinellist", - "solady": "github:vectorized/solady", - "solarray": "github:sablier-labs/solarray", "solhint": "^4.1.1" }, "files": [ @@ -51,6 +45,8 @@ "repository": "github.com/rhinestonewtf/modulekit", "scripts": { "build": "forge build", + "fmt": "forge fmt", + "fmt:check": "forge fmt --check", "build:optimized": "FOUNDRY_PROFILE=optimized forge build", "build:smt": "FOUNDRY_PROFILE=smt forge build", "clean": "rm -rf artifacts broadcast cache docs out out-optimized out-svg", diff --git a/src/core/ConditionManager/ConditionManagerCalldata.sol b/packages/ConditionManager/ConditionManagerCalldata.sol similarity index 100% rename from src/core/ConditionManager/ConditionManagerCalldata.sol rename to packages/ConditionManager/ConditionManagerCalldata.sol diff --git a/src/core/ConditionManager/ConditionManagerL2.sol b/packages/ConditionManager/ConditionManagerL2.sol similarity index 100% rename from src/core/ConditionManager/ConditionManagerL2.sol rename to packages/ConditionManager/ConditionManagerL2.sol diff --git a/src/core/ConditionManager/ICondition.sol b/packages/ConditionManager/ICondition.sol similarity index 100% rename from src/core/ConditionManager/ICondition.sol rename to packages/ConditionManager/ICondition.sol diff --git a/src/core/ConditionManager/IConditionManager.sol b/packages/ConditionManager/IConditionManager.sol similarity index 100% rename from src/core/ConditionManager/IConditionManager.sol rename to packages/ConditionManager/IConditionManager.sol diff --git a/src/Accounts.sol b/packages/DiffAccount/foo.sol.bak similarity index 76% rename from src/Accounts.sol rename to packages/DiffAccount/foo.sol.bak index 75df75ea..f9128645 100644 --- a/src/Accounts.sol +++ b/packages/DiffAccount/foo.sol.bak @@ -1,10 +1,4 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.23; -/* solhint-disable no-unused-import */ -import { Execution, IERC7579Account } from "./external/ERC7579.sol"; - -import { AccountFactory as SafeFactory } from "./accounts/safe/src/Account.sol"; import "forge-std/Test.sol"; contract MultiAccount is Test { diff --git a/packages/SessionKeyManager/bytecode.sh b/packages/SessionKeyManager/bytecode.sh new file mode 100755 index 00000000..b9abe489 --- /dev/null +++ b/packages/SessionKeyManager/bytecode.sh @@ -0,0 +1,8 @@ +#!/bin/sh +bytecode=$(jq ".bytecode" out/SessionKeyManager.sol/SessionKeyManager.json | jq ".object" | sed s/\"0x/hex\"/g) + +echo "// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +/* solhint-disable max-line-length */ +bytes constant SESSIONKEYMANAGER_BYTECODE = $bytecode;" > src/SessionKeyManagerBytecode.sol diff --git a/foundry.toml b/packages/SessionKeyManager/foundry.toml similarity index 96% rename from foundry.toml rename to packages/SessionKeyManager/foundry.toml index a6d59920..ed1a6c0d 100644 --- a/foundry.toml +++ b/packages/SessionKeyManager/foundry.toml @@ -2,11 +2,10 @@ src = "src" out = "out" libs = ["lib"] -#via_ir = true +via_ir = true fs_permissions = [{ access = "read", path = "out-optimized" }, { access = "read-write", path = "gas_calculations" }] allow_paths = ["*", "/"] - [rpc_endpoints] mainnet = "https://rpc.ankr.com/eth" diff --git a/packages/SessionKeyManager/package.json b/packages/SessionKeyManager/package.json new file mode 100644 index 00000000..5371212a --- /dev/null +++ b/packages/SessionKeyManager/package.json @@ -0,0 +1,64 @@ +{ + "name": "@rhinestone/sessionkeymanager", + "description": "ERC-4337 / ERC-7579 SessionKeyManager", + "license": "MIT", + "version": "0.1.0", + "author": { + "name": "zeroknots.eth", + "url": "https://rhinestone.wtf" + }, + "bugs": { + "url": "https://github.com/rhinestonewtf/modulekit/issues" + }, + "devDependencies": { + "@rhinestone/modulekit": "workspace:*", + "ds-test": "github:dapphub/ds-test", + "@ERC4337/account-abstraction": "github:kopy-kat/account-abstraction#develop", + "@ERC4337/account-abstraction-v0.6": "github:eth-infinitism/account-abstraction#v0.6.0", + "sentinellist": "github:zeroknots/sentinellist", + "erc7579": "github:erc7579/erc7579-implementation", + "forge-std": "github:foundry-rs/forge-std", + "solady": "github:vectorized/solady", + "solhint": "^4.1.1", + "prettier": "^2.8.8" + }, + "files": [ + "artifacts", + "src", + "test/utils", + "CHANGELOG.md", + "LICENSE-GPL.md" + ], + "keywords": [ + "blockchain", + "ethereum", + "foundry", + "smart-contracts", + "solidity", + "web3" + ], + "publishConfig": { + "access": "public" + }, + "repository": "github.com/rhinestonewtf/modulekit", + "scripts": { + "fmt": "forge fmt", + "fmt:check": "forge fmt --check", + "build": "forge build && ./bytecode.sh", + "bytecode": "./bytescode.sh", + "build:optimized": "FOUNDRY_PROFILE=optimized forge build", + "build:smt": "FOUNDRY_PROFILE=smt forge build", + "clean": "rm -rf artifacts broadcast cache docs out out-optimized out-svg", + "gas:report": "forge test --gas-report --mp \"./test/integration/**/*.sol\" --nmt \"test(Fuzz)?_RevertWhen_\\w{1,}?\"", + "gas:snapshot": "forge snapshot --mp \"./test/integration/**/*.sol\" --nmt \"test(Fuzz)?_RevertWhen_\\w{1,}?\"", + "gas:snapshot:optimized": "pnpm run build:optimized && FOUNDRY_PROFILE=test-optimized forge snapshot --mp \"./test/integration/**/*.sol\" --nmt \"test(Fork)?(Fuzz)?_RevertWhen_\\w{1,}?\"", + "lint": "pnpm run lint:sol && bun run prettier:check", + "lint:sol": "forge fmt --check && pnpm solhint \"{script,src,test}/**/*.sol\"", + "prepack": "pnpm install", + "prettier:check": "prettier --check \"**/*.{json,md,svg,yml}\"", + "prettier:write": "prettier --write \"**/*.{json,md,svg,yml}\"", + "test": "forge test", + "test:lite": "FOUNDRY_PROFILE=lite forge test", + "test:optimized": "pnpm run build:optimized && FOUNDRY_PROFILE=test-optimized forge test" + } +} diff --git a/packages/SessionKeyManager/remappings.txt b/packages/SessionKeyManager/remappings.txt new file mode 100644 index 00000000..71afa807 --- /dev/null +++ b/packages/SessionKeyManager/remappings.txt @@ -0,0 +1,9 @@ +solady/=node_modules/solady/ +@rhinestone/=node_modules/@rhinestone/ +erc7579/=node_modules/erc7579/src/ +@ERC4337/=node_modules/@ERC4337/ +account-abstraction/=node_modules/@ERC4337/account-abstraction/contracts/ +account-abstraction-v0.6/=node_modules/@ERC4337/account-abstraction-v0.6/contracts/ +forge-std/=node_modules/forge-std/src/ +ds-test/=node_modules/ds-test/src/ +sentinellist/=node_modules/sentinellist/src/ diff --git a/src/core/SessionKey/ISessionKeyManager.sol b/packages/SessionKeyManager/src/ISessionKeyManager.sol similarity index 91% rename from src/core/SessionKey/ISessionKeyManager.sol rename to packages/SessionKeyManager/src/ISessionKeyManager.sol index 02badb5c..c26fe93a 100644 --- a/src/core/SessionKey/ISessionKeyManager.sol +++ b/packages/SessionKeyManager/src/ISessionKeyManager.sol @@ -3,16 +3,16 @@ pragma solidity ^0.8.23; import { ISessionValidationModule } from "./ISessionValidationModule.sol"; -struct SessionData { - uint48 validUntil; - uint48 validAfter; - ISessionValidationModule sessionValidationModule; - bytes sessionKeyData; -} - interface ISessionKeyManager { type ValidationData is uint256; + struct SessionData { + uint48 validUntil; + uint48 validAfter; + ISessionValidationModule sessionValidationModule; + bytes sessionKeyData; + } + struct UserOperation { address sender; uint256 nonce; diff --git a/src/core/SessionKey/ISessionValidationModule.sol b/packages/SessionKeyManager/src/ISessionValidationModule.sol similarity index 100% rename from src/core/SessionKey/ISessionValidationModule.sol rename to packages/SessionKeyManager/src/ISessionValidationModule.sol diff --git a/src/core/SessionKey/SessionKeyManager.sol.bak b/packages/SessionKeyManager/src/SessionKeyManager.sol similarity index 85% rename from src/core/SessionKey/SessionKeyManager.sol.bak rename to packages/SessionKeyManager/src/SessionKeyManager.sol index 713db210..44b20b90 100644 --- a/src/core/SessionKey/SessionKeyManager.sol.bak +++ b/packages/SessionKeyManager/src/SessionKeyManager.sol @@ -4,18 +4,22 @@ pragma solidity ^0.8.23; /* solhint-disable function-max-lines*/ /* solhint-disable ordering*/ -import { ERC7579ValidatorBase } from "../../modules/ERC7579ValidatorBase.sol"; -import { UserOperation, UserOperationLib } from "../../external/ERC4337.sol"; -import { IERC7579Account } from "../../ModuleKitLib.sol"; -import { IERC1271 } from "../../interfaces/IERC1271.sol"; +import { + ACCOUNT_EXEC_TYPE, + ERC7579ValidatorLib +} from "@rhinestone/modulekit/src/modules/utils/ERC7579ValidatorLib.sol"; +import { ERC7579ValidatorBase } from "@rhinestone/modulekit/src/modules/ERC7579ValidatorBase.sol"; +import { + PackedUserOperation, UserOperationLib +} from "@rhinestone/modulekit/src/external/ERC4337.sol"; import { ISessionValidationModule } from "./ISessionValidationModule.sol"; import { SessionData, SessionKeyManagerLib } from "./SessionKeyManagerLib.sol"; -import { ACCOUNT_EXEC_TYPE, ERC7579ValidatorLib } from "../../modules/utils/ERC7579ValidatorLib.sol"; import { SignatureCheckerLib } from "solady/src/utils/SignatureCheckerLib.sol"; +import { Execution } from "erc7579/interfaces/IERC7579Account.sol"; contract SessionKeyManager is ERC7579ValidatorBase { - using UserOperationLib for UserOperation; - using ERC7579ValidatorLib for UserOperation; + using UserOperationLib for PackedUserOperation; + using ERC7579ValidatorLib for PackedUserOperation; using ERC7579ValidatorLib for bytes; using SessionKeyManagerLib for SessionData; using SessionKeyManagerLib for bytes32; @@ -58,7 +62,7 @@ contract SessionKeyManager is ERC7579ValidatorBase { } function validateUserOp( - UserOperation calldata userOp, + PackedUserOperation calldata userOp, bytes32 userOpHash ) external @@ -78,8 +82,8 @@ contract SessionKeyManager is ERC7579ValidatorBase { } function _validateSingleExec( - UserOperation calldata userOp, - bytes32 userOpHash + PackedUserOperation calldata userOp, + bytes32 /*userOpHash*/ // TODO: userOpHash is currently not evaluated. DONT USE THIS IN PROD ) internal returns (ValidationData vd) @@ -105,8 +109,8 @@ contract SessionKeyManager is ERC7579ValidatorBase { } function _validateBatchedExec( - UserOperation calldata userOp, - bytes32 userOpHash + PackedUserOperation calldata userOp, + bytes32 /*userOpHash*/ ) internal returns (ValidationData vd) @@ -118,8 +122,7 @@ contract SessionKeyManager is ERC7579ValidatorBase { SessionKeyManagerLib.decodeSignatureBatch(userOp.signature); // get ERC7579 Execution struct array from callData - Execution[] calldata execs = - ERC7579ValidatorLib.decodeCalldataBatch(userOp.callData); + Execution[] calldata execs = ERC7579ValidatorLib.decodeCalldataBatch(userOp.callData); uint256 length = sessionKeySignatures.length; if (execs.length != length) { @@ -198,11 +201,11 @@ contract SessionKeyManager is ERC7579ValidatorBase { returns (bytes4) { } - function name() external pure virtual override returns (string memory) { + function name() external pure virtual returns (string memory) { return "SessionKeyManager"; } - function version() external pure virtual override returns (string memory) { + function version() external pure virtual returns (string memory) { return "0.0.1"; } @@ -213,4 +216,6 @@ contract SessionKeyManager is ERC7579ValidatorBase { function onInstall(bytes calldata data) external override { } function onUninstall(bytes calldata data) external override { } + + function isInitialized(address smartAccount) external view override returns (bool) { } } diff --git a/packages/SessionKeyManager/src/SessionKeyManagerBytecode.sol b/packages/SessionKeyManager/src/SessionKeyManagerBytecode.sol new file mode 100644 index 00000000..c1f9b7f8 --- /dev/null +++ b/packages/SessionKeyManager/src/SessionKeyManagerBytecode.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +/* solhint-disable max-line-length */ +bytes constant SESSIONKEYMANAGER_BYTECODE = + hex"6080806040523461001657610cfe908161001c8239f35b600080fdfe60806040908082526004918236101561001757600080fd5b600091823560e01c90816306fdde03146106025750806354fd4d50146105be5780636d61fe70146105b95780638a91b0e3146105b95780639700320314610563578063cb9b272c14610308578063d4511ee9146102e7578063d60b347f146102c2578063d6cc1aa4146102a8578063df73e60e146101cb578063ecd05961146101a6578063f42c859d146100ff5763f551e2ee146100b457600080fd5b346100fb5760603660031901126100fb576100cd610727565b5060443567ffffffffffffffff81116100f7576020936100ef9136910161068f565b505051908152f35b8280fd5b5080fd5b508183346100fb5760203660031901126100fb576001903592838352826020528083203384526020528220828155016101388154610807565b80610169575b505050337f10103b778a5e09e8bcc680439d97711489525190a1fe679251002e893f9ea5638380a380f35b82601f8211600114610181575050555b81838061013e565b909180825261019f601f60208420940160051c840160018501610841565b5555610179565b509190346101c85760203660031901126101c857506001602092519135148152f35b80fd5b50346100fb57806003193601126100fb576102a460016101e9610727565b838051956101f68761073d565b808752606080602098838a820152838582015201526024358152808752818120848060a01b038094168252875220948451946102318661073d565b86549165ffffffffffff9788918285168952610271818a0192848760301c168452858b019660601c875261026a8651809a81930161088c565b038861078b565b606089019687528351998a99828b52511690890152511690860152511660608401525160808084015260a083019061064f565b0390f35b50346100fb57816003193601126100fb5751908152602090f35b50346100fb5760203660031901126100fb57906020916102e0610727565b5051908152f35b50346100fb576020906103016102fc366106f5565b610c34565b9051908152f35b5082346100f757610318366106f5565b9061032282610c34565b92838552602092858452818620338752845281862065ffffffffffff9283610349846107e0565b1690868401946bffffffffffff000000000000610365876107e0565b60301b16828601936bffffffffffffffffffffffff19610384866107f3565b60601b169117178455600180940160608601946103a186886107ad565b919067ffffffffffffffff9a8b841161055057509082918e8d6103c48754610807565b90601f8211610517575b90508193601f86116001146104ad575050926104a2575b50508160011b916000199060031b1c19161790555b6104178251968988528261040d88610858565b168a890152610858565b1690850152356001600160a01b0381169081900361049e57606084015235601e198236030181121561049a57018035930191831161049657823603821361049657806104907f57aa9b35aca9ac2ac77db1278fe563afa57004616360740e680d89bc674ebd1e93608080840152339560a084019161086b565b0390a380f35b8480fd5b8680fd5b8780fd5b013590508d806103e5565b8783528183209550929392601f19871692915b8383106104ff575050509084600195949392106104e5575b505050811b0190556103fa565b0135600019600384901b60f8161c191690558d80806104d8565b8185978293949688013581550196019301908f6104c0565b87835280832061053f92601f880160051c8201928810610546575b601f0160051c0190610841565b388e6103ce565b9091508190610532565b634e487b7160e01b8f526041905260248efd5b5090346101c8576003199282843601126100fb57803567ffffffffffffffff81116100f7576101208183019582360301126100f75760646105a59101856107ad565b919050116101c85750610301602092610922565b6106c2565b50346100fb57816003193601126100fb5780516102a4916105de8261076f565b6005825264302e302e3160d81b60208301525191829160208352602083019061064f565b919050346100f757826003193601126100f7576102a492506106238261076f565b601182527029b2b9b9b4b7b725b2bca6b0b730b3b2b960791b6020830152519182916020835260208301905b919082519283825260005b84811061067b575050826000602080949584010152601f8019910116010190565b60208183018101518483018201520161065a565b9181601f840112156106bd5782359167ffffffffffffffff83116106bd57602083818601950101116106bd57565b600080fd5b346106bd5760203660031901126106bd5760043567ffffffffffffffff81116106bd576106f390369060040161068f565b005b600319906020818301126106bd576004359167ffffffffffffffff83116106bd57826080920301126106bd5760040190565b600435906001600160a01b03821682036106bd57565b6080810190811067ffffffffffffffff82111761075957604052565b634e487b7160e01b600052604160045260246000fd5b6040810190811067ffffffffffffffff82111761075957604052565b90601f8019910116810190811067ffffffffffffffff82111761075957604052565b903590601e19813603018212156106bd570180359067ffffffffffffffff82116106bd576020019181360383136106bd57565b3565ffffffffffff811681036106bd5790565b356001600160a01b03811681036106bd5790565b90600182811c92168015610837575b602083101461082157565b634e487b7160e01b600052602260045260246000fd5b91607f1691610816565b81811061084c575050565b60008155600101610841565b359065ffffffffffff821682036106bd57565b908060209392818452848401376000828201840152601f01601f1916010190565b80546000939261089b82610807565b9182825260209360019160018116908160001461090357506001146108c2575b5050505050565b90939495506000929192528360002092846000945b8386106108ef575050505001019038808080806108bb565b8054858701830152940193859082016108d7565b60ff19168685015250505090151560051b0101915038808080806108bb565b6109306101008201826107ad565b5060018101356000526000602052604060002060018060a01b0383351660005260205261096660406000209260608101906107ad565b9290836004116106bd576003198401806020116106bd57806040116106bd57601f198501858111610c1e57806080116106bd57116106bd576109f7602091610a0c956000855460601c92610a2c604051998a968795869463c20bccb960e01b8652601081013560601c60048701526024810135602487015260a06044870152608460a4870192609f1901910161086b565b83810360031901606485015260018a0161088c565b82810360031901608484015260218a8101358b016001810135910161086b565b03925af1928315610c1257600093610bce575b5054916000916001600160a01b038216610a80575b505015610a7a5760a01b65ffffffffffff60d01b81169065ffffffffffff60a01b161790565b50600190565b9091506040519160018201356000526040600160218401358401013514610b6f575b6041600160218401358401013514610b25575b60006060526040838152630b135d3f60e11b8085526001848101356004870152602486019283526021808601358601808301356044890181905294979396602096899690959460649490930184860137602181013501013501916001600160a01b03165afa915114163880610a54565b6021828101358301606181013560001a6020526040910181376020600160806000825afa516001600160a01b038216183d1517610ab5575050600060605260405260013880610a54565b6021828101358301604181013560ff81901c601b01602090815291909201356040526001600160ff1b03909116606052600160806000825afa516001600160a01b038216183d1517610aa2575050600060605260405260013880610a54565b9092506020813d602011610c0a575b81610bea6020938361078b565b810103126106bd57516001600160a01b03811681036106bd579138610a3f565b3d9150610bdd565b6040513d6000823e3d90fd5b634e487b7160e01b600052601160045260246000fd5b610c3d816107e0565b90610cc26040610c4f602084016107e0565b93610c69610c5e8386016107f3565b9460608101906107ad565b80918451968794602086019965ffffffffffff60d01b809260d01b168b5260d01b1660268601526bffffffffffffffffffffffff199060601b16602c85015284840137810160008382015203602081018452018261078b565b5190209056fea264697066735822122026a81cd670005fcd561638caf42a14771310b8b3023b89447085b3f5739e2d3364736f6c63430008180033"; diff --git a/src/core/SessionKey/SessionKeyManagerLib.sol b/packages/SessionKeyManager/src/SessionKeyManagerLib.sol similarity index 100% rename from src/core/SessionKey/SessionKeyManagerLib.sol rename to packages/SessionKeyManager/src/SessionKeyManagerLib.sol diff --git a/packages/modulekit/.gas-snapshot b/packages/modulekit/.gas-snapshot new file mode 100644 index 00000000..858b9377 --- /dev/null +++ b/packages/modulekit/.gas-snapshot @@ -0,0 +1,15 @@ +BaseTest:test_transfer() (gas: 712286) +ERC7579DifferentialModuleKitLibTest:testAddExecutor() (gas: 1083999) +ERC7579DifferentialModuleKitLibTest:testAddHook() (gas: 717105) +ERC7579DifferentialModuleKitLibTest:testAddSessionKey() (gas: 166) +ERC7579DifferentialModuleKitLibTest:testAddValidator() (gas: 1245702) +ERC7579DifferentialModuleKitLibTest:testDeployAccount() (gas: 20268383) +ERC7579DifferentialModuleKitLibTest:testGetUserOpHash() (gas: 188) +ERC7579DifferentialModuleKitLibTest:testRemoveExecutor() (gas: 1160670) +ERC7579DifferentialModuleKitLibTest:testRemoveValidator() (gas: 1002596) +ERC7579DifferentialModuleKitLibTest:testWriteGas() (gas: 1567493) +ERC7579DifferentialModuleKitLibTest:test_transfer() (gas: 712461) +ERC7579DifferentialModuleKitLibTest:testexec__Given__FourInputs() (gas: 710862) +ERC7579DifferentialModuleKitLibTest:testexec__Given__ThreeInputs() (gas: 711683) +ERC7579DifferentialModuleKitLibTest:testexec__Given__TwoInputs() (gas: 716318) +ERC7579DifferentialModuleKitLibTest:testexec__RevertWhen__UserOperationFails() (gas: 694625) \ No newline at end of file diff --git a/packages/modulekit/foundry.toml b/packages/modulekit/foundry.toml new file mode 100644 index 00000000..7c06b254 --- /dev/null +++ b/packages/modulekit/foundry.toml @@ -0,0 +1,21 @@ +[profile.default] +src = "src" +out = "out" +libs = ["node_modules"] +#via_ir = true +fs_permissions = [{ access = "read", path = "out-optimized" }, { access = "read-write", path = "gas_calculations" }] +allow_paths = ["*", "/"] + +[rpc_endpoints] +mainnet = "https://rpc.ankr.com/eth" + + +[fmt] +bracket_spacing = true +int_types = "long" +line_length = 100 +multiline_func_header = "all" +number_underscore = "thousands" +quote_style = "double" +tab_width = 4 +wrap_comments = true diff --git a/packages/modulekit/gas_calculations/testWriteGas.json b/packages/modulekit/gas_calculations/testWriteGas.json new file mode 100644 index 00000000..6fd303a5 --- /dev/null +++ b/packages/modulekit/gas_calculations/testWriteGas.json @@ -0,0 +1,12 @@ +{ + "Calldata": { + "Arbitrum": "6348 gas", + "OP-Stack": "8794 gas" + }, + "Phases": { + "Creation": "334714 gas", + "Execution": "37137 gas", + "Validation": "36038 gas" + }, + "Total": "2698598 gas" +} \ No newline at end of file diff --git a/packages/modulekit/package.json b/packages/modulekit/package.json new file mode 100644 index 00000000..d0da21e4 --- /dev/null +++ b/packages/modulekit/package.json @@ -0,0 +1,71 @@ +{ + "name": "@rhinestone/modulekit", + "description": "ModuleKit is a development toolkit to build Smart Account Modules", + "license": "MIT", + "version": "0.3.1", + "author": { + "name": "zeroknots.eth", + "url": "https://rhinestone.wtf" + }, + "bugs": { + "url": "https://github.com/rhinestonewtf/modulekit/issues" + }, + "dependencies": {}, + "devDependencies": { + "@rhinestone/sessionkeymanager": "workspace:*", + "@rhinestone/safe7579": "workspace:*", + "ds-test": "github:dapphub/ds-test", + "forge-std": "github:foundry-rs/forge-std", + "@openzeppelin/contracts": "5.0.1", + "@prb/math": "^4.0.2", + "erc4337-validation": "github:rhinestonewtf/erc4337-validation", + "@ERC4337/account-abstraction": "github:kopy-kat/account-abstraction#develop", + "@ERC4337/account-abstraction-v0.6": "github:eth-infinitism/account-abstraction#v0.6.0", + "@safe-global/safe-contracts": "^1.4.1", + "erc7579": "github:erc7579/erc7579-implementation", + "prettier": "^2.8.8", + "sentinellist": "github:zeroknots/sentinellist", + "solady": "github:vectorized/solady", + "solarray": "github:sablier-labs/solarray", + "solhint": "^4.1.1" + }, + "files": [ + "artifacts", + "src", + "test/utils", + "CHANGELOG.md", + "LICENSE-GPL.md" + ], + "homepage": "https://github.com/rhinestonewtf/modulekit/#readme", + "keywords": [ + "blockchain", + "ethereum", + "foundry", + "smart-contracts", + "solidity", + "web3" + ], + "publishConfig": { + "access": "public" + }, + "repository": "github.com/rhinestonewtf/modulekit", + "scripts": { + "build": "forge build", + "fmt": "forge fmt", + "fmt:check": "forge fmt --check", + "build:optimized": "FOUNDRY_PROFILE=optimized forge build", + "build:smt": "FOUNDRY_PROFILE=smt forge build", + "clean": "rm -rf artifacts broadcast cache docs out out-optimized out-svg", + "gas:report": "forge test --gas-report --mp \"./test/integration/**/*.sol\" --nmt \"test(Fuzz)?_RevertWhen_\\w{1,}?\"", + "gas:snapshot": "forge snapshot --mp \"./test/integration/**/*.sol\" --nmt \"test(Fuzz)?_RevertWhen_\\w{1,}?\"", + "gas:snapshot:optimized": "pnpm run build:optimized && FOUNDRY_PROFILE=test-optimized forge snapshot --mp \"./test/integration/**/*.sol\" --nmt \"test(Fork)?(Fuzz)?_RevertWhen_\\w{1,}?\"", + "lint": "pnpm run lint:sol && bun run prettier:check", + "lint:sol": "forge fmt --check && pnpm solhint \"{script,src,test}/**/*.sol\"", + "prepack": "pnpm install", + "prettier:check": "prettier --check \"**/*.{json,md,svg,yml}\"", + "prettier:write": "prettier --write \"**/*.{json,md,svg,yml}\"", + "test": "forge test", + "test:lite": "FOUNDRY_PROFILE=lite forge test", + "test:optimized": "pnpm run build:optimized && FOUNDRY_PROFILE=test-optimized forge test" + } +} diff --git a/remappings.txt b/packages/modulekit/remappings.txt similarity index 54% rename from remappings.txt rename to packages/modulekit/remappings.txt index faca4f3b..11d91084 100644 --- a/remappings.txt +++ b/packages/modulekit/remappings.txt @@ -1,13 +1,15 @@ -account-abstraction/=node_modules/account-abstraction/contracts/ -account-abstraction-v0.6/=node_modules/account-abstraction-v0.6/contracts/ +@rhinestone/=node_modules/@rhinestone/ +@ERC4337/=node_modules/@ERC4337/ +account-abstraction/=node_modules/@ERC4337/account-abstraction/contracts/ +account-abstraction-v0.6/=node_modules/@ERC4337/account-abstraction-v0.6/contracts/ @openzeppelin/=node_modules/@openzeppelin/ +@safe-global/=node_modules/@safe-global/ ds-test/=node_modules/ds-test/src/ erc7579/=node_modules/erc7579/src/ -@rhinestone/sessionkeymanager/=node_modules/@rhinestone/sessionkeymanager/src/ forge-std/=node_modules/forge-std/src/ -@safe-global/=node_modules/@safe-global/ sentinellist/=node_modules/sentinellist/src/ solady/=node_modules/solady/ solarray/=node_modules/solarray/src/ @prb/math/=node_modules/@prb/math/ -erc4337-validation/=node_modules/erc4337-validation/src/ \ No newline at end of file +erc4337-validation/=node_modules/erc4337-validation/src/ + diff --git a/packages/modulekit/src/Accounts.sol b/packages/modulekit/src/Accounts.sol new file mode 100644 index 00000000..c990987b --- /dev/null +++ b/packages/modulekit/src/Accounts.sol @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +/* solhint-disable no-unused-import */ +import { Execution, IERC7579Account } from "./external/ERC7579.sol"; diff --git a/src/Core.sol b/packages/modulekit/src/Core.sol similarity index 65% rename from src/Core.sol rename to packages/modulekit/src/Core.sol index 3a01bc8a..0cd46bc5 100644 --- a/src/Core.sol +++ b/packages/modulekit/src/Core.sol @@ -3,10 +3,10 @@ pragma solidity ^0.8.23; /* solhint-disable no-unused-import */ import { ISessionValidationModule } from - "@rhinestone/sessionkeymanager/ISessionValidationModule.sol"; + "@rhinestone/sessionkeymanager/src/ISessionValidationModule.sol"; -import { ISessionKeyManager } from "@rhinestone/sessionkeymanager/ISessionKeyManager.sol"; +import { ISessionKeyManager } from "@rhinestone/sessionkeymanager/src/ISessionKeyManager.sol"; import { SESSIONKEYMANAGER_BYTECODE } from - "@rhinestone/sessionkeymanager/SessionKeyManagerBytecode.sol"; -import { SessionKeyManagerLib } from "@rhinestone/sessionkeymanager/SessionKeyManagerLib.sol"; + "@rhinestone/sessionkeymanager/src/SessionKeyManagerBytecode.sol"; +import { SessionKeyManagerLib } from "@rhinestone/sessionkeymanager/src/SessionKeyManagerLib.sol"; import { ExtensibleFallbackHandler } from "./core/ExtensibleFallbackHandler.sol"; diff --git a/src/Helpers.sol b/packages/modulekit/src/Helpers.sol similarity index 100% rename from src/Helpers.sol rename to packages/modulekit/src/Helpers.sol diff --git a/src/Integrations.sol b/packages/modulekit/src/Integrations.sol similarity index 100% rename from src/Integrations.sol rename to packages/modulekit/src/Integrations.sol diff --git a/src/Mocks.sol b/packages/modulekit/src/Mocks.sol similarity index 100% rename from src/Mocks.sol rename to packages/modulekit/src/Mocks.sol diff --git a/src/ModuleKit.sol b/packages/modulekit/src/ModuleKit.sol similarity index 100% rename from src/ModuleKit.sol rename to packages/modulekit/src/ModuleKit.sol diff --git a/src/Modules.sol b/packages/modulekit/src/Modules.sol similarity index 82% rename from src/Modules.sol rename to packages/modulekit/src/Modules.sol index 1992c006..5222b7a3 100644 --- a/src/Modules.sol +++ b/packages/modulekit/src/Modules.sol @@ -9,3 +9,9 @@ import { ERC7579HookBase } from "./modules/ERC7579HookBase.sol"; import { ERC7579HookDestruct } from "./modules/ERC7579HookDestruct.sol"; import { ERC7579FallbackBase } from "./modules/ERC7579FallbackBase.sol"; import { ExtensibleFallbackHandler } from "./core/ExtensibleFallbackHandler.sol"; +import { + IERC7579Validator, + IERC7579Executor, + IERC7579Fallback, + IERC7579Hook +} from "./external/ERC7579.sol"; diff --git a/packages/modulekit/src/accountFactory/MultiAccountFactory.sol b/packages/modulekit/src/accountFactory/MultiAccountFactory.sol new file mode 100644 index 00000000..0faacb61 --- /dev/null +++ b/packages/modulekit/src/accountFactory/MultiAccountFactory.sol @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import "forge-std/Base.sol"; +import "./safe7579/Safe7579Factory.sol"; +import "./referenceImpl/RefImplFactory.sol"; +import { ERC7579BootstrapConfig } from "../external/ERC7579.sol"; + +enum AccountType { + DEFAULT, + SAFE7579 +} + +string constant DEFAULT = "DEFAULT"; +string constant SAFE7579 = "SAFE7579"; + +contract MultiAccountFactory is TestBase, Safe7579Factory, RefImplFactory { + AccountType public env; + + constructor() { + string memory _env = vm.envOr("ACCOUNT_TYPE", DEFAULT); + + if (keccak256(abi.encodePacked(_env)) == keccak256(abi.encodePacked(SAFE7579))) { + env = AccountType.SAFE7579; + } else { + env = AccountType.DEFAULT; + } + } + + function createAccount( + bytes32 salt, + bytes calldata initCode + ) + public + returns (address account) + { + if (env == AccountType.SAFE7579) { + return _makeSafe(salt, initCode); + } else { + return _makeDefault(salt, initCode); + } + } + + function _makeDefault(bytes32 salt, bytes calldata initCode) public returns (address) { + return _createUMSA(salt, initCode); + } + + function _makeSafe(bytes32 salt, bytes calldata initCode) public returns (address) { + return _createSafe(salt, initCode); + } + + function getAddress( + bytes32 salt, + bytes memory initCode + ) + public + view + virtual + returns (address) + { + if (env == AccountType.SAFE7579) { + return getAddressSafe(salt, initCode); + } else { + return getAddressUMSA(salt, initCode); + } + } + + function _getSalt( + bytes32 _salt, + bytes memory initCode + ) + public + pure + virtual + override(RefImplFactory, Safe7579Factory) + returns (bytes32 salt) + { + salt = keccak256(abi.encodePacked(_salt, initCode)); + } + + function getBootstrapCallData( + ERC7579BootstrapConfig[] calldata _validators, + ERC7579BootstrapConfig[] calldata _executors, + ERC7579BootstrapConfig calldata _hook, + ERC7579BootstrapConfig calldata _fallback + ) + external + view + returns (bytes memory init) + { + if (env == AccountType.SAFE7579) { + init = abi.encode( + address(bootstrapSafe), + abi.encodeCall( + ERC7579Bootstrap.initMSA, (_validators, _executors, _hook, _fallback) + ) + ); + } else { + init = abi.encode( + address(bootstrapDefault), + abi.encodeCall(BootstrapSafe.initMSA, (_validators, _executors, _hook, _fallback)) + ); + } + } +} diff --git a/packages/modulekit/src/accountFactory/referenceImpl/RefImplFactory.sol b/packages/modulekit/src/accountFactory/referenceImpl/RefImplFactory.sol new file mode 100644 index 00000000..a44e83e1 --- /dev/null +++ b/packages/modulekit/src/accountFactory/referenceImpl/RefImplFactory.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import "../../external/ERC7579.sol"; +import { LibClone } from "solady/src/utils/LibClone.sol"; + +interface IMSA { + function initializeAccount(bytes calldata initCode) external; +} + +abstract contract RefImplFactory { + ERC7579Account internal implementation; + ERC7579Bootstrap internal bootstrapDefault; + + constructor() { + implementation = new ERC7579Account(); + bootstrapDefault = new ERC7579Bootstrap(); + } + + function _createUMSA(bytes32 salt, bytes memory initCode) public returns (address account) { + bytes32 _salt = _getSalt(salt, initCode); + address account = LibClone.cloneDeterministic(0, address(implementation), initCode, _salt); + + IMSA(account).initializeAccount(initCode); + return account; + } + + function getAddressUMSA( + bytes32 salt, + bytes memory initCode + ) + public + view + virtual + returns (address) + { + bytes32 _salt = _getSalt(salt, initCode); + return LibClone.predictDeterministicAddress( + address(implementation), initCode, _salt, address(this) + ); + } + + function _getSalt( + bytes32 _salt, + bytes memory initCode + ) + public + pure + virtual + returns (bytes32 salt); +} diff --git a/packages/modulekit/src/accountFactory/safe7579/BootstrapSafe.sol b/packages/modulekit/src/accountFactory/safe7579/BootstrapSafe.sol new file mode 100644 index 00000000..73d00c2b --- /dev/null +++ b/packages/modulekit/src/accountFactory/safe7579/BootstrapSafe.sol @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.21; + +import "@rhinestone/safe7579/src/core/ModuleManager.sol"; +import "@rhinestone/safe7579/src/core/HookManager.sol"; + +import "../../external/ERC7579.sol"; + +contract BootstrapSafe is ModuleManager, HookManager { + function singleInitMSA(IERC7579Validator validator, bytes calldata data) external { + // init validator + _installValidator(address(validator), data); + } + + /** + * This function is intended to be called by the MSA with a delegatecall. + * Make sure that the MSA already initilazed the linked lists in the ModuleManager prior to + * calling this function + */ + function initMSA( + ERC7579BootstrapConfig[] calldata _validators, + ERC7579BootstrapConfig[] calldata _executors, + ERC7579BootstrapConfig calldata _hook, + ERC7579BootstrapConfig calldata _fallback + ) + external + { + // init validators + for (uint256 i; i < _validators.length; i++) { + _installValidator(_validators[i].module, _validators[i].data); + } + + // init executors + for (uint256 i; i < _executors.length; i++) { + if (_executors[i].module == address(0)) continue; + _installExecutor(_executors[i].module, _executors[i].data); + } + + // init hook + if (_hook.module != address(0)) { + _installHook(_hook.module, _hook.data); + } + + // init fallback + if (_fallback.module != address(0)) { + _installFallbackHandler(_fallback.module, _fallback.data); + } + } + + function _getInitMSACalldata( + ERC7579BootstrapConfig[] calldata _validators, + ERC7579BootstrapConfig[] calldata _executors, + ERC7579BootstrapConfig calldata _hook, + ERC7579BootstrapConfig calldata _fallback + ) + external + view + returns (bytes memory init) + { + init = abi.encode( + address(this), abi.encodeCall(this.initMSA, (_validators, _executors, _hook, _fallback)) + ); + } +} diff --git a/packages/modulekit/src/accountFactory/safe7579/Safe7579Factory.sol b/packages/modulekit/src/accountFactory/safe7579/Safe7579Factory.sol new file mode 100644 index 00000000..1d2a157d --- /dev/null +++ b/packages/modulekit/src/accountFactory/safe7579/Safe7579Factory.sol @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import "forge-std/Base.sol"; +import { SafeERC7579 } from "@rhinestone/safe7579/src/SafeERC7579.sol"; +import "@safe-global/safe-contracts/contracts/Safe.sol"; +import { LibClone } from "solady/src/utils/LibClone.sol"; + +import { BootstrapSafe } from "./BootstrapSafe.sol"; + +abstract contract Safe7579Factory is TestBase { + // singletons + + SafeERC7579 internal erc7579Mod; + Safe internal safeImpl; + + BootstrapSafe internal bootstrapSafe; + + constructor() { + // Set up MSA and Factory + erc7579Mod = new SafeERC7579(); + safeImpl = new Safe(); + bootstrapSafe = new BootstrapSafe(); + } + + function _createSafe(bytes32 salt, bytes calldata initCode) internal returns (address safe) { + bytes32 _salt = _getSalt(salt, initCode); + Safe clone = + Safe(payable(LibClone.cloneDeterministic(0, address(safeImpl), initCode, _salt))); + + address[] memory signers = new address[](2); + signers[0] = address(0x12345); + signers[1] = address(0x54321); + + clone.setup({ + _owners: signers, + _threshold: 2, + to: address(0), // optional delegatecall + data: "", + fallbackHandler: address(erc7579Mod), + paymentToken: address(0), // optional payment token + payment: 0, + paymentReceiver: payable(address(0)) // optional payment receiver + }); + + vm.startPrank(address(clone)); + clone.enableModule(address(erc7579Mod)); + erc7579Mod.initializeAccount(initCode); + vm.stopPrank(); + + return address(clone); + } + + function getAddressSafe( + bytes32 salt, + bytes memory initCode + ) + public + view + virtual + returns (address) + { + bytes32 _salt = _getSalt(salt, initCode); + return + LibClone.predictDeterministicAddress(address(safeImpl), initCode, _salt, address(this)); + } + + function _getSalt( + bytes32 _salt, + bytes memory initCode + ) + public + pure + virtual + returns (bytes32 salt); +} diff --git a/src/core/ERC2771Handler.sol b/packages/modulekit/src/core/ERC2771Handler.sol similarity index 95% rename from src/core/ERC2771Handler.sol rename to packages/modulekit/src/core/ERC2771Handler.sol index e08f3008..67342187 100644 --- a/src/core/ERC2771Handler.sol +++ b/packages/modulekit/src/core/ERC2771Handler.sol @@ -7,7 +7,8 @@ pragma solidity ^0.8.23; * @dev The fallback manager appends the following context to the calldata: * 1. Fallback manager caller address (non-padded) * based on - * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/f8cc8b844a9f92f63dc55aa581f7d643a1bc5ac1/contracts/metatx/ERC2771Context.sol + * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/f8cc8b844a9f92f63dc55aa581f7d643a1bc5ac1 + * /contracts/metatx/ERC2771Context.sol * @author Richard Meissner - @rmeissner */ contract ERC2771Handler { diff --git a/src/core/ExtensibleFallbackHandler.sol b/packages/modulekit/src/core/ExtensibleFallbackHandler.sol similarity index 87% rename from src/core/ExtensibleFallbackHandler.sol rename to packages/modulekit/src/core/ExtensibleFallbackHandler.sol index ed219547..111f8a36 100644 --- a/src/core/ExtensibleFallbackHandler.sol +++ b/packages/modulekit/src/core/ExtensibleFallbackHandler.sol @@ -6,9 +6,6 @@ pragma solidity ^0.8.23; import { ERC7579FallbackBase } from "../modules/ERC7579FallbackBase.sol"; import { ERC2771Handler } from "./ERC2771Handler.sol"; -import { ModuleTypeLib, EncodedModuleTypes, ModuleType } from "erc7579/lib/ModuleTypeLib.sol"; - -import "forge-std/console2.sol"; interface IFallbackMethod { function handle( @@ -39,14 +36,6 @@ contract ExtensibleFallbackHandler is ERC7579FallbackBase, ERC2771Handler { Dynamic } - EncodedModuleTypes immutable MODULE_TYPES; - - constructor() { - ModuleType[] memory moduleTypes = new ModuleType[](1); - moduleTypes[0] = ModuleType.wrap(TYPE_FALLBACK); - MODULE_TYPES = ModuleTypeLib.bitEncode(moduleTypes); - } - function onInstall(bytes calldata data) external override { if (data.length == 0) return; Params[] memory params = abi.decode(data, (Params[])); @@ -119,10 +108,6 @@ contract ExtensibleFallbackHandler is ERC7579FallbackBase, ERC2771Handler { return isType == TYPE_FALLBACK; } - function getModuleTypes() external view returns (EncodedModuleTypes) { - return MODULE_TYPES; - } - function isInitialized(address smartAccount) external pure returns (bool) { return false; } diff --git a/src/core/GasTest/GasLog.sol b/packages/modulekit/src/core/GasTest/GasLog.sol similarity index 100% rename from src/core/GasTest/GasLog.sol rename to packages/modulekit/src/core/GasTest/GasLog.sol diff --git a/src/core/Licensing/LicenseManager.sol.todo b/packages/modulekit/src/core/Licensing/LicenseManager.sol.todo similarity index 100% rename from src/core/Licensing/LicenseManager.sol.todo rename to packages/modulekit/src/core/Licensing/LicenseManager.sol.todo diff --git a/src/core/Licensing/LicensedModule.sol.bak b/packages/modulekit/src/core/Licensing/LicensedModule.sol.bak similarity index 100% rename from src/core/Licensing/LicensedModule.sol.bak rename to packages/modulekit/src/core/Licensing/LicensedModule.sol.bak diff --git a/src/deployment/RegistryDeployer.sol b/packages/modulekit/src/deployment/RegistryDeployer.sol similarity index 100% rename from src/deployment/RegistryDeployer.sol rename to packages/modulekit/src/deployment/RegistryDeployer.sol diff --git a/packages/modulekit/src/external/ERC4337.sol b/packages/modulekit/src/external/ERC4337.sol new file mode 100644 index 00000000..968d6b57 --- /dev/null +++ b/packages/modulekit/src/external/ERC4337.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +/* solhint-disable no-unused-import */ +import { PackedUserOperation } from + "@ERC4337/account-abstraction/contracts/interfaces/PackedUserOperation.sol"; +import { UserOperationLib } from "@ERC4337/account-abstraction/contracts/core/UserOperationLib.sol"; +import { IEntryPoint } from "@ERC4337/account-abstraction/contracts/interfaces/IEntryPoint.sol"; +import { IEntryPointSimulations } from + "@ERC4337/account-abstraction/contracts/interfaces/IEntryPointSimulations.sol"; +import { + ValidationData, + _packValidationData +} from "@ERC4337/account-abstraction/contracts/core/Helpers.sol"; +import { IStakeManager } from "@ERC4337/account-abstraction/contracts/interfaces/IStakeManager.sol"; + +/* solhint-enable no-unused-import */ diff --git a/src/external/ERC7579.sol b/packages/modulekit/src/external/ERC7579.sol similarity index 92% rename from src/external/ERC7579.sol rename to packages/modulekit/src/external/ERC7579.sol index dc730b58..47e1cd7d 100644 --- a/src/external/ERC7579.sol +++ b/packages/modulekit/src/external/ERC7579.sol @@ -28,7 +28,6 @@ import { EXECTYPE_DEFAULT, MODE_DEFAULT } from "erc7579/lib/ModeLib.sol"; -import { EncodedModuleTypes, ModuleTypeLib, ModuleType } from "erc7579/lib/ModuleTypeLib.sol"; import { Execution, ExecutionLib as ERC7579ExecutionLib } from "erc7579/lib/ExecutionLib.sol"; import { diff --git a/src/integrations/ERC20.sol b/packages/modulekit/src/integrations/ERC20.sol similarity index 100% rename from src/integrations/ERC20.sol rename to packages/modulekit/src/integrations/ERC20.sol diff --git a/src/integrations/ERC4626.sol b/packages/modulekit/src/integrations/ERC4626.sol similarity index 100% rename from src/integrations/ERC4626.sol rename to packages/modulekit/src/integrations/ERC4626.sol diff --git a/src/integrations/ERC721.sol b/packages/modulekit/src/integrations/ERC721.sol similarity index 100% rename from src/integrations/ERC721.sol rename to packages/modulekit/src/integrations/ERC721.sol diff --git a/src/integrations/interfaces/IBotRegistry.sol b/packages/modulekit/src/integrations/interfaces/IBotRegistry.sol similarity index 100% rename from src/integrations/interfaces/IBotRegistry.sol rename to packages/modulekit/src/integrations/interfaces/IBotRegistry.sol diff --git a/src/integrations/interfaces/IDFSRegistry.sol b/packages/modulekit/src/integrations/interfaces/IDFSRegistry.sol similarity index 100% rename from src/integrations/interfaces/IDFSRegistry.sol rename to packages/modulekit/src/integrations/interfaces/IDFSRegistry.sol diff --git a/src/integrations/interfaces/IDSProxy.sol b/packages/modulekit/src/integrations/interfaces/IDSProxy.sol similarity index 100% rename from src/integrations/interfaces/IDSProxy.sol rename to packages/modulekit/src/integrations/interfaces/IDSProxy.sol diff --git a/src/integrations/interfaces/IERC20.sol b/packages/modulekit/src/integrations/interfaces/IERC20.sol similarity index 100% rename from src/integrations/interfaces/IERC20.sol rename to packages/modulekit/src/integrations/interfaces/IERC20.sol diff --git a/src/integrations/interfaces/IERC4626.sol b/packages/modulekit/src/integrations/interfaces/IERC4626.sol similarity index 100% rename from src/integrations/interfaces/IERC4626.sol rename to packages/modulekit/src/integrations/interfaces/IERC4626.sol diff --git a/src/integrations/interfaces/IERC721.sol b/packages/modulekit/src/integrations/interfaces/IERC721.sol similarity index 100% rename from src/integrations/interfaces/IERC721.sol rename to packages/modulekit/src/integrations/interfaces/IERC721.sol diff --git a/src/integrations/interfaces/IERC721Enumerable.sol b/packages/modulekit/src/integrations/interfaces/IERC721Enumerable.sol similarity index 100% rename from src/integrations/interfaces/IERC721Enumerable.sol rename to packages/modulekit/src/integrations/interfaces/IERC721Enumerable.sol diff --git a/src/integrations/interfaces/IFLParamGetter.sol b/packages/modulekit/src/integrations/interfaces/IFLParamGetter.sol similarity index 100% rename from src/integrations/interfaces/IFLParamGetter.sol rename to packages/modulekit/src/integrations/interfaces/IFLParamGetter.sol diff --git a/src/integrations/interfaces/IGasToken.sol b/packages/modulekit/src/integrations/interfaces/IGasToken.sol similarity index 100% rename from src/integrations/interfaces/IGasToken.sol rename to packages/modulekit/src/integrations/interfaces/IGasToken.sol diff --git a/src/integrations/interfaces/ILendingPool.sol b/packages/modulekit/src/integrations/interfaces/ILendingPool.sol similarity index 100% rename from src/integrations/interfaces/ILendingPool.sol rename to packages/modulekit/src/integrations/interfaces/ILendingPool.sol diff --git a/src/integrations/interfaces/IMCDPriceVerifier.sol b/packages/modulekit/src/integrations/interfaces/IMCDPriceVerifier.sol similarity index 100% rename from src/integrations/interfaces/IMCDPriceVerifier.sol rename to packages/modulekit/src/integrations/interfaces/IMCDPriceVerifier.sol diff --git a/src/integrations/interfaces/IProxyERC20.sol b/packages/modulekit/src/integrations/interfaces/IProxyERC20.sol similarity index 100% rename from src/integrations/interfaces/IProxyERC20.sol rename to packages/modulekit/src/integrations/interfaces/IProxyERC20.sol diff --git a/src/integrations/interfaces/IProxyRegistry.sol b/packages/modulekit/src/integrations/interfaces/IProxyRegistry.sol similarity index 100% rename from src/integrations/interfaces/IProxyRegistry.sol rename to packages/modulekit/src/integrations/interfaces/IProxyRegistry.sol diff --git a/src/integrations/interfaces/ISubscriptions.sol b/packages/modulekit/src/integrations/interfaces/ISubscriptions.sol similarity index 100% rename from src/integrations/interfaces/ISubscriptions.sol rename to packages/modulekit/src/integrations/interfaces/ISubscriptions.sol diff --git a/src/integrations/interfaces/ITrigger.sol b/packages/modulekit/src/integrations/interfaces/ITrigger.sol similarity index 100% rename from src/integrations/interfaces/ITrigger.sol rename to packages/modulekit/src/integrations/interfaces/ITrigger.sol diff --git a/src/integrations/interfaces/IWETH.sol b/packages/modulekit/src/integrations/interfaces/IWETH.sol similarity index 100% rename from src/integrations/interfaces/IWETH.sol rename to packages/modulekit/src/integrations/interfaces/IWETH.sol diff --git a/src/integrations/interfaces/LSTs/ICBETH.sol b/packages/modulekit/src/integrations/interfaces/LSTs/ICBETH.sol similarity index 100% rename from src/integrations/interfaces/LSTs/ICBETH.sol rename to packages/modulekit/src/integrations/interfaces/LSTs/ICBETH.sol diff --git a/src/integrations/interfaces/LSTs/IRETH.sol b/packages/modulekit/src/integrations/interfaces/LSTs/IRETH.sol similarity index 100% rename from src/integrations/interfaces/LSTs/IRETH.sol rename to packages/modulekit/src/integrations/interfaces/LSTs/IRETH.sol diff --git a/src/integrations/interfaces/LSTs/IWstETH.sol b/packages/modulekit/src/integrations/interfaces/LSTs/IWstETH.sol similarity index 100% rename from src/integrations/interfaces/LSTs/IWstETH.sol rename to packages/modulekit/src/integrations/interfaces/LSTs/IWstETH.sol diff --git a/src/integrations/interfaces/aave/IAToken.sol b/packages/modulekit/src/integrations/interfaces/aave/IAToken.sol similarity index 100% rename from src/integrations/interfaces/aave/IAToken.sol rename to packages/modulekit/src/integrations/interfaces/aave/IAToken.sol diff --git a/src/integrations/interfaces/aave/ILendToAaveMigrator.sol b/packages/modulekit/src/integrations/interfaces/aave/ILendToAaveMigrator.sol similarity index 100% rename from src/integrations/interfaces/aave/ILendToAaveMigrator.sol rename to packages/modulekit/src/integrations/interfaces/aave/ILendToAaveMigrator.sol diff --git a/src/integrations/interfaces/aave/ILendingPool.sol b/packages/modulekit/src/integrations/interfaces/aave/ILendingPool.sol similarity index 100% rename from src/integrations/interfaces/aave/ILendingPool.sol rename to packages/modulekit/src/integrations/interfaces/aave/ILendingPool.sol diff --git a/src/integrations/interfaces/aave/ILendingPoolAddressesProvider.sol b/packages/modulekit/src/integrations/interfaces/aave/ILendingPoolAddressesProvider.sol similarity index 100% rename from src/integrations/interfaces/aave/ILendingPoolAddressesProvider.sol rename to packages/modulekit/src/integrations/interfaces/aave/ILendingPoolAddressesProvider.sol diff --git a/src/integrations/interfaces/aave/IStkAave.sol b/packages/modulekit/src/integrations/interfaces/aave/IStkAave.sol similarity index 100% rename from src/integrations/interfaces/aave/IStkAave.sol rename to packages/modulekit/src/integrations/interfaces/aave/IStkAave.sol diff --git a/src/integrations/interfaces/aaveV2/IAaveIncentivesController.sol b/packages/modulekit/src/integrations/interfaces/aaveV2/IAaveIncentivesController.sol similarity index 100% rename from src/integrations/interfaces/aaveV2/IAaveIncentivesController.sol rename to packages/modulekit/src/integrations/interfaces/aaveV2/IAaveIncentivesController.sol diff --git a/src/integrations/interfaces/aaveV2/IAaveProtocolDataProviderV2.sol b/packages/modulekit/src/integrations/interfaces/aaveV2/IAaveProtocolDataProviderV2.sol similarity index 100% rename from src/integrations/interfaces/aaveV2/IAaveProtocolDataProviderV2.sol rename to packages/modulekit/src/integrations/interfaces/aaveV2/IAaveProtocolDataProviderV2.sol diff --git a/src/integrations/interfaces/aaveV2/ILendingPoolAddressesProviderV2.sol b/packages/modulekit/src/integrations/interfaces/aaveV2/ILendingPoolAddressesProviderV2.sol similarity index 100% rename from src/integrations/interfaces/aaveV2/ILendingPoolAddressesProviderV2.sol rename to packages/modulekit/src/integrations/interfaces/aaveV2/ILendingPoolAddressesProviderV2.sol diff --git a/src/integrations/interfaces/aaveV2/ILendingPoolV2.sol b/packages/modulekit/src/integrations/interfaces/aaveV2/ILendingPoolV2.sol similarity index 100% rename from src/integrations/interfaces/aaveV2/ILendingPoolV2.sol rename to packages/modulekit/src/integrations/interfaces/aaveV2/ILendingPoolV2.sol diff --git a/src/integrations/interfaces/aaveV2/IPriceOracleGetterAave.sol b/packages/modulekit/src/integrations/interfaces/aaveV2/IPriceOracleGetterAave.sol similarity index 100% rename from src/integrations/interfaces/aaveV2/IPriceOracleGetterAave.sol rename to packages/modulekit/src/integrations/interfaces/aaveV2/IPriceOracleGetterAave.sol diff --git a/src/integrations/interfaces/aaveV2/IStakedToken.sol b/packages/modulekit/src/integrations/interfaces/aaveV2/IStakedToken.sol similarity index 100% rename from src/integrations/interfaces/aaveV2/IStakedToken.sol rename to packages/modulekit/src/integrations/interfaces/aaveV2/IStakedToken.sol diff --git a/src/integrations/interfaces/aaveV3/DataTypes.sol b/packages/modulekit/src/integrations/interfaces/aaveV3/DataTypes.sol similarity index 100% rename from src/integrations/interfaces/aaveV3/DataTypes.sol rename to packages/modulekit/src/integrations/interfaces/aaveV3/DataTypes.sol diff --git a/src/integrations/interfaces/aaveV3/IAaveProtocolDataProvider.sol b/packages/modulekit/src/integrations/interfaces/aaveV3/IAaveProtocolDataProvider.sol similarity index 100% rename from src/integrations/interfaces/aaveV3/IAaveProtocolDataProvider.sol rename to packages/modulekit/src/integrations/interfaces/aaveV3/IAaveProtocolDataProvider.sol diff --git a/src/integrations/interfaces/aaveV3/IAaveV3Oracle.sol b/packages/modulekit/src/integrations/interfaces/aaveV3/IAaveV3Oracle.sol similarity index 100% rename from src/integrations/interfaces/aaveV3/IAaveV3Oracle.sol rename to packages/modulekit/src/integrations/interfaces/aaveV3/IAaveV3Oracle.sol diff --git a/src/integrations/interfaces/aaveV3/IL2PoolV3.sol b/packages/modulekit/src/integrations/interfaces/aaveV3/IL2PoolV3.sol similarity index 100% rename from src/integrations/interfaces/aaveV3/IL2PoolV3.sol rename to packages/modulekit/src/integrations/interfaces/aaveV3/IL2PoolV3.sol diff --git a/src/integrations/interfaces/aaveV3/IPoolAddressesProvider.sol b/packages/modulekit/src/integrations/interfaces/aaveV3/IPoolAddressesProvider.sol similarity index 100% rename from src/integrations/interfaces/aaveV3/IPoolAddressesProvider.sol rename to packages/modulekit/src/integrations/interfaces/aaveV3/IPoolAddressesProvider.sol diff --git a/src/integrations/interfaces/aaveV3/IPoolV3.sol b/packages/modulekit/src/integrations/interfaces/aaveV3/IPoolV3.sol similarity index 100% rename from src/integrations/interfaces/aaveV3/IPoolV3.sol rename to packages/modulekit/src/integrations/interfaces/aaveV3/IPoolV3.sol diff --git a/src/integrations/interfaces/aaveV3/IPriceOracleGetter.sol b/packages/modulekit/src/integrations/interfaces/aaveV3/IPriceOracleGetter.sol similarity index 100% rename from src/integrations/interfaces/aaveV3/IPriceOracleGetter.sol rename to packages/modulekit/src/integrations/interfaces/aaveV3/IPriceOracleGetter.sol diff --git a/src/integrations/interfaces/aaveV3/IPriceOracleSentinel.sol b/packages/modulekit/src/integrations/interfaces/aaveV3/IPriceOracleSentinel.sol similarity index 100% rename from src/integrations/interfaces/aaveV3/IPriceOracleSentinel.sol rename to packages/modulekit/src/integrations/interfaces/aaveV3/IPriceOracleSentinel.sol diff --git a/src/integrations/interfaces/aaveV3/IRewardsController.sol b/packages/modulekit/src/integrations/interfaces/aaveV3/IRewardsController.sol similarity index 100% rename from src/integrations/interfaces/aaveV3/IRewardsController.sol rename to packages/modulekit/src/integrations/interfaces/aaveV3/IRewardsController.sol diff --git a/src/integrations/interfaces/aaveV3/IRewardsDistributor.sol b/packages/modulekit/src/integrations/interfaces/aaveV3/IRewardsDistributor.sol similarity index 100% rename from src/integrations/interfaces/aaveV3/IRewardsDistributor.sol rename to packages/modulekit/src/integrations/interfaces/aaveV3/IRewardsDistributor.sol diff --git a/src/integrations/interfaces/balancer/IFlashLoanRecipient.sol b/packages/modulekit/src/integrations/interfaces/balancer/IFlashLoanRecipient.sol similarity index 100% rename from src/integrations/interfaces/balancer/IFlashLoanRecipient.sol rename to packages/modulekit/src/integrations/interfaces/balancer/IFlashLoanRecipient.sol diff --git a/src/integrations/interfaces/balancer/IFlashLoans.sol b/packages/modulekit/src/integrations/interfaces/balancer/IFlashLoans.sol similarity index 100% rename from src/integrations/interfaces/balancer/IFlashLoans.sol rename to packages/modulekit/src/integrations/interfaces/balancer/IFlashLoans.sol diff --git a/src/integrations/interfaces/balancer/IMerkleRedeem.sol b/packages/modulekit/src/integrations/interfaces/balancer/IMerkleRedeem.sol similarity index 100% rename from src/integrations/interfaces/balancer/IMerkleRedeem.sol rename to packages/modulekit/src/integrations/interfaces/balancer/IMerkleRedeem.sol diff --git a/src/integrations/interfaces/balancer/IPool.sol b/packages/modulekit/src/integrations/interfaces/balancer/IPool.sol similarity index 100% rename from src/integrations/interfaces/balancer/IPool.sol rename to packages/modulekit/src/integrations/interfaces/balancer/IPool.sol diff --git a/src/integrations/interfaces/balancer/IVault.sol b/packages/modulekit/src/integrations/interfaces/balancer/IVault.sol similarity index 100% rename from src/integrations/interfaces/balancer/IVault.sol rename to packages/modulekit/src/integrations/interfaces/balancer/IVault.sol diff --git a/src/integrations/interfaces/bprotocol/IBAMM.sol b/packages/modulekit/src/integrations/interfaces/bprotocol/IBAMM.sol similarity index 100% rename from src/integrations/interfaces/bprotocol/IBAMM.sol rename to packages/modulekit/src/integrations/interfaces/bprotocol/IBAMM.sol diff --git a/src/integrations/interfaces/chainlink/IAggregatorV3.sol b/packages/modulekit/src/integrations/interfaces/chainlink/IAggregatorV3.sol similarity index 100% rename from src/integrations/interfaces/chainlink/IAggregatorV3.sol rename to packages/modulekit/src/integrations/interfaces/chainlink/IAggregatorV3.sol diff --git a/src/integrations/interfaces/chainlink/IFeedRegistry.sol b/packages/modulekit/src/integrations/interfaces/chainlink/IFeedRegistry.sol similarity index 100% rename from src/integrations/interfaces/chainlink/IFeedRegistry.sol rename to packages/modulekit/src/integrations/interfaces/chainlink/IFeedRegistry.sol diff --git a/src/integrations/interfaces/chainlink/IPhaseAggregator.sol b/packages/modulekit/src/integrations/interfaces/chainlink/IPhaseAggregator.sol similarity index 100% rename from src/integrations/interfaces/chainlink/IPhaseAggregator.sol rename to packages/modulekit/src/integrations/interfaces/chainlink/IPhaseAggregator.sol diff --git a/src/integrations/interfaces/compound/ICToken.sol b/packages/modulekit/src/integrations/interfaces/compound/ICToken.sol similarity index 100% rename from src/integrations/interfaces/compound/ICToken.sol rename to packages/modulekit/src/integrations/interfaces/compound/ICToken.sol diff --git a/src/integrations/interfaces/compound/ICompoundOracle.sol b/packages/modulekit/src/integrations/interfaces/compound/ICompoundOracle.sol similarity index 100% rename from src/integrations/interfaces/compound/ICompoundOracle.sol rename to packages/modulekit/src/integrations/interfaces/compound/ICompoundOracle.sol diff --git a/src/integrations/interfaces/compound/IComptroller.sol b/packages/modulekit/src/integrations/interfaces/compound/IComptroller.sol similarity index 100% rename from src/integrations/interfaces/compound/IComptroller.sol rename to packages/modulekit/src/integrations/interfaces/compound/IComptroller.sol diff --git a/src/integrations/interfaces/compoundV3/IComet.sol b/packages/modulekit/src/integrations/interfaces/compoundV3/IComet.sol similarity index 100% rename from src/integrations/interfaces/compoundV3/IComet.sol rename to packages/modulekit/src/integrations/interfaces/compoundV3/IComet.sol diff --git a/src/integrations/interfaces/compoundV3/ICometExt.sol b/packages/modulekit/src/integrations/interfaces/compoundV3/ICometExt.sol similarity index 100% rename from src/integrations/interfaces/compoundV3/ICometExt.sol rename to packages/modulekit/src/integrations/interfaces/compoundV3/ICometExt.sol diff --git a/src/integrations/interfaces/compoundV3/ICometRewards.sol b/packages/modulekit/src/integrations/interfaces/compoundV3/ICometRewards.sol similarity index 100% rename from src/integrations/interfaces/compoundV3/ICometRewards.sol rename to packages/modulekit/src/integrations/interfaces/compoundV3/ICometRewards.sol diff --git a/src/integrations/interfaces/convex/IBaseRewardPool.sol b/packages/modulekit/src/integrations/interfaces/convex/IBaseRewardPool.sol similarity index 100% rename from src/integrations/interfaces/convex/IBaseRewardPool.sol rename to packages/modulekit/src/integrations/interfaces/convex/IBaseRewardPool.sol diff --git a/src/integrations/interfaces/convex/IBooster.sol b/packages/modulekit/src/integrations/interfaces/convex/IBooster.sol similarity index 100% rename from src/integrations/interfaces/convex/IBooster.sol rename to packages/modulekit/src/integrations/interfaces/convex/IBooster.sol diff --git a/src/integrations/interfaces/convex/IConvexToken.sol b/packages/modulekit/src/integrations/interfaces/convex/IConvexToken.sol similarity index 100% rename from src/integrations/interfaces/convex/IConvexToken.sol rename to packages/modulekit/src/integrations/interfaces/convex/IConvexToken.sol diff --git a/src/integrations/interfaces/convex/IRewardPool.sol b/packages/modulekit/src/integrations/interfaces/convex/IRewardPool.sol similarity index 100% rename from src/integrations/interfaces/convex/IRewardPool.sol rename to packages/modulekit/src/integrations/interfaces/convex/IRewardPool.sol diff --git a/src/integrations/interfaces/curve/IAddressProvider.sol b/packages/modulekit/src/integrations/interfaces/curve/IAddressProvider.sol similarity index 100% rename from src/integrations/interfaces/curve/IAddressProvider.sol rename to packages/modulekit/src/integrations/interfaces/curve/IAddressProvider.sol diff --git a/src/integrations/interfaces/curve/ICurve3PoolZap.sol b/packages/modulekit/src/integrations/interfaces/curve/ICurve3PoolZap.sol similarity index 100% rename from src/integrations/interfaces/curve/ICurve3PoolZap.sol rename to packages/modulekit/src/integrations/interfaces/curve/ICurve3PoolZap.sol diff --git a/src/integrations/interfaces/curve/ICurveFactory.sol b/packages/modulekit/src/integrations/interfaces/curve/ICurveFactory.sol similarity index 100% rename from src/integrations/interfaces/curve/ICurveFactory.sol rename to packages/modulekit/src/integrations/interfaces/curve/ICurveFactory.sol diff --git a/src/integrations/interfaces/curve/IDepositZap.sol b/packages/modulekit/src/integrations/interfaces/curve/IDepositZap.sol similarity index 100% rename from src/integrations/interfaces/curve/IDepositZap.sol rename to packages/modulekit/src/integrations/interfaces/curve/IDepositZap.sol diff --git a/src/integrations/interfaces/curve/IFeeDistributor.sol b/packages/modulekit/src/integrations/interfaces/curve/IFeeDistributor.sol similarity index 100% rename from src/integrations/interfaces/curve/IFeeDistributor.sol rename to packages/modulekit/src/integrations/interfaces/curve/IFeeDistributor.sol diff --git a/src/integrations/interfaces/curve/ILiquidityGauge.sol b/packages/modulekit/src/integrations/interfaces/curve/ILiquidityGauge.sol similarity index 100% rename from src/integrations/interfaces/curve/ILiquidityGauge.sol rename to packages/modulekit/src/integrations/interfaces/curve/ILiquidityGauge.sol diff --git a/src/integrations/interfaces/curve/IMinter.sol b/packages/modulekit/src/integrations/interfaces/curve/IMinter.sol similarity index 100% rename from src/integrations/interfaces/curve/IMinter.sol rename to packages/modulekit/src/integrations/interfaces/curve/IMinter.sol diff --git a/src/integrations/interfaces/curve/IRegistry.sol b/packages/modulekit/src/integrations/interfaces/curve/IRegistry.sol similarity index 100% rename from src/integrations/interfaces/curve/IRegistry.sol rename to packages/modulekit/src/integrations/interfaces/curve/IRegistry.sol diff --git a/src/integrations/interfaces/curve/ISwaps.sol b/packages/modulekit/src/integrations/interfaces/curve/ISwaps.sol similarity index 100% rename from src/integrations/interfaces/curve/ISwaps.sol rename to packages/modulekit/src/integrations/interfaces/curve/ISwaps.sol diff --git a/src/integrations/interfaces/curve/IVotingEscrow.sol b/packages/modulekit/src/integrations/interfaces/curve/IVotingEscrow.sol similarity index 100% rename from src/integrations/interfaces/curve/IVotingEscrow.sol rename to packages/modulekit/src/integrations/interfaces/curve/IVotingEscrow.sol diff --git a/src/integrations/interfaces/curve/stethPool/ICurveStethPool.sol b/packages/modulekit/src/integrations/interfaces/curve/stethPool/ICurveStethPool.sol similarity index 100% rename from src/integrations/interfaces/curve/stethPool/ICurveStethPool.sol rename to packages/modulekit/src/integrations/interfaces/curve/stethPool/ICurveStethPool.sol diff --git a/src/integrations/interfaces/curveusd/ICurveUsd.sol b/packages/modulekit/src/integrations/interfaces/curveusd/ICurveUsd.sol similarity index 100% rename from src/integrations/interfaces/curveusd/ICurveUsd.sol rename to packages/modulekit/src/integrations/interfaces/curveusd/ICurveUsd.sol diff --git a/src/integrations/interfaces/dydx/ISoloMargin.sol b/packages/modulekit/src/integrations/interfaces/dydx/ISoloMargin.sol similarity index 100% rename from src/integrations/interfaces/dydx/ISoloMargin.sol rename to packages/modulekit/src/integrations/interfaces/dydx/ISoloMargin.sol diff --git a/src/integrations/interfaces/euler/IDToken.sol b/packages/modulekit/src/integrations/interfaces/euler/IDToken.sol similarity index 100% rename from src/integrations/interfaces/euler/IDToken.sol rename to packages/modulekit/src/integrations/interfaces/euler/IDToken.sol diff --git a/src/integrations/interfaces/euler/IEulerMarkets.sol b/packages/modulekit/src/integrations/interfaces/euler/IEulerMarkets.sol similarity index 100% rename from src/integrations/interfaces/euler/IEulerMarkets.sol rename to packages/modulekit/src/integrations/interfaces/euler/IEulerMarkets.sol diff --git a/src/integrations/interfaces/exchange/IExchangeV3.sol b/packages/modulekit/src/integrations/interfaces/exchange/IExchangeV3.sol similarity index 100% rename from src/integrations/interfaces/exchange/IExchangeV3.sol rename to packages/modulekit/src/integrations/interfaces/exchange/IExchangeV3.sol diff --git a/src/integrations/interfaces/exchange/IExchangeWrapper.sol b/packages/modulekit/src/integrations/interfaces/exchange/IExchangeWrapper.sol similarity index 100% rename from src/integrations/interfaces/exchange/IExchangeWrapper.sol rename to packages/modulekit/src/integrations/interfaces/exchange/IExchangeWrapper.sol diff --git a/src/integrations/interfaces/exchange/IKyberNetworkProxy.sol b/packages/modulekit/src/integrations/interfaces/exchange/IKyberNetworkProxy.sol similarity index 100% rename from src/integrations/interfaces/exchange/IKyberNetworkProxy.sol rename to packages/modulekit/src/integrations/interfaces/exchange/IKyberNetworkProxy.sol diff --git a/src/integrations/interfaces/exchange/IOasis.sol b/packages/modulekit/src/integrations/interfaces/exchange/IOasis.sol similarity index 100% rename from src/integrations/interfaces/exchange/IOasis.sol rename to packages/modulekit/src/integrations/interfaces/exchange/IOasis.sol diff --git a/src/integrations/interfaces/exchange/IOffchainWrapper.sol.bak b/packages/modulekit/src/integrations/interfaces/exchange/IOffchainWrapper.sol.bak similarity index 100% rename from src/integrations/interfaces/exchange/IOffchainWrapper.sol.bak rename to packages/modulekit/src/integrations/interfaces/exchange/IOffchainWrapper.sol.bak diff --git a/src/integrations/interfaces/exchange/IPair.sol b/packages/modulekit/src/integrations/interfaces/exchange/IPair.sol similarity index 100% rename from src/integrations/interfaces/exchange/IPair.sol rename to packages/modulekit/src/integrations/interfaces/exchange/IPair.sol diff --git a/src/integrations/interfaces/exchange/IQuoter.sol b/packages/modulekit/src/integrations/interfaces/exchange/IQuoter.sol similarity index 100% rename from src/integrations/interfaces/exchange/IQuoter.sol rename to packages/modulekit/src/integrations/interfaces/exchange/IQuoter.sol diff --git a/src/integrations/interfaces/exchange/ISwapRouter.sol b/packages/modulekit/src/integrations/interfaces/exchange/ISwapRouter.sol similarity index 100% rename from src/integrations/interfaces/exchange/ISwapRouter.sol rename to packages/modulekit/src/integrations/interfaces/exchange/ISwapRouter.sol diff --git a/src/integrations/interfaces/exchange/IUniswapRouter.sol b/packages/modulekit/src/integrations/interfaces/exchange/IUniswapRouter.sol similarity index 100% rename from src/integrations/interfaces/exchange/IUniswapRouter.sol rename to packages/modulekit/src/integrations/interfaces/exchange/IUniswapRouter.sol diff --git a/src/integrations/interfaces/flashloan/IERC3156FlashBorrower.sol b/packages/modulekit/src/integrations/interfaces/flashloan/IERC3156FlashBorrower.sol similarity index 100% rename from src/integrations/interfaces/flashloan/IERC3156FlashBorrower.sol rename to packages/modulekit/src/integrations/interfaces/flashloan/IERC3156FlashBorrower.sol diff --git a/src/integrations/interfaces/flashloan/IERC3156FlashLender.sol b/packages/modulekit/src/integrations/interfaces/flashloan/IERC3156FlashLender.sol similarity index 100% rename from src/integrations/interfaces/flashloan/IERC3156FlashLender.sol rename to packages/modulekit/src/integrations/interfaces/flashloan/IERC3156FlashLender.sol diff --git a/src/integrations/interfaces/flashloan/IFlashLoanBase.sol b/packages/modulekit/src/integrations/interfaces/flashloan/IFlashLoanBase.sol similarity index 100% rename from src/integrations/interfaces/flashloan/IFlashLoanBase.sol rename to packages/modulekit/src/integrations/interfaces/flashloan/IFlashLoanBase.sol diff --git a/src/integrations/interfaces/guni/IGUniPool.sol b/packages/modulekit/src/integrations/interfaces/guni/IGUniPool.sol similarity index 100% rename from src/integrations/interfaces/guni/IGUniPool.sol rename to packages/modulekit/src/integrations/interfaces/guni/IGUniPool.sol diff --git a/src/integrations/interfaces/guni/IGUniRouter02.sol b/packages/modulekit/src/integrations/interfaces/guni/IGUniRouter02.sol similarity index 100% rename from src/integrations/interfaces/guni/IGUniRouter02.sol rename to packages/modulekit/src/integrations/interfaces/guni/IGUniRouter02.sol diff --git a/src/integrations/interfaces/insta/IInstaAccountV2.sol b/packages/modulekit/src/integrations/interfaces/insta/IInstaAccountV2.sol similarity index 100% rename from src/integrations/interfaces/insta/IInstaAccountV2.sol rename to packages/modulekit/src/integrations/interfaces/insta/IInstaAccountV2.sol diff --git a/src/integrations/interfaces/insta/IInstaIndex.sol b/packages/modulekit/src/integrations/interfaces/insta/IInstaIndex.sol similarity index 100% rename from src/integrations/interfaces/insta/IInstaIndex.sol rename to packages/modulekit/src/integrations/interfaces/insta/IInstaIndex.sol diff --git a/src/integrations/interfaces/insta/IInstaMakerDAOMerkleDistributor.sol b/packages/modulekit/src/integrations/interfaces/insta/IInstaMakerDAOMerkleDistributor.sol similarity index 100% rename from src/integrations/interfaces/insta/IInstaMakerDAOMerkleDistributor.sol rename to packages/modulekit/src/integrations/interfaces/insta/IInstaMakerDAOMerkleDistributor.sol diff --git a/src/integrations/interfaces/kyber/IAggregationExecutor.sol b/packages/modulekit/src/integrations/interfaces/kyber/IAggregationExecutor.sol similarity index 100% rename from src/integrations/interfaces/kyber/IAggregationExecutor.sol rename to packages/modulekit/src/integrations/interfaces/kyber/IAggregationExecutor.sol diff --git a/src/integrations/interfaces/kyber/IExecutorHelper.sol b/packages/modulekit/src/integrations/interfaces/kyber/IExecutorHelper.sol similarity index 100% rename from src/integrations/interfaces/kyber/IExecutorHelper.sol rename to packages/modulekit/src/integrations/interfaces/kyber/IExecutorHelper.sol diff --git a/src/integrations/interfaces/kyber/IMetaAggregationRouterV2.sol b/packages/modulekit/src/integrations/interfaces/kyber/IMetaAggregationRouterV2.sol similarity index 100% rename from src/integrations/interfaces/kyber/IMetaAggregationRouterV2.sol rename to packages/modulekit/src/integrations/interfaces/kyber/IMetaAggregationRouterV2.sol diff --git a/src/integrations/interfaces/lido/IWStEth.sol b/packages/modulekit/src/integrations/interfaces/lido/IWStEth.sol similarity index 100% rename from src/integrations/interfaces/lido/IWStEth.sol rename to packages/modulekit/src/integrations/interfaces/lido/IWStEth.sol diff --git a/src/integrations/interfaces/liquity/IBondNFT.sol b/packages/modulekit/src/integrations/interfaces/liquity/IBondNFT.sol similarity index 100% rename from src/integrations/interfaces/liquity/IBondNFT.sol rename to packages/modulekit/src/integrations/interfaces/liquity/IBondNFT.sol diff --git a/src/integrations/interfaces/liquity/IBondNFTArtwork.sol b/packages/modulekit/src/integrations/interfaces/liquity/IBondNFTArtwork.sol similarity index 100% rename from src/integrations/interfaces/liquity/IBondNFTArtwork.sol rename to packages/modulekit/src/integrations/interfaces/liquity/IBondNFTArtwork.sol diff --git a/src/integrations/interfaces/liquity/IBorrowerOperations.sol b/packages/modulekit/src/integrations/interfaces/liquity/IBorrowerOperations.sol similarity index 100% rename from src/integrations/interfaces/liquity/IBorrowerOperations.sol rename to packages/modulekit/src/integrations/interfaces/liquity/IBorrowerOperations.sol diff --git a/src/integrations/interfaces/liquity/IChickenBondManager.sol b/packages/modulekit/src/integrations/interfaces/liquity/IChickenBondManager.sol similarity index 100% rename from src/integrations/interfaces/liquity/IChickenBondManager.sol rename to packages/modulekit/src/integrations/interfaces/liquity/IChickenBondManager.sol diff --git a/src/integrations/interfaces/liquity/ICollSurplusPool.sol b/packages/modulekit/src/integrations/interfaces/liquity/ICollSurplusPool.sol similarity index 100% rename from src/integrations/interfaces/liquity/ICollSurplusPool.sol rename to packages/modulekit/src/integrations/interfaces/liquity/ICollSurplusPool.sol diff --git a/src/integrations/interfaces/liquity/IHintHelpers.sol b/packages/modulekit/src/integrations/interfaces/liquity/IHintHelpers.sol similarity index 100% rename from src/integrations/interfaces/liquity/IHintHelpers.sol rename to packages/modulekit/src/integrations/interfaces/liquity/IHintHelpers.sol diff --git a/src/integrations/interfaces/liquity/ILQTYStaking.sol b/packages/modulekit/src/integrations/interfaces/liquity/ILQTYStaking.sol similarity index 100% rename from src/integrations/interfaces/liquity/ILQTYStaking.sol rename to packages/modulekit/src/integrations/interfaces/liquity/ILQTYStaking.sol diff --git a/src/integrations/interfaces/liquity/IPriceFeed.sol b/packages/modulekit/src/integrations/interfaces/liquity/IPriceFeed.sol similarity index 100% rename from src/integrations/interfaces/liquity/IPriceFeed.sol rename to packages/modulekit/src/integrations/interfaces/liquity/IPriceFeed.sol diff --git a/src/integrations/interfaces/liquity/ISortedTroves.sol b/packages/modulekit/src/integrations/interfaces/liquity/ISortedTroves.sol similarity index 100% rename from src/integrations/interfaces/liquity/ISortedTroves.sol rename to packages/modulekit/src/integrations/interfaces/liquity/ISortedTroves.sol diff --git a/src/integrations/interfaces/liquity/IStabilityPool.sol b/packages/modulekit/src/integrations/interfaces/liquity/IStabilityPool.sol similarity index 100% rename from src/integrations/interfaces/liquity/IStabilityPool.sol rename to packages/modulekit/src/integrations/interfaces/liquity/IStabilityPool.sol diff --git a/src/integrations/interfaces/liquity/ITroveManager.sol b/packages/modulekit/src/integrations/interfaces/liquity/ITroveManager.sol similarity index 100% rename from src/integrations/interfaces/liquity/ITroveManager.sol rename to packages/modulekit/src/integrations/interfaces/liquity/ITroveManager.sol diff --git a/src/integrations/interfaces/mcd/ICat.sol b/packages/modulekit/src/integrations/interfaces/mcd/ICat.sol similarity index 100% rename from src/integrations/interfaces/mcd/ICat.sol rename to packages/modulekit/src/integrations/interfaces/mcd/ICat.sol diff --git a/src/integrations/interfaces/mcd/ICdpRegistry.sol b/packages/modulekit/src/integrations/interfaces/mcd/ICdpRegistry.sol similarity index 100% rename from src/integrations/interfaces/mcd/ICdpRegistry.sol rename to packages/modulekit/src/integrations/interfaces/mcd/ICdpRegistry.sol diff --git a/src/integrations/interfaces/mcd/ICropJoin.sol b/packages/modulekit/src/integrations/interfaces/mcd/ICropJoin.sol similarity index 100% rename from src/integrations/interfaces/mcd/ICropJoin.sol rename to packages/modulekit/src/integrations/interfaces/mcd/ICropJoin.sol diff --git a/src/integrations/interfaces/mcd/ICropper.sol b/packages/modulekit/src/integrations/interfaces/mcd/ICropper.sol similarity index 100% rename from src/integrations/interfaces/mcd/ICropper.sol rename to packages/modulekit/src/integrations/interfaces/mcd/ICropper.sol diff --git a/src/integrations/interfaces/mcd/IDSPause.sol b/packages/modulekit/src/integrations/interfaces/mcd/IDSPause.sol similarity index 100% rename from src/integrations/interfaces/mcd/IDSPause.sol rename to packages/modulekit/src/integrations/interfaces/mcd/IDSPause.sol diff --git a/src/integrations/interfaces/mcd/IDaiJoin.sol b/packages/modulekit/src/integrations/interfaces/mcd/IDaiJoin.sol similarity index 100% rename from src/integrations/interfaces/mcd/IDaiJoin.sol rename to packages/modulekit/src/integrations/interfaces/mcd/IDaiJoin.sol diff --git a/src/integrations/interfaces/mcd/IDssSpell.sol b/packages/modulekit/src/integrations/interfaces/mcd/IDssSpell.sol similarity index 100% rename from src/integrations/interfaces/mcd/IDssSpell.sol rename to packages/modulekit/src/integrations/interfaces/mcd/IDssSpell.sol diff --git a/src/integrations/interfaces/mcd/IGem.sol b/packages/modulekit/src/integrations/interfaces/mcd/IGem.sol similarity index 100% rename from src/integrations/interfaces/mcd/IGem.sol rename to packages/modulekit/src/integrations/interfaces/mcd/IGem.sol diff --git a/src/integrations/interfaces/mcd/IGetCdps.sol b/packages/modulekit/src/integrations/interfaces/mcd/IGetCdps.sol similarity index 100% rename from src/integrations/interfaces/mcd/IGetCdps.sol rename to packages/modulekit/src/integrations/interfaces/mcd/IGetCdps.sol diff --git a/src/integrations/interfaces/mcd/IJoin.sol b/packages/modulekit/src/integrations/interfaces/mcd/IJoin.sol similarity index 100% rename from src/integrations/interfaces/mcd/IJoin.sol rename to packages/modulekit/src/integrations/interfaces/mcd/IJoin.sol diff --git a/src/integrations/interfaces/mcd/IJug.sol b/packages/modulekit/src/integrations/interfaces/mcd/IJug.sol similarity index 100% rename from src/integrations/interfaces/mcd/IJug.sol rename to packages/modulekit/src/integrations/interfaces/mcd/IJug.sol diff --git a/src/integrations/interfaces/mcd/IManager.sol b/packages/modulekit/src/integrations/interfaces/mcd/IManager.sol similarity index 100% rename from src/integrations/interfaces/mcd/IManager.sol rename to packages/modulekit/src/integrations/interfaces/mcd/IManager.sol diff --git a/src/integrations/interfaces/mcd/IOsm.sol b/packages/modulekit/src/integrations/interfaces/mcd/IOsm.sol similarity index 100% rename from src/integrations/interfaces/mcd/IOsm.sol rename to packages/modulekit/src/integrations/interfaces/mcd/IOsm.sol diff --git a/src/integrations/interfaces/mcd/IPipInterface.sol b/packages/modulekit/src/integrations/interfaces/mcd/IPipInterface.sol similarity index 100% rename from src/integrations/interfaces/mcd/IPipInterface.sol rename to packages/modulekit/src/integrations/interfaces/mcd/IPipInterface.sol diff --git a/src/integrations/interfaces/mcd/IPot.sol b/packages/modulekit/src/integrations/interfaces/mcd/IPot.sol similarity index 100% rename from src/integrations/interfaces/mcd/IPot.sol rename to packages/modulekit/src/integrations/interfaces/mcd/IPot.sol diff --git a/src/integrations/interfaces/mcd/ISpotter.sol b/packages/modulekit/src/integrations/interfaces/mcd/ISpotter.sol similarity index 100% rename from src/integrations/interfaces/mcd/ISpotter.sol rename to packages/modulekit/src/integrations/interfaces/mcd/ISpotter.sol diff --git a/src/integrations/interfaces/mcd/IVat.sol b/packages/modulekit/src/integrations/interfaces/mcd/IVat.sol similarity index 100% rename from src/integrations/interfaces/mcd/IVat.sol rename to packages/modulekit/src/integrations/interfaces/mcd/IVat.sol diff --git a/src/integrations/interfaces/morpho/IMorpho.sol b/packages/modulekit/src/integrations/interfaces/morpho/IMorpho.sol similarity index 100% rename from src/integrations/interfaces/morpho/IMorpho.sol rename to packages/modulekit/src/integrations/interfaces/morpho/IMorpho.sol diff --git a/src/integrations/interfaces/morpho/IMorphoAaveV2Lens.sol b/packages/modulekit/src/integrations/interfaces/morpho/IMorphoAaveV2Lens.sol similarity index 99% rename from src/integrations/interfaces/morpho/IMorphoAaveV2Lens.sol rename to packages/modulekit/src/integrations/interfaces/morpho/IMorphoAaveV2Lens.sol index 36b1ac05..06303636 100644 --- a/src/integrations/interfaces/morpho/IMorphoAaveV2Lens.sol +++ b/packages/modulekit/src/integrations/interfaces/morpho/IMorphoAaveV2Lens.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GNU AGPLv3 -pragma solidity >=0.5.0; +pragma solidity >=0.8.0; import "./MorphoTypes.sol"; diff --git a/src/integrations/interfaces/morpho/IMorphoAaveV3.sol b/packages/modulekit/src/integrations/interfaces/morpho/IMorphoAaveV3.sol similarity index 100% rename from src/integrations/interfaces/morpho/IMorphoAaveV3.sol rename to packages/modulekit/src/integrations/interfaces/morpho/IMorphoAaveV3.sol diff --git a/src/integrations/interfaces/morpho/IRewardsDistributor.sol b/packages/modulekit/src/integrations/interfaces/morpho/IRewardsDistributor.sol similarity index 100% rename from src/integrations/interfaces/morpho/IRewardsDistributor.sol rename to packages/modulekit/src/integrations/interfaces/morpho/IRewardsDistributor.sol diff --git a/src/integrations/interfaces/morpho/MorphoTypes.sol b/packages/modulekit/src/integrations/interfaces/morpho/MorphoTypes.sol similarity index 100% rename from src/integrations/interfaces/morpho/MorphoTypes.sol rename to packages/modulekit/src/integrations/interfaces/morpho/MorphoTypes.sol diff --git a/src/integrations/interfaces/morpho/MorphoTypesAaveV3.sol b/packages/modulekit/src/integrations/interfaces/morpho/MorphoTypesAaveV3.sol similarity index 100% rename from src/integrations/interfaces/morpho/MorphoTypesAaveV3.sol rename to packages/modulekit/src/integrations/interfaces/morpho/MorphoTypesAaveV3.sol diff --git a/src/integrations/interfaces/mstable/IBoostedVaultWithLockup.sol b/packages/modulekit/src/integrations/interfaces/mstable/IBoostedVaultWithLockup.sol similarity index 100% rename from src/integrations/interfaces/mstable/IBoostedVaultWithLockup.sol rename to packages/modulekit/src/integrations/interfaces/mstable/IBoostedVaultWithLockup.sol diff --git a/src/integrations/interfaces/mstable/ISavingsContractV2.sol b/packages/modulekit/src/integrations/interfaces/mstable/ISavingsContractV2.sol similarity index 100% rename from src/integrations/interfaces/mstable/ISavingsContractV2.sol rename to packages/modulekit/src/integrations/interfaces/mstable/ISavingsContractV2.sol diff --git a/src/integrations/interfaces/mstable/ImAsset.sol b/packages/modulekit/src/integrations/interfaces/mstable/ImAsset.sol similarity index 100% rename from src/integrations/interfaces/mstable/ImAsset.sol rename to packages/modulekit/src/integrations/interfaces/mstable/ImAsset.sol diff --git a/src/integrations/interfaces/qidao/IQiDaoRegistry.sol b/packages/modulekit/src/integrations/interfaces/qidao/IQiDaoRegistry.sol similarity index 100% rename from src/integrations/interfaces/qidao/IQiDaoRegistry.sol rename to packages/modulekit/src/integrations/interfaces/qidao/IQiDaoRegistry.sol diff --git a/src/integrations/interfaces/qidao/IStablecoin.sol b/packages/modulekit/src/integrations/interfaces/qidao/IStablecoin.sol similarity index 100% rename from src/integrations/interfaces/qidao/IStablecoin.sol rename to packages/modulekit/src/integrations/interfaces/qidao/IStablecoin.sol diff --git a/src/integrations/interfaces/rari/IFundController.sol b/packages/modulekit/src/integrations/interfaces/rari/IFundController.sol similarity index 100% rename from src/integrations/interfaces/rari/IFundController.sol rename to packages/modulekit/src/integrations/interfaces/rari/IFundController.sol diff --git a/src/integrations/interfaces/rari/IFundManager.sol b/packages/modulekit/src/integrations/interfaces/rari/IFundManager.sol similarity index 100% rename from src/integrations/interfaces/rari/IFundManager.sol rename to packages/modulekit/src/integrations/interfaces/rari/IFundManager.sol diff --git a/src/integrations/interfaces/rari/IFundProxy.sol b/packages/modulekit/src/integrations/interfaces/rari/IFundProxy.sol similarity index 100% rename from src/integrations/interfaces/rari/IFundProxy.sol rename to packages/modulekit/src/integrations/interfaces/rari/IFundProxy.sol diff --git a/src/integrations/interfaces/rari/IFuseAsset.sol b/packages/modulekit/src/integrations/interfaces/rari/IFuseAsset.sol similarity index 100% rename from src/integrations/interfaces/rari/IFuseAsset.sol rename to packages/modulekit/src/integrations/interfaces/rari/IFuseAsset.sol diff --git a/src/integrations/interfaces/reflexer/IBasicTokenAdapters.sol b/packages/modulekit/src/integrations/interfaces/reflexer/IBasicTokenAdapters.sol similarity index 100% rename from src/integrations/interfaces/reflexer/IBasicTokenAdapters.sol rename to packages/modulekit/src/integrations/interfaces/reflexer/IBasicTokenAdapters.sol diff --git a/src/integrations/interfaces/reflexer/ICoinJoin.sol b/packages/modulekit/src/integrations/interfaces/reflexer/ICoinJoin.sol similarity index 100% rename from src/integrations/interfaces/reflexer/ICoinJoin.sol rename to packages/modulekit/src/integrations/interfaces/reflexer/ICoinJoin.sol diff --git a/src/integrations/interfaces/reflexer/IFSMWrapper.sol b/packages/modulekit/src/integrations/interfaces/reflexer/IFSMWrapper.sol similarity index 100% rename from src/integrations/interfaces/reflexer/IFSMWrapper.sol rename to packages/modulekit/src/integrations/interfaces/reflexer/IFSMWrapper.sol diff --git a/src/integrations/interfaces/reflexer/IGetSafes.sol b/packages/modulekit/src/integrations/interfaces/reflexer/IGetSafes.sol similarity index 100% rename from src/integrations/interfaces/reflexer/IGetSafes.sol rename to packages/modulekit/src/integrations/interfaces/reflexer/IGetSafes.sol diff --git a/src/integrations/interfaces/reflexer/IMedianOracle.sol b/packages/modulekit/src/integrations/interfaces/reflexer/IMedianOracle.sol similarity index 100% rename from src/integrations/interfaces/reflexer/IMedianOracle.sol rename to packages/modulekit/src/integrations/interfaces/reflexer/IMedianOracle.sol diff --git a/src/integrations/interfaces/reflexer/IOracleRelayer.sol b/packages/modulekit/src/integrations/interfaces/reflexer/IOracleRelayer.sol similarity index 100% rename from src/integrations/interfaces/reflexer/IOracleRelayer.sol rename to packages/modulekit/src/integrations/interfaces/reflexer/IOracleRelayer.sol diff --git a/src/integrations/interfaces/reflexer/ISAFEEngine.sol b/packages/modulekit/src/integrations/interfaces/reflexer/ISAFEEngine.sol similarity index 100% rename from src/integrations/interfaces/reflexer/ISAFEEngine.sol rename to packages/modulekit/src/integrations/interfaces/reflexer/ISAFEEngine.sol diff --git a/src/integrations/interfaces/reflexer/ISAFEManager.sol b/packages/modulekit/src/integrations/interfaces/reflexer/ISAFEManager.sol similarity index 100% rename from src/integrations/interfaces/reflexer/ISAFEManager.sol rename to packages/modulekit/src/integrations/interfaces/reflexer/ISAFEManager.sol diff --git a/src/integrations/interfaces/reflexer/ISAFESaviour.sol b/packages/modulekit/src/integrations/interfaces/reflexer/ISAFESaviour.sol similarity index 100% rename from src/integrations/interfaces/reflexer/ISAFESaviour.sol rename to packages/modulekit/src/integrations/interfaces/reflexer/ISAFESaviour.sol diff --git a/src/integrations/interfaces/reflexer/ITaxCollector.sol b/packages/modulekit/src/integrations/interfaces/reflexer/ITaxCollector.sol similarity index 100% rename from src/integrations/interfaces/reflexer/ITaxCollector.sol rename to packages/modulekit/src/integrations/interfaces/reflexer/ITaxCollector.sol diff --git a/src/integrations/interfaces/spark/IsDAI.sol b/packages/modulekit/src/integrations/interfaces/spark/IsDAI.sol similarity index 100% rename from src/integrations/interfaces/spark/IsDAI.sol rename to packages/modulekit/src/integrations/interfaces/spark/IsDAI.sol diff --git a/src/integrations/interfaces/strategy/ISubStorage.sol b/packages/modulekit/src/integrations/interfaces/strategy/ISubStorage.sol similarity index 100% rename from src/integrations/interfaces/strategy/ISubStorage.sol rename to packages/modulekit/src/integrations/interfaces/strategy/ISubStorage.sol diff --git a/src/integrations/interfaces/uniswap/IUniswapV2Factory.sol b/packages/modulekit/src/integrations/interfaces/uniswap/IUniswapV2Factory.sol similarity index 100% rename from src/integrations/interfaces/uniswap/IUniswapV2Factory.sol rename to packages/modulekit/src/integrations/interfaces/uniswap/IUniswapV2Factory.sol diff --git a/src/integrations/interfaces/uniswap/IUniswapV2Pair.sol b/packages/modulekit/src/integrations/interfaces/uniswap/IUniswapV2Pair.sol similarity index 100% rename from src/integrations/interfaces/uniswap/IUniswapV2Pair.sol rename to packages/modulekit/src/integrations/interfaces/uniswap/IUniswapV2Pair.sol diff --git a/src/integrations/interfaces/uniswap/v3/IQuoter.sol b/packages/modulekit/src/integrations/interfaces/uniswap/v3/IQuoter.sol similarity index 100% rename from src/integrations/interfaces/uniswap/v3/IQuoter.sol rename to packages/modulekit/src/integrations/interfaces/uniswap/v3/IQuoter.sol diff --git a/src/integrations/interfaces/uniswap/v3/ISwapRouter.sol b/packages/modulekit/src/integrations/interfaces/uniswap/v3/ISwapRouter.sol similarity index 100% rename from src/integrations/interfaces/uniswap/v3/ISwapRouter.sol rename to packages/modulekit/src/integrations/interfaces/uniswap/v3/ISwapRouter.sol diff --git a/src/integrations/interfaces/uniswap/v3/IUniswapV3Factory.sol b/packages/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3Factory.sol similarity index 100% rename from src/integrations/interfaces/uniswap/v3/IUniswapV3Factory.sol rename to packages/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3Factory.sol diff --git a/src/integrations/interfaces/uniswap/v3/IUniswapV3FlashCallback.sol b/packages/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3FlashCallback.sol similarity index 100% rename from src/integrations/interfaces/uniswap/v3/IUniswapV3FlashCallback.sol rename to packages/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3FlashCallback.sol diff --git a/src/integrations/interfaces/uniswap/v3/IUniswapV3NonfungiblePositionManager.sol b/packages/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3NonfungiblePositionManager.sol similarity index 100% rename from src/integrations/interfaces/uniswap/v3/IUniswapV3NonfungiblePositionManager.sol rename to packages/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3NonfungiblePositionManager.sol diff --git a/src/integrations/interfaces/uniswap/v3/IUniswapV3Pool.sol b/packages/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3Pool.sol similarity index 100% rename from src/integrations/interfaces/uniswap/v3/IUniswapV3Pool.sol rename to packages/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3Pool.sol diff --git a/src/integrations/interfaces/uniswap/v3/IUniswapV3SwapCallback.sol b/packages/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3SwapCallback.sol similarity index 100% rename from src/integrations/interfaces/uniswap/v3/IUniswapV3SwapCallback.sol rename to packages/modulekit/src/integrations/interfaces/uniswap/v3/IUniswapV3SwapCallback.sol diff --git a/src/integrations/interfaces/yearn/IYVault.sol b/packages/modulekit/src/integrations/interfaces/yearn/IYVault.sol similarity index 100% rename from src/integrations/interfaces/yearn/IYVault.sol rename to packages/modulekit/src/integrations/interfaces/yearn/IYVault.sol diff --git a/src/integrations/interfaces/yearn/IYearnRegistry.sol b/packages/modulekit/src/integrations/interfaces/yearn/IYearnRegistry.sol similarity index 100% rename from src/integrations/interfaces/yearn/IYearnRegistry.sol rename to packages/modulekit/src/integrations/interfaces/yearn/IYearnRegistry.sol diff --git a/src/integrations/uniswap/MockUniswap.sol b/packages/modulekit/src/integrations/uniswap/MockUniswap.sol similarity index 100% rename from src/integrations/uniswap/MockUniswap.sol rename to packages/modulekit/src/integrations/uniswap/MockUniswap.sol diff --git a/src/integrations/uniswap/helpers/MainnetAddresses.sol b/packages/modulekit/src/integrations/uniswap/helpers/MainnetAddresses.sol similarity index 100% rename from src/integrations/uniswap/helpers/MainnetAddresses.sol rename to packages/modulekit/src/integrations/uniswap/helpers/MainnetAddresses.sol diff --git a/src/integrations/uniswap/v3/Uniswap.sol b/packages/modulekit/src/integrations/uniswap/v3/Uniswap.sol similarity index 100% rename from src/integrations/uniswap/v3/Uniswap.sol rename to packages/modulekit/src/integrations/uniswap/v3/Uniswap.sol diff --git a/src/interfaces/IERC1271.sol b/packages/modulekit/src/interfaces/IERC1271.sol similarity index 100% rename from src/interfaces/IERC1271.sol rename to packages/modulekit/src/interfaces/IERC1271.sol diff --git a/src/interfaces/IERC7484Registry.sol b/packages/modulekit/src/interfaces/IERC7484Registry.sol similarity index 100% rename from src/interfaces/IERC7484Registry.sol rename to packages/modulekit/src/interfaces/IERC7484Registry.sol diff --git a/src/mocks/MockExecutor.sol b/packages/modulekit/src/mocks/MockExecutor.sol similarity index 64% rename from src/mocks/MockExecutor.sol rename to packages/modulekit/src/mocks/MockExecutor.sol index 928e081f..9fb9b3c7 100644 --- a/src/mocks/MockExecutor.sol +++ b/packages/modulekit/src/mocks/MockExecutor.sol @@ -3,17 +3,8 @@ pragma solidity ^0.8.23; import { ERC7579ExecutorBase } from "../Modules.sol"; import { IERC7579Account } from "../external/ERC7579.sol"; -import { ModuleTypeLib, EncodedModuleTypes, ModuleType } from "erc7579/lib/ModuleTypeLib.sol"; contract MockExecutor is ERC7579ExecutorBase { - EncodedModuleTypes immutable MODULE_TYPES; - - constructor() { - ModuleType[] memory moduleTypes = new ModuleType[](1); - moduleTypes[0] = ModuleType.wrap(TYPE_EXECUTOR); - MODULE_TYPES = ModuleTypeLib.bitEncode(moduleTypes); - } - function onInstall(bytes calldata data) external override { } function onUninstall(bytes calldata data) external override { } @@ -37,8 +28,4 @@ contract MockExecutor is ERC7579ExecutorBase { function isInitialized(address smartAccount) external pure returns (bool) { return false; } - - function getModuleTypes() external view returns (EncodedModuleTypes) { - return MODULE_TYPES; - } } diff --git a/packages/modulekit/src/mocks/MockFallback.sol b/packages/modulekit/src/mocks/MockFallback.sol new file mode 100644 index 00000000..60024b3d --- /dev/null +++ b/packages/modulekit/src/mocks/MockFallback.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import { ERC7579FallbackBase } from "../Modules.sol"; + +contract MockFallback is ERC7579FallbackBase { + function onInstall(bytes calldata data) external override { } + + function onUninstall(bytes calldata data) external override { } + + function targetFunction() external returns (bool) { + return true; + } + + function isModuleType(uint256 typeID) external view returns (bool) { + return typeID == TYPE_FALLBACK; + } + + function isInitialized(address smartAccount) external view returns (bool) { + return false; + } +} diff --git a/src/mocks/MockHook.sol b/packages/modulekit/src/mocks/MockHook.sol similarity index 56% rename from src/mocks/MockHook.sol rename to packages/modulekit/src/mocks/MockHook.sol index d34331a9..e7ef64c9 100644 --- a/src/mocks/MockHook.sol +++ b/packages/modulekit/src/mocks/MockHook.sol @@ -2,17 +2,8 @@ pragma solidity ^0.8.23; import { ERC7579HookBase } from "../Modules.sol"; -import { ModuleTypeLib, EncodedModuleTypes, ModuleType } from "erc7579/lib/ModuleTypeLib.sol"; contract MockHook is ERC7579HookBase { - EncodedModuleTypes immutable MODULE_TYPES; - - constructor() { - ModuleType[] memory moduleTypes = new ModuleType[](1); - moduleTypes[0] = ModuleType.wrap(TYPE_HOOK); - MODULE_TYPES = ModuleTypeLib.bitEncode(moduleTypes); - } - function onInstall(bytes calldata data) external override { } function onUninstall(bytes calldata data) external override { } @@ -22,11 +13,12 @@ contract MockHook is ERC7579HookBase { bytes calldata msgData ) external + virtual override returns (bytes memory hookData) { } - function postCheck(bytes calldata) external override returns (bool success) { + function postCheck(bytes calldata) external virtual override returns (bool success) { return true; } @@ -37,8 +29,4 @@ contract MockHook is ERC7579HookBase { function isModuleType(uint256 typeID) external pure returns (bool) { return typeID == TYPE_HOOK; } - - function getModuleTypes() external view returns (EncodedModuleTypes) { - return MODULE_TYPES; - } } diff --git a/src/mocks/MockRegistry.sol b/packages/modulekit/src/mocks/MockRegistry.sol similarity index 100% rename from src/mocks/MockRegistry.sol rename to packages/modulekit/src/mocks/MockRegistry.sol diff --git a/src/mocks/MockSessionKeyValidator.sol.bak b/packages/modulekit/src/mocks/MockSessionKeyValidator.sol.bak similarity index 100% rename from src/mocks/MockSessionKeyValidator.sol.bak rename to packages/modulekit/src/mocks/MockSessionKeyValidator.sol.bak diff --git a/src/mocks/MockTarget.sol b/packages/modulekit/src/mocks/MockTarget.sol similarity index 100% rename from src/mocks/MockTarget.sol rename to packages/modulekit/src/mocks/MockTarget.sol diff --git a/src/mocks/MockValidator.sol b/packages/modulekit/src/mocks/MockValidator.sol similarity index 72% rename from src/mocks/MockValidator.sol rename to packages/modulekit/src/mocks/MockValidator.sol index d4490ce6..2f5f6c52 100644 --- a/src/mocks/MockValidator.sol +++ b/packages/modulekit/src/mocks/MockValidator.sol @@ -4,17 +4,8 @@ pragma solidity ^0.8.23; /* solhint-disable no-unused-vars */ import { ERC7579ValidatorBase } from "../Modules.sol"; import { PackedUserOperation } from "../external/ERC4337.sol"; -import { ModuleTypeLib, EncodedModuleTypes, ModuleType } from "erc7579/lib/ModuleTypeLib.sol"; contract MockValidator is ERC7579ValidatorBase { - EncodedModuleTypes immutable MODULE_TYPES; - - constructor() { - ModuleType[] memory moduleTypes = new ModuleType[](1); - moduleTypes[0] = ModuleType.wrap(TYPE_VALIDATOR); - MODULE_TYPES = ModuleTypeLib.bitEncode(moduleTypes); - } - function onInstall(bytes calldata data) external virtual override { } function onUninstall(bytes calldata data) external virtual override { } @@ -24,6 +15,7 @@ contract MockValidator is ERC7579ValidatorBase { bytes32 userOpHash ) external + virtual override returns (ValidationData) { @@ -38,6 +30,7 @@ contract MockValidator is ERC7579ValidatorBase { ) external view + virtual override returns (bytes4) { @@ -48,10 +41,6 @@ contract MockValidator is ERC7579ValidatorBase { return typeID == TYPE_VALIDATOR; } - function getModuleTypes() external view returns (EncodedModuleTypes) { - return MODULE_TYPES; - } - function isInitialized(address smartAccount) external pure returns (bool) { return false; } diff --git a/src/modules/ERC7579ExecutorBase.sol b/packages/modulekit/src/modules/ERC7579ExecutorBase.sol similarity index 100% rename from src/modules/ERC7579ExecutorBase.sol rename to packages/modulekit/src/modules/ERC7579ExecutorBase.sol diff --git a/src/modules/ERC7579FallbackBase.sol b/packages/modulekit/src/modules/ERC7579FallbackBase.sol similarity index 100% rename from src/modules/ERC7579FallbackBase.sol rename to packages/modulekit/src/modules/ERC7579FallbackBase.sol diff --git a/src/modules/ERC7579HookBase.sol b/packages/modulekit/src/modules/ERC7579HookBase.sol similarity index 100% rename from src/modules/ERC7579HookBase.sol rename to packages/modulekit/src/modules/ERC7579HookBase.sol diff --git a/packages/modulekit/src/modules/ERC7579HookDestruct.sol b/packages/modulekit/src/modules/ERC7579HookDestruct.sol new file mode 100644 index 00000000..f50df6a6 --- /dev/null +++ b/packages/modulekit/src/modules/ERC7579HookDestruct.sol @@ -0,0 +1,224 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import { ERC7579HookBase } from "./ERC7579HookBase.sol"; +import { IERC7579Account } from "../Accounts.sol"; +import { ExecutionLib, Execution } from "erc7579/lib/ExecutionLib.sol"; +import { + ModeLib, + CallType, + ModeCode, + CALLTYPE_SINGLE, + CALLTYPE_BATCH, + CALLTYPE_DELEGATECALL +} from "erc7579/lib/ModeLib.sol"; + +uint256 constant EXEC_OFFSET = 100; +uint256 constant INSTALL_OFFSET = 132; + +abstract contract ERC7579HookDestruct is ERC7579HookBase { + error HookInvalidSelector(); + + /*////////////////////////////////////////////////////////////////////////// + CALLDATA DECODING + //////////////////////////////////////////////////////////////////////////*/ + + function preCheck( + address msgSender, + bytes calldata msgData + ) + external + virtual + override + returns (bytes memory hookData) + { + bytes4 selector = bytes4(msgData[0:4]); + + if (selector == IERC7579Account.execute.selector) { + return _handle4337Executions(msgSender, msgData); + } else if (selector == IERC7579Account.executeFromExecutor.selector) { + return _handleExecutorExecutions(msgSender, msgData); + } else if (selector == IERC7579Account.installModule.selector) { + uint256 paramLen = uint256(bytes32(msgData[INSTALL_OFFSET - 32:INSTALL_OFFSET])); + bytes calldata initData = msgData[INSTALL_OFFSET:INSTALL_OFFSET + paramLen]; + uint256 moduleType = uint256(bytes32(msgData[4:36])); + address module = address(bytes20((msgData[48:68]))); + return onInstallModule(msgSender, moduleType, module, initData); + } else if (selector == IERC7579Account.uninstallModule.selector) { + uint256 paramLen = uint256(bytes32(msgData[INSTALL_OFFSET - 32:INSTALL_OFFSET])); + bytes calldata initData = msgData[INSTALL_OFFSET:INSTALL_OFFSET + paramLen]; + uint256 moduleType = uint256(bytes32(msgData[4:36])); + address module = address(bytes20((msgData[48:68]))); + + return onUninstallModule(msgSender, moduleType, module, initData); + } else { + revert(); + } + } + + function _handle4337Executions( + address msgSender, + bytes calldata msgData + ) + internal + returns (bytes memory hookData) + { + uint256 paramLen = uint256(bytes32(msgData[EXEC_OFFSET - 32:EXEC_OFFSET])); + bytes calldata encodedExecutions = msgData[EXEC_OFFSET:EXEC_OFFSET + paramLen]; + + ModeCode mode = ModeCode.wrap(bytes32(msgData[4:36])); + CallType calltype = ModeLib.getCallType(mode); + + if (calltype == CALLTYPE_SINGLE) { + (address to, uint256 value, bytes calldata callData) = + ExecutionLib.decodeSingle(encodedExecutions); + return onExecute(msgSender, to, value, callData); + } else if (calltype == CALLTYPE_BATCH) { + Execution[] calldata execs = ExecutionLib.decodeBatch(encodedExecutions); + return onExecuteBatch(msgSender, execs); + } + } + + function _handleExecutorExecutions( + address msgSender, + bytes calldata msgData + ) + internal + returns (bytes memory hookData) + { + uint256 paramLen = uint256(bytes32(msgData[EXEC_OFFSET - 32:EXEC_OFFSET])); + bytes calldata encodedExecutions = msgData[EXEC_OFFSET:EXEC_OFFSET + paramLen]; + + ModeCode mode = ModeCode.wrap(bytes32(msgData[4:36])); + CallType calltype = ModeLib.getCallType(mode); + + if (calltype == CALLTYPE_SINGLE) { + (address to, uint256 value, bytes calldata callData) = + ExecutionLib.decodeSingle(encodedExecutions); + return onExecuteFromExecutor(msgSender, to, value, callData); + } else if (calltype == CALLTYPE_BATCH) { + Execution[] calldata execs = ExecutionLib.decodeBatch(encodedExecutions); + return onExecuteBatchFromExecutor(msgSender, execs); + } + } + + // if (selector == IERC7579Account.execute.selector) { + // ModeCode mode = ModeCode.wrap(bytes32(msgData[4:36])); + // CallType calltype = ModeLib.getCallType(mode); + // uint256 offset = msgData.offset(); + // if (calltype == CALLTYPE_SINGLE) { + // (address to, uint256 value, bytes calldata callData) = + // ExecutionLib.decodeSingle(msgData[36:offset]); + // return onExecute(msgSender, to, value, callData); + // } else if (calltype == CALLTYPE_BATCH) { + // Execution[] calldata execs = ExecutionLib.decodeBatch(msgData[36:offset]); + // return onExecuteBatch(msgSender, execs); + // } else { + // revert HookInvalidSelector(); + // } + // } else if (selector == IERC7579Account.executeFromExecutor.selector) { + // uint256 offset = msgData.offset(); + // + // ModeCode mode = ModeCode.wrap(bytes32(msgData[4:36])); + // CallType calltype = ModeLib.getCallType(mode); + // if (calltype == CALLTYPE_SINGLE) { + // (address to, uint256 value, bytes calldata callData) = + // ExecutionLib.decodeSingle(msgData[36:offset]); + // return onExecuteFromExecutor(msgSender, to, value, callData); + // } else if (calltype == CALLTYPE_BATCH) { + // Execution[] calldata execs = ExecutionLib.decodeBatch(msgData[36:offset]); + // return onExecuteBatchFromExecutor(msgSender, execs); + // } else { + // revert HookInvalidSelector(); + // } + // } else if (selector == IERC7579Account.installModule.selector) { + // uint256 offset = msgData.offset(); + // uint256 moduleType = uint256(bytes32(msgData[4:24])); + // address module = address(bytes20(msgData[24:36])); + // bytes calldata initData = msgData[36:offset]; + // onInstallModule(msgSender, moduleType, module, initData); + // } else if (selector == IERC7579Account.uninstallModule.selector) { + // uint256 offset = msgData.offset(); + // uint256 moduleType = uint256(bytes32(msgData[4:24])); + // address module = address(bytes20(msgData[24:36])); + // bytes calldata initData = msgData[36:offset]; + // onUninstallModule(msgSender, moduleType, module, initData); + // } else { + // revert HookInvalidSelector(); + // } + + function postCheck(bytes calldata hookData) external override returns (bool success) { + if (hookData.length == 0) return true; + return onPostCheck(hookData); + } + + /*////////////////////////////////////////////////////////////////////////// + EXECUTION + //////////////////////////////////////////////////////////////////////////*/ + + function onExecute( + address msgSender, + address target, + uint256 value, + bytes calldata callData + ) + internal + virtual + returns (bytes memory hookData); + + function onExecuteBatch( + address msgSender, + Execution[] calldata + ) + internal + virtual + returns (bytes memory hookData); + + function onExecuteFromExecutor( + address msgSender, + address target, + uint256 value, + bytes calldata callData + ) + internal + virtual + returns (bytes memory hookData); + + function onExecuteBatchFromExecutor( + address msgSender, + Execution[] calldata + ) + internal + virtual + returns (bytes memory hookData); + + /*////////////////////////////////////////////////////////////////////////// + CONFIG + //////////////////////////////////////////////////////////////////////////*/ + + function onInstallModule( + address msgSender, + uint256 moduleType, + address module, + bytes calldata initData + ) + internal + virtual + returns (bytes memory hookData); + + function onUninstallModule( + address msgSender, + uint256 moduleType, + address module, + bytes calldata deInitData + ) + internal + virtual + returns (bytes memory hookData); + + /*////////////////////////////////////////////////////////////////////////// + POSTCHECK + //////////////////////////////////////////////////////////////////////////*/ + + function onPostCheck(bytes calldata hookData) internal virtual returns (bool success); +} diff --git a/src/modules/ERC7579ModuleBase.sol b/packages/modulekit/src/modules/ERC7579ModuleBase.sol similarity index 100% rename from src/modules/ERC7579ModuleBase.sol rename to packages/modulekit/src/modules/ERC7579ModuleBase.sol diff --git a/src/modules/ERC7579ValidatorBase.sol b/packages/modulekit/src/modules/ERC7579ValidatorBase.sol similarity index 100% rename from src/modules/ERC7579ValidatorBase.sol rename to packages/modulekit/src/modules/ERC7579ValidatorBase.sol diff --git a/src/modules/ERC7579ValidatorMaster.sol b/packages/modulekit/src/modules/ERC7579ValidatorMaster.sol similarity index 100% rename from src/modules/ERC7579ValidatorMaster.sol rename to packages/modulekit/src/modules/ERC7579ValidatorMaster.sol diff --git a/src/modules/SessionKeyBase.sol b/packages/modulekit/src/modules/SessionKeyBase.sol similarity index 87% rename from src/modules/SessionKeyBase.sol rename to packages/modulekit/src/modules/SessionKeyBase.sol index 14154502..0d2eeac0 100644 --- a/src/modules/SessionKeyBase.sol +++ b/packages/modulekit/src/modules/SessionKeyBase.sol @@ -2,7 +2,8 @@ pragma solidity ^0.8.23; import { ERC7579ModuleBase } from "./ERC7579ModuleBase.sol"; -import { ISessionValidationModule } from "../core/SessionKey/ISessionValidationModule.sol"; +import { ISessionValidationModule } from + "@rhinestone/sessionkeymanager/src/ISessionValidationModule.sol"; abstract contract SessionKeyBase is ISessionValidationModule, ERC7579ModuleBase { error InvalidMethod(bytes4); diff --git a/src/modules/utils/ERC7579ValidatorLib.sol.todo b/packages/modulekit/src/modules/utils/ERC7579ValidatorLib.sol similarity index 79% rename from src/modules/utils/ERC7579ValidatorLib.sol.todo rename to packages/modulekit/src/modules/utils/ERC7579ValidatorLib.sol index 16612900..13d18f6b 100644 --- a/src/modules/utils/ERC7579ValidatorLib.sol.todo +++ b/packages/modulekit/src/modules/utils/ERC7579ValidatorLib.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.23; import { IERC7579Account, Execution } from "../../Accounts.sol"; -import { UserOperation, UserOperationLib } from "../../external/ERC4337.sol"; +import { PackedUserOperation, UserOperationLib } from "../../external/ERC4337.sol"; enum ACCOUNT_EXEC_TYPE { EXEC_SINGLE, @@ -18,7 +18,7 @@ enum ACCOUNT_EXEC_TYPE { library ERC7579ValidatorLib { error InvalidExecutionType(); - function decodeExecType(UserOperation calldata _ops) + function decodeExecType(PackedUserOperation calldata _ops) internal pure returns (ACCOUNT_EXEC_TYPE _type) @@ -33,23 +33,23 @@ library ERC7579ValidatorLib { { bytes4 functionSig = bytes4(userOpCalldata[:4]); - if (IERC7579Account.execute.selector == functionSig) { - _type = ACCOUNT_EXEC_TYPE.EXEC_SINGLE; - } else if (IERC7579Account.executeBatch.selector == functionSig) { - _type = ACCOUNT_EXEC_TYPE.EXEC_BATCH; - } else if (IERC7579Account.executeFromExecutor.selector == functionSig) { - _type = ACCOUNT_EXEC_TYPE.EXEC_SINGLE_FROM_EXECUTOR; - } else if (IERC7579Account.executeBatchFromExecutor.selector == functionSig) { - _type = ACCOUNT_EXEC_TYPE.EXEC_BATCH_FROM_EXECUTOR; - } else if (IERC7579Account.installValidator.selector == functionSig) { - _type = ACCOUNT_EXEC_TYPE.INSTALL_VALIDATOR; - } else if (IERC7579Account.installExecutor.selector == functionSig) { - _type = ACCOUNT_EXEC_TYPE.INSTALL_EXECUTOR; - } else if (IERC7579Account.uninstallHook.selector == functionSig) { - _type = ACCOUNT_EXEC_TYPE.UNINSTALL_HOOK; - } else { - _type = ACCOUNT_EXEC_TYPE.ERROR; - } + // if (IERC7579Account.execute.selector == functionSig) { + // _type = ACCOUNT_EXEC_TYPE.EXEC_SINGLE; + // } else if (IERC7579Account.executeBatch.selector == functionSig) { + // _type = ACCOUNT_EXEC_TYPE.EXEC_BATCH; + // } else if (IERC7579Account.executeFromExecutor.selector == functionSig) { + // _type = ACCOUNT_EXEC_TYPE.EXEC_SINGLE_FROM_EXECUTOR; + // } else if (IERC7579Account.executeBatchFromExecutor.selector == functionSig) { + // _type = ACCOUNT_EXEC_TYPE.EXEC_BATCH_FROM_EXECUTOR; + // } else if (IERC7579Account.installValidator.selector == functionSig) { + // _type = ACCOUNT_EXEC_TYPE.INSTALL_VALIDATOR; + // } else if (IERC7579Account.installExecutor.selector == functionSig) { + // _type = ACCOUNT_EXEC_TYPE.INSTALL_EXECUTOR; + // } else if (IERC7579Account.uninstallHook.selector == functionSig) { + // _type = ACCOUNT_EXEC_TYPE.UNINSTALL_HOOK; + // } else { + // _type = ACCOUNT_EXEC_TYPE.ERROR; + // } } function decodeCalldataBatch(bytes calldata userOpCalldata) @@ -98,8 +98,8 @@ library ERC7579ValidatorLib { } function validateWith( - UserOperation calldata userOp, - function(UserOperation calldata,address,uint256,bytes calldata) internal returns(uint48,uint48) + PackedUserOperation calldata userOp, + function(PackedUserOperation calldata,address,uint256,bytes calldata) internal returns(uint48,uint48) validationFunction ) internal @@ -134,7 +134,7 @@ abstract contract Decoder { using ERC7579ValidatorLib for *; using UserOperationLib for *; - function validate(UserOperation calldata userOp) internal { + function validate(PackedUserOperation calldata userOp) internal { ACCOUNT_EXEC_TYPE accountExecType = userOp.callData.decodeExecType(); address smartAccount = userOp.getSender(); diff --git a/src/test/Auxiliary.sol b/packages/modulekit/src/test/Auxiliary.sol similarity index 93% rename from src/test/Auxiliary.sol rename to packages/modulekit/src/test/Auxiliary.sol index b3645217..8c532956 100644 --- a/src/test/Auxiliary.sol +++ b/packages/modulekit/src/test/Auxiliary.sol @@ -5,8 +5,10 @@ import { IEntryPoint, PackedUserOperation } from "../external/ERC4337.sol"; import { ERC7579Bootstrap } from "../external/ERC7579.sol"; import { IERC7484Registry } from "../interfaces/IERC7484Registry.sol"; import { etchEntrypoint } from "./predeploy/EntryPoint.sol"; -import { EntryPointSimulations } from "account-abstraction/core/EntryPointSimulations.sol"; -import { IEntryPointSimulations } from "account-abstraction/interfaces/IEntryPointSimulations.sol"; +import { EntryPointSimulations } from + "@ERC4337/account-abstraction/contracts/core/EntryPointSimulations.sol"; +import { IEntryPointSimulations } from + "@ERC4337/account-abstraction/contracts/interfaces/IEntryPointSimulations.sol"; import { ISessionKeyManager, etchSessionKeyManager } from "./predeploy/SessionKeyManager.sol"; import { ExtensibleFallbackHandler } from "../core/ExtensibleFallbackHandler.sol"; import { MockRegistry } from "../mocks/MockRegistry.sol"; diff --git a/src/test/ModuleKitFallbackHandler.sol b/packages/modulekit/src/test/ModuleKitFallbackHandler.sol similarity index 100% rename from src/test/ModuleKitFallbackHandler.sol rename to packages/modulekit/src/test/ModuleKitFallbackHandler.sol diff --git a/src/test/ModuleKitHelpers.sol b/packages/modulekit/src/test/ModuleKitHelpers.sol similarity index 99% rename from src/test/ModuleKitHelpers.sol rename to packages/modulekit/src/test/ModuleKitHelpers.sol index 6422943d..4c4999e0 100644 --- a/src/test/ModuleKitHelpers.sol +++ b/packages/modulekit/src/test/ModuleKitHelpers.sol @@ -9,8 +9,6 @@ import { ERC4337Helpers } from "./utils/ERC4337Helpers.sol"; import { ModuleKitCache } from "./utils/ModuleKitCache.sol"; import { writeExpectRevert, writeGasIdentifier } from "./utils/Log.sol"; -import "forge-std/console2.sol"; - library ModuleKitHelpers { using ModuleKitUserOp for AccountInstance; using ModuleKitHelpers for AccountInstance; diff --git a/src/test/ModuleKitSCM.sol b/packages/modulekit/src/test/ModuleKitSCM.sol similarity index 100% rename from src/test/ModuleKitSCM.sol rename to packages/modulekit/src/test/ModuleKitSCM.sol diff --git a/src/test/ModuleKitUserOp.sol b/packages/modulekit/src/test/ModuleKitUserOp.sol similarity index 100% rename from src/test/ModuleKitUserOp.sol rename to packages/modulekit/src/test/ModuleKitUserOp.sol diff --git a/src/test/RhinestoneModuleKit.sol b/packages/modulekit/src/test/RhinestoneModuleKit.sol similarity index 89% rename from src/test/RhinestoneModuleKit.sol rename to packages/modulekit/src/test/RhinestoneModuleKit.sol index 355f911d..c0a8e445 100644 --- a/src/test/RhinestoneModuleKit.sol +++ b/packages/modulekit/src/test/RhinestoneModuleKit.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.23; import { Auxiliary, AuxiliaryFactory } from "./Auxiliary.sol"; +import { MultiAccountFactory } from "../accountFactory/MultiAccountFactory.sol"; import { PackedUserOperation, IEntryPoint, IStakeManager } from "../external/ERC4337.sol"; import { ERC7579Helpers, BootstrapUtil } from "./utils/ERC7579Helpers.sol"; import { ENTRYPOINT_ADDR } from "./predeploy/EntryPoint.sol"; @@ -37,8 +38,10 @@ struct UserOpData { } contract RhinestoneModuleKit is AuxiliaryFactory { - ERC7579AccountFactory public accountFactory; - IERC7579Account public accountImplementationSingleton; + // ERC7579AccountFactory public accountFactory; + // IERC7579Account public accountImplementationSingleton; + + MultiAccountFactory public accountFactory; bool internal isInit; @@ -60,11 +63,13 @@ contract RhinestoneModuleKit is AuxiliaryFactory { isInit = true; - // Deploy default contracts - accountImplementationSingleton = new ERC7579Account(); - label(address(accountImplementationSingleton), "ERC7579AccountImpl"); - accountFactory = new ERC7579AccountFactory(address(accountImplementationSingleton)); - label(address(accountFactory), "ERC7579AccountFactory"); + // // Deploy default contracts + // accountImplementationSingleton = new ERC7579Account(); + // label(address(accountImplementationSingleton), "ERC7579AccountImpl"); + // accountFactory = new ERC7579AccountFactory(address(accountImplementationSingleton)); + // label(address(accountFactory), "ERC7579AccountFactory"); + + accountFactory = new MultiAccountFactory(); defaultValidator = new MockValidator(); label(address(defaultValidator), "DefaultValidator"); @@ -140,8 +145,10 @@ contract RhinestoneModuleKit is AuxiliaryFactory { validators = _validators; } + // bytes memory bootstrapCalldata = + // auxiliary.bootstrap._getInitMSACalldata(validators, executors, hook, fallBack); bytes memory bootstrapCalldata = - auxiliary.bootstrap._getInitMSACalldata(validators, executors, hook, fallBack); + accountFactory.getBootstrapCallData(validators, executors, hook, fallBack); address account = accountFactory.getAddress(salt, bootstrapCalldata); // using MSAFactory from ERC7579 repo. diff --git a/packages/modulekit/src/test/RhinestoneModuleKit.sol.bak b/packages/modulekit/src/test/RhinestoneModuleKit.sol.bak new file mode 100644 index 00000000..afedc21a --- /dev/null +++ b/packages/modulekit/src/test/RhinestoneModuleKit.sol.bak @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import { Auxiliary, AuxiliaryFactory } from "./Auxiliary.sol"; +import { PackedUserOperation, IEntryPoint, IStakeManager } from "../external/ERC4337.sol"; +import { ERC7579Helpers, BootstrapUtil } from "./utils/ERC7579Helpers.sol"; +import { ENTRYPOINT_ADDR } from "./predeploy/EntryPoint.sol"; + +import { + ERC7579BootstrapConfig, + IERC7579Account, + ERC7579Account, + ERC7579AccountFactory, + IERC7579Validator +} from "../external/ERC7579.sol"; + +import { ModuleKitUserOp } from "./ModuleKitUserOp.sol"; +import { ModuleKitHelpers } from "./ModuleKitHelpers.sol"; +import { MockValidator } from "../Mocks.sol"; +import { MultiAccountFactory } from "./MultiAccountFactory.sol"; +import { AccountDetection } from "./utils/AccountDetection.sol"; +import { IAccountFactory } from "../IAccountFactory.sol"; + +import "./utils/Vm.sol"; +import "./utils/ModuleKitCache.sol"; +import "./utils/Log.sol"; + +struct AccountInstance { + address account; + Auxiliary aux; + IERC7579Validator defaultValidator; + bytes32 salt; + bytes initCode; + bool gasLog; +} + +struct UserOpData { + PackedUserOperation userOp; + bytes32 userOpHash; +} + +contract RhinestoneModuleKit is AccountDetection, AuxiliaryFactory, MultiAccountFactory { + IAccountFactory public accountFactory; + bool internal isInit; + MockValidator public defaultValidator; + + constructor() { + init(); + } + + /** + * Initializes Auxiliary and /src/core + * This function will run before any accounts can be created + */ + function init() internal virtual override { + if (!isInit) { + super.init(); + isInit = true; + } + + isInit = true; + defaultValidator = new MockValidator(); + label(address(defaultValidator), "DefaultValidator"); + + // // Deploy default contracts + // accountImplementationSingleton = new ERC7579Account(); + // label(address(accountImplementationSingleton), "ERC7579AccountImpl"); + // accountFactory = new ERC7579AccountFactory(address(accountImplementationSingleton)); + // label(address(accountFactory), "ERC7579AccountFactory"); + // defaultValidator = new MockValidator(); + // label(address(defaultValidator), "DefaultValidator"); + // + // // Stake factory on EntryPoint + // deal(address(accountFactory), 10 ether); + // prank(address(accountFactory)); + // IStakeManager(ENTRYPOINT_ADDR).addStake{ value: 10 ether }(100_000); + } + + function makeAccountInstance(bytes32 salt) internal returns (AccountInstance memory instance) { + address account = makeAccount(accountFlavor, salt, address(defaultValidator), ""); + + instance = AccountInstance({ + account: account, + aux: auxiliary, + salt: salt, + defaultValidator: IERC7579Validator(address(defaultValidator)), + initCode: "", + gasLog: false + }); + } + + function makeAccountInstance( + bytes32 salt, + address account, + address defaultValidator, + bytes memory initCode + ) + internal + returns (AccountInstance memory instance) + { } +} diff --git a/src/test/predeploy/EntryPoint.sol b/packages/modulekit/src/test/predeploy/EntryPoint.sol similarity index 82% rename from src/test/predeploy/EntryPoint.sol rename to packages/modulekit/src/test/predeploy/EntryPoint.sol index 98b95a3f..bba27136 100644 --- a/src/test/predeploy/EntryPoint.sol +++ b/packages/modulekit/src/test/predeploy/EntryPoint.sol @@ -5,9 +5,11 @@ pragma solidity ^0.8.23; /* solhint-disable no-global-import */ import "../utils/Vm.sol"; import { IEntryPoint } from "../../external/ERC4337.sol"; -import { SenderCreator } from "account-abstraction/core/EntryPoint.sol"; -import { EntryPointSimulations } from "account-abstraction/core/EntryPointSimulations.sol"; -import { IEntryPointSimulations } from "account-abstraction/interfaces/IEntryPointSimulations.sol"; +import { SenderCreator } from "@ERC4337/account-abstraction/contracts/core/EntryPoint.sol"; +import { EntryPointSimulations } from + "@ERC4337/account-abstraction/contracts/core/EntryPointSimulations.sol"; +import { IEntryPointSimulations } from + "@ERC4337/account-abstraction/contracts/interfaces/IEntryPointSimulations.sol"; contract EntryPointSimulationsPatch is EntryPointSimulations { address _entrypointAddr = address(this); @@ -32,7 +34,7 @@ contract EntryPointSimulationsPatch is EntryPointSimulations { } } -address constant ENTRYPOINT_ADDR = 0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789; +address constant ENTRYPOINT_ADDR = 0x0000000071727De22E5E9d8BAf0edAc6f37da032; function etchEntrypoint() returns (IEntryPoint) { address payable entryPoint = payable(address(new EntryPointSimulationsPatch())); diff --git a/src/test/predeploy/MockFactory.sol b/packages/modulekit/src/test/predeploy/MockFactory.sol similarity index 100% rename from src/test/predeploy/MockFactory.sol rename to packages/modulekit/src/test/predeploy/MockFactory.sol diff --git a/src/test/predeploy/SessionKeyManager.sol b/packages/modulekit/src/test/predeploy/SessionKeyManager.sol similarity index 100% rename from src/test/predeploy/SessionKeyManager.sol rename to packages/modulekit/src/test/predeploy/SessionKeyManager.sol diff --git a/src/test/utils/ERC4337Helpers.sol b/packages/modulekit/src/test/utils/ERC4337Helpers.sol similarity index 99% rename from src/test/utils/ERC4337Helpers.sol rename to packages/modulekit/src/test/utils/ERC4337Helpers.sol index 2454caf5..b685e724 100644 --- a/src/test/utils/ERC4337Helpers.sol +++ b/packages/modulekit/src/test/utils/ERC4337Helpers.sol @@ -12,7 +12,6 @@ import { ENTRYPOINT_ADDR } from "../predeploy/EntryPoint.sol"; import "./Vm.sol"; import "./Log.sol"; import "./GasCalculations.sol"; -import "forge-std/console2.sol"; import { Simulator } from "erc4337-validation/Simulator.sol"; library ERC4337Helpers { diff --git a/src/test/utils/ERC7579Helpers.sol b/packages/modulekit/src/test/utils/ERC7579Helpers.sol similarity index 100% rename from src/test/utils/ERC7579Helpers.sol rename to packages/modulekit/src/test/utils/ERC7579Helpers.sol diff --git a/src/test/utils/GasCalculations.sol b/packages/modulekit/src/test/utils/GasCalculations.sol similarity index 100% rename from src/test/utils/GasCalculations.sol rename to packages/modulekit/src/test/utils/GasCalculations.sol diff --git a/src/test/utils/Log.sol b/packages/modulekit/src/test/utils/Log.sol similarity index 100% rename from src/test/utils/Log.sol rename to packages/modulekit/src/test/utils/Log.sol diff --git a/src/test/utils/ModuleKitCache.sol b/packages/modulekit/src/test/utils/ModuleKitCache.sol similarity index 100% rename from src/test/utils/ModuleKitCache.sol rename to packages/modulekit/src/test/utils/ModuleKitCache.sol diff --git a/src/test/utils/Vm.sol b/packages/modulekit/src/test/utils/Vm.sol similarity index 100% rename from src/test/utils/Vm.sol rename to packages/modulekit/src/test/utils/Vm.sol diff --git a/test/Diff.t.sol b/packages/modulekit/test/Diff.t.sol similarity index 90% rename from test/Diff.t.sol rename to packages/modulekit/test/Diff.t.sol index f2c29778..930552c6 100644 --- a/test/Diff.t.sol +++ b/packages/modulekit/test/Diff.t.sol @@ -36,31 +36,32 @@ contract ERC7579DifferentialModuleKitLibTest is BaseTest { // Setup aux token = new MockERC20(); token.initialize("Mock Token", "MTK", 18); - fund(); + deal(address(token), instance.account, 100 ether); + vm.deal(instance.account, 1000 ether); } - function fund() internal { - for (uint256 i; i < diffAccounts.length; i++) { - instance = diffAccounts[i]; - deal(address(token), instance.account, 100 ether); - vm.deal(instance.account, 1000 ether); - } - } - - modifier diffTest() { - uint256 snapshot = vm.snapshot(); // saves the state - for (uint256 i; i < diffAccounts.length; i++) { - instance = diffAccounts[i]; - _; - vm.revertTo(snapshot); - } - } + // function fund() internal { + // for (uint256 i; i < diffAccounts.length; i++) { + // instance = diffAccounts[i]; + // deal(address(token), instance.account, 100 ether); + // vm.deal(instance.account, 1000 ether); + // } + // } + // + // modifier () { + // uint256 snapshot = vm.snapshot(); // saves the state + // for (uint256 i; i < diffAccounts.length; i++) { + // instance = diffAccounts[i]; + // _; + // vm.revertTo(snapshot); + // } + // } /*////////////////////////////////////////////////////////////////////////// exec //////////////////////////////////////////////////////////////////////////*/ - function testexec__Given__TwoInputs() public diffTest { + function testexec__Given__TwoInputs() public { // Create userOperation fields address receiver = makeAddr("receiver"); uint256 value = 10 gwei; @@ -74,7 +75,7 @@ contract ERC7579DifferentialModuleKitLibTest is BaseTest { assertEq(token.balanceOf(receiver), value, "Receiver should have 10 gwei in tokens"); } - function testexec__Given__ThreeInputs() public diffTest { + function testexec__Given__ThreeInputs() public { // Create userOperation fields address receiver = makeAddr("receiver"); uint256 value = 10 gwei; @@ -87,7 +88,7 @@ contract ERC7579DifferentialModuleKitLibTest is BaseTest { assertEq(receiver.balance, value, "Receiver should have 10 gwei"); } - function testexec__Given__FourInputs() public diffTest { + function testexec__Given__FourInputs() public { // Create userOperation fields address receiver = makeAddr("receiver"); uint256 value = 10 gwei; @@ -119,7 +120,7 @@ contract ERC7579DifferentialModuleKitLibTest is BaseTest { MODULES //////////////////////////////////////////////////////////////////////////*/ - function testAddValidator() public diffTest { + function testAddValidator() public { address newValidator = address(new MockValidator()); address newValidator1 = address(new MockValidator()); vm.label(newValidator, "2nd validator"); @@ -143,7 +144,7 @@ contract ERC7579DifferentialModuleKitLibTest is BaseTest { assertTrue(validator1Enabled); } - function testRemoveValidator() public diffTest { + function testRemoveValidator() public { address newValidator = address(new MockValidator()); instance.installModule({ moduleTypeId: MODULE_TYPE_VALIDATOR, @@ -199,14 +200,14 @@ contract ERC7579DifferentialModuleKitLibTest is BaseTest { // assertTrue(isValidProof); } - function testAddHook() public diffTest { + function testAddHook() public { instance.installModule({ moduleTypeId: MODULE_TYPE_HOOK, module: address(hook), data: "" }); bool hookEnabled = instance.isModuleInstalled(MODULE_TYPE_HOOK, address(hook)); assertTrue(hookEnabled); } - function testAddExecutor() public diffTest { + function testAddExecutor() public { address newExecutor = address(new MockExecutor()); instance.installModule({ moduleTypeId: MODULE_TYPE_EXECUTOR, module: newExecutor, data: "" }); @@ -214,7 +215,7 @@ contract ERC7579DifferentialModuleKitLibTest is BaseTest { assertTrue(executorEnabled); } - function testRemoveExecutor() public diffTest { + function testRemoveExecutor() public { address newExecutor = address(new MockExecutor()); instance.installModule({ moduleTypeId: MODULE_TYPE_EXECUTOR, module: newExecutor, data: "" }); @@ -316,8 +317,8 @@ contract ERC7579DifferentialModuleKitLibTest is BaseTest { assertTrue(vm.isFile(fileName)); } - function testSimulateUserOp() public { - writeSimulateUserOp(true); - testexec__Given__TwoInputs(); - } + // function testSimulateUserOp() public { + // writeSimulateUserOp(true); + // testexec__Given__TwoInputs(); + // } } diff --git a/test/LicenseManager.t.sol.bak b/packages/modulekit/test/LicenseManager.t.sol.bak similarity index 100% rename from test/LicenseManager.t.sol.bak rename to packages/modulekit/test/LicenseManager.t.sol.bak diff --git a/test/MakeAccount.t.sol b/packages/modulekit/test/MakeAccount.t.sol similarity index 74% rename from test/MakeAccount.t.sol rename to packages/modulekit/test/MakeAccount.t.sol index fb6bb6b5..14b79a53 100644 --- a/test/MakeAccount.t.sol +++ b/packages/modulekit/test/MakeAccount.t.sol @@ -11,9 +11,6 @@ import "src/Mocks.sol"; contract BaseTest is RhinestoneModuleKit, Test { using ModuleKitHelpers for AccountInstance; - MultiAccount multiAccount; - AccountInstance[] internal diffAccounts; - AccountInstance internal instance; AccountInstance internal instanceSafe; @@ -21,14 +18,10 @@ contract BaseTest is RhinestoneModuleKit, Test { function setUp() public virtual { instance = makeAccountInstance("1"); + MockValidator defaultValidator = new MockValidator(); MockExecutor defaultExecutor = new MockExecutor(); - multiAccount = new MultiAccount(address(defaultValidator), address(defaultExecutor)); - address safe = multiAccount.makeSafe(); - instanceSafe = makeAccountInstance("2", safe, address(defaultValidator), ""); vm.deal(instanceSafe.account, 1000 ether); - diffAccounts.push(instance); - diffAccounts.push(instanceSafe); vm.deal(instance.account, 2 ether); recipient = makeAddr("recipient"); diff --git a/test/SessionValidator.t.sol.bak b/packages/modulekit/test/SessionValidator.t.sol.bak similarity index 100% rename from test/SessionValidator.t.sol.bak rename to packages/modulekit/test/SessionValidator.t.sol.bak diff --git a/test/SessionValidator.t.sol.bak2 b/packages/modulekit/test/SessionValidator.t.sol.bak2 similarity index 100% rename from test/SessionValidator.t.sol.bak2 rename to packages/modulekit/test/SessionValidator.t.sol.bak2 diff --git a/test/ValidatorUtils.t.sol.bak b/packages/modulekit/test/ValidatorUtils.t.sol.bak similarity index 100% rename from test/ValidatorUtils.t.sol.bak rename to packages/modulekit/test/ValidatorUtils.t.sol.bak diff --git a/packages/modulekit/test/components/HookDestruct.t.sol b/packages/modulekit/test/components/HookDestruct.t.sol new file mode 100644 index 00000000..ad684a8f --- /dev/null +++ b/packages/modulekit/test/components/HookDestruct.t.sol @@ -0,0 +1,226 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import "src/modules/ERC7579HookDestruct.sol"; +import { IERC7579Account } from "src/external/ERC7579.sol"; + +import "forge-std/Test.sol"; +import { ExecutionLib, Execution } from "erc7579/lib/ExecutionLib.sol"; + +contract HookDestructTest is Test, ERC7579HookDestruct { + struct Log { + address msgSender; + bytes msgData; + mapping(uint256 index => Execution) executions; + uint256 executionsLength; + } + + struct InstallLog { + address module; + uint256 moduleType; + bytes initData; + } + + Log _log; + InstallLog _installLog; + + function setUp() public { } + + function test_executeSingle( + address msgSender, + address target, + uint256 value, + bytes memory data + ) + public + { + vm.assume(data.length > 0); + ModeCode mode = ModeLib.encodeSimpleSingle(); + bytes memory execution = ExecutionLib.encodeSingle(target, value, data); + bytes memory callData = + abi.encodeCall(IERC7579Account.executeFromExecutor, (mode, execution)); + _log.msgData = callData; + _log.msgSender = msgSender; + + _log.executionsLength = 1; + _log.executions[0].target = target; + _log.executions[0].value = value; + _log.executions[0].callData = data; + + bytes memory hookData = ERC7579HookDestruct(address(this)).preCheck(msgSender, callData); + assertEq(hookData, "onExecute"); + } + + function test_executeBatch(address msgSender, Execution[] memory _execution) public { + vm.assume(_execution.length > 0); + ModeCode mode = ModeLib.encodeSimpleBatch(); + bytes memory execution = ExecutionLib.encodeBatch(_execution); + bytes memory callData = + abi.encodeCall(IERC7579Account.executeFromExecutor, (mode, execution)); + + _log.msgData = callData; + _log.msgSender = msgSender; + + _log.executionsLength = _execution.length; + for (uint256 i; i < _execution.length; i++) { + _log.executions[i].target = _execution[i].target; + _log.executions[i].value = _execution[i].value; + _log.executions[i].callData = _execution[i].callData; + } + + bytes memory hookData = ERC7579HookDestruct(address(this)).preCheck(msgSender, callData); + assertEq(hookData, "onExecuteBatch"); + } + + function test_installModule( + address msgSender, + address moduleAddress, + uint256 moduleType, + bytes memory data + ) + public + { + vm.assume(data.length > 0); + moduleType = moduleType % 5; + bytes memory callData = + abi.encodeCall(IERC7579Account.installModule, (moduleType, moduleAddress, data)); + _log.msgData = callData; + _log.msgSender = msgSender; + + _installLog.module = moduleAddress; + _installLog.moduleType = moduleType; + _installLog.initData = data; + + bytes memory hookData = ERC7579HookDestruct(address(this)).preCheck(msgSender, callData); + assertEq(hookData, "onInstall", "return value wrong"); + } + + function onExecute( + address msgSender, + address target, + uint256 value, + bytes calldata callData + ) + internal + virtual + override + returns (bytes memory hookData) + { + assertTrue(_log.msgSender == msgSender); + assertTrue(_log.executionsLength == 1); + + assertEq(_log.executions[0].callData, callData, "callData decoding failed"); + assertEq(_log.executions[0].value, value); + assertEq(_log.executions[0].target, target); + + hookData = "onExecute"; + } + + function onExecuteBatch( + address msgSender, + Execution[] calldata executions + ) + internal + virtual + override + returns (bytes memory hookData) + { + assertTrue(_log.msgSender == msgSender); + assertEq(_log.executionsLength, executions.length); + + for (uint256 i; i < executions.length; i++) { + assertEq(_log.executions[i].callData, executions[i].callData); + assertEq(_log.executions[i].value, executions[i].value); + assertEq(_log.executions[i].target, executions[i].target); + } + + return "onExecuteBatch"; + } + + function onExecuteFromExecutor( + address msgSender, + address target, + uint256 value, + bytes calldata callData + ) + internal + virtual + override + returns (bytes memory hookData) + { + assertTrue(_log.msgSender == msgSender); + assertTrue(_log.executionsLength == 1); + + assertEq(_log.executions[0].callData, callData, "callData decoding failed"); + assertEq(_log.executions[0].value, value); + assertEq(_log.executions[0].target, target); + + hookData = "onExecute"; + } + + function onExecuteBatchFromExecutor( + address msgSender, + Execution[] calldata executions + ) + internal + virtual + override + returns (bytes memory hookData) + { + assertTrue(_log.msgSender == msgSender); + assertEq(_log.executionsLength, executions.length); + + for (uint256 i; i < executions.length; i++) { + assertEq(_log.executions[i].callData, executions[i].callData); + assertEq(_log.executions[i].value, executions[i].value); + assertEq(_log.executions[i].target, executions[i].target); + } + + return "onExecuteBatch"; + } + + function onInstallModule( + address msgSender, + uint256 moduleType, + address module, + bytes calldata initData + ) + internal + virtual + override + returns (bytes memory hookData) + { + assertEq(_log.msgSender, msgSender); + + assertEq(_installLog.module, module); + assertEq(_installLog.moduleType, moduleType); + assertEq(_installLog.initData, initData); + + hookData = "onInstall"; + } + + function onUninstallModule( + address msgSender, + uint256 moduleType, + address module, + bytes calldata deInitData + ) + internal + virtual + override + returns (bytes memory hookData) + { } + + function onPostCheck(bytes calldata hookData) + internal + virtual + override + returns (bool success) + { } + + function onInstall(bytes calldata) public { } + function onUninstall(bytes calldata) public { } + + function isInitialized(address smartAccount) public view returns (bool) { } + function isModuleType(uint256 moduleType) public pure returns (bool) { } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 921562ad..4ed6ef18 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,54 +4,220 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false -dependencies: - '@openzeppelin/contracts': - specifier: 5.0.1 - version: 5.0.1 - '@prb/math': - specifier: ^4.0.2 - version: 4.0.2 - erc4337-validation: - specifier: github:rhinestonewtf/erc4337-validation - version: github.com/rhinestonewtf/erc4337-validation/19a97d86f8f29709664334078925b2a843be19e0 - -devDependencies: - '@rhinestone/sessionkeymanager': - specifier: github:rhinestonewtf/sessionkeymanager - version: github.com/rhinestonewtf/sessionkeymanager/96bb3be7444c0c304075b6fdb2d6fb4260e275cc - '@safe-global/safe-contracts': - specifier: ^1.4.1 - version: 1.4.1(ethers@5.4.0) - account-abstraction: - specifier: github:kopy-kat/account-abstraction#develop - version: github.com/kopy-kat/account-abstraction/3c0127e9f7cb76e4a0fdb2d35cac51900f252bdc(ethers@5.4.0)(hardhat@2.20.1)(lodash@4.17.21)(typechain@5.2.0) - account-abstraction-v0.6: - specifier: github:eth-infinitism/account-abstraction#v0.6.0 - version: github.com/eth-infinitism/account-abstraction/7174d6d845618dbd11cee68eefa715f5263690b6(ethers@5.4.0)(hardhat@2.20.1)(lodash@4.17.21)(typechain@5.2.0) - ds-test: - specifier: github:dapphub/ds-test - version: github.com/dapphub/ds-test/e282159d5170298eb2455a6c05280ab5a73a4ef0 - erc7579: - specifier: github:erc7579/erc7579-implementation - version: github.com/erc7579/erc7579-implementation/957cd05deeab6a9a85343bb8d1c9701705ed4ecf - forge-std: - specifier: github:foundry-rs/forge-std - version: github.com/foundry-rs/forge-std/1d0766bc5d814f117c7b1e643828f7d85024fb51 - prettier: - specifier: ^2.8.8 - version: 2.8.8 - sentinellist: - specifier: github:zeroknots/sentinellist - version: github.com/zeroknots/sentinellist/2783f466b6d9c457da0a240e392db183ca1607bb - solady: - specifier: github:vectorized/solady - version: github.com/vectorized/solady/1372606383445c0a247e6c58eb255a529734258a - solarray: - specifier: github:sablier-labs/solarray - version: github.com/sablier-labs/solarray/6bf10cb34cdace52a3ba5fe437e78cc82df92684 - solhint: - specifier: ^4.1.1 - version: 4.1.1(typescript@5.3.3) +importers: + + .: + devDependencies: + '@rhinestone/modulekit': + specifier: workspace:* + version: link:packages/modulekit + '@rhinestone/safe7579': + specifier: workspace:* + version: link:accounts/safe7579 + '@rhinestone/sessionkeymanager': + specifier: workspace:* + version: link:packages/SessionKeyManager + prettier: + specifier: ^2.8.8 + version: 2.8.8 + solhint: + specifier: ^4.1.1 + version: 4.1.1(typescript@5.3.3) + + accounts/safe7579: + devDependencies: + '@ERC4337/account-abstraction': + specifier: github:kopy-kat/account-abstraction#develop + version: github.com/kopy-kat/account-abstraction/3c0127e9f7cb76e4a0fdb2d35cac51900f252bdc(ethers@5.4.0)(hardhat@2.20.1)(lodash@4.17.21)(typechain@5.2.0) + '@ERC4337/account-abstraction-v0.6': + specifier: github:eth-infinitism/account-abstraction#v0.6.0 + version: github.com/eth-infinitism/account-abstraction/7174d6d845618dbd11cee68eefa715f5263690b6(ethers@5.4.0)(hardhat@2.20.1)(lodash@4.17.21)(typechain@5.2.0) + '@openzeppelin/contracts': + specifier: 5.0.1 + version: 5.0.1 + '@prb/math': + specifier: ^4.0.2 + version: 4.0.2 + '@rhinestone/modulekit': + specifier: workspace:* + version: link:../../packages/modulekit + '@rhinestone/sessionkeymanager': + specifier: workspace:* + version: link:../../packages/SessionKeyManager + '@safe-global/safe-contracts': + specifier: ^1.4.1 + version: 1.4.1(ethers@5.4.0) + ds-test: + specifier: github:dapphub/ds-test + version: github.com/dapphub/ds-test/e282159d5170298eb2455a6c05280ab5a73a4ef0 + erc4337-validation: + specifier: github:rhinestonewtf/erc4337-validation + version: github.com/rhinestonewtf/erc4337-validation/19a97d86f8f29709664334078925b2a843be19e0 + erc7579: + specifier: github:erc7579/erc7579-implementation + version: github.com/erc7579/erc7579-implementation/1548b5bd9d20c257926d84952190cc6877ba7a57 + forge-std: + specifier: github:foundry-rs/forge-std + version: github.com/foundry-rs/forge-std/1d0766bc5d814f117c7b1e643828f7d85024fb51 + prettier: + specifier: ^2.8.8 + version: 2.8.8 + sentinellist: + specifier: github:zeroknots/sentinellist + version: github.com/zeroknots/sentinellist/6294bf412489c0f6d3b9c92ad0aceb08c5b8704b + solady: + specifier: github:vectorized/solady + version: github.com/vectorized/solady/72e47ca417d24a30801b2921584e8486462cfc7b + solarray: + specifier: github:sablier-labs/solarray + version: github.com/sablier-labs/solarray/6bf10cb34cdace52a3ba5fe437e78cc82df92684 + solhint: + specifier: ^4.1.1 + version: 4.1.1(typescript@5.3.3) + solmate: + specifier: github:transmissions11/solmate + version: github.com/transmissions11/solmate/c892309933b25c03d32b1b0d674df7ae292ba925 + + examples: + devDependencies: + '@ERC4337/account-abstraction': + specifier: github:kopy-kat/account-abstraction#develop + version: github.com/kopy-kat/account-abstraction/3c0127e9f7cb76e4a0fdb2d35cac51900f252bdc(ethers@5.4.0)(hardhat@2.20.1)(lodash@4.17.21)(typechain@5.2.0) + '@ERC4337/account-abstraction-v0.6': + specifier: github:eth-infinitism/account-abstraction#v0.6.0 + version: github.com/eth-infinitism/account-abstraction/7174d6d845618dbd11cee68eefa715f5263690b6(ethers@5.4.0)(hardhat@2.20.1)(lodash@4.17.21)(typechain@5.2.0) + '@openzeppelin/contracts': + specifier: 5.0.1 + version: 5.0.1 + '@prb/math': + specifier: ^4.0.2 + version: 4.0.2 + '@rhinestone/modulekit': + specifier: workspace:* + version: link:../packages/modulekit + '@rhinestone/safe7579': + specifier: workspace:* + version: link:../accounts/safe7579 + '@rhinestone/sessionkeymanager': + specifier: workspace:* + version: link:../packages/SessionKeyManager + '@safe-global/safe-contracts': + specifier: ^1.4.1 + version: 1.4.1(ethers@5.4.0) + ds-test: + specifier: github:dapphub/ds-test + version: github.com/dapphub/ds-test/e282159d5170298eb2455a6c05280ab5a73a4ef0 + erc4337-validation: + specifier: github:rhinestonewtf/erc4337-validation + version: github.com/rhinestonewtf/erc4337-validation/19a97d86f8f29709664334078925b2a843be19e0 + erc7579: + specifier: github:erc7579/erc7579-implementation + version: github.com/erc7579/erc7579-implementation/1548b5bd9d20c257926d84952190cc6877ba7a57 + forge-std: + specifier: github:foundry-rs/forge-std + version: github.com/foundry-rs/forge-std/1d0766bc5d814f117c7b1e643828f7d85024fb51 + prettier: + specifier: ^2.8.8 + version: 2.8.8 + sentinellist: + specifier: github:zeroknots/sentinellist + version: github.com/zeroknots/sentinellist/6294bf412489c0f6d3b9c92ad0aceb08c5b8704b + solady: + specifier: github:vectorized/solady + version: github.com/vectorized/solady/72e47ca417d24a30801b2921584e8486462cfc7b + solarray: + specifier: github:sablier-labs/solarray + version: github.com/sablier-labs/solarray/6bf10cb34cdace52a3ba5fe437e78cc82df92684 + solhint: + specifier: ^4.1.1 + version: 4.1.1(typescript@5.3.3) + solmate: + specifier: github:transmissions11/solmate + version: github.com/transmissions11/solmate/c892309933b25c03d32b1b0d674df7ae292ba925 + + packages/SessionKeyManager: + devDependencies: + '@ERC4337/account-abstraction': + specifier: github:kopy-kat/account-abstraction#develop + version: github.com/kopy-kat/account-abstraction/3c0127e9f7cb76e4a0fdb2d35cac51900f252bdc(ethers@5.7.2)(hardhat@2.20.1)(lodash@4.17.21)(typechain@5.2.0) + '@ERC4337/account-abstraction-v0.6': + specifier: github:eth-infinitism/account-abstraction#v0.6.0 + version: github.com/eth-infinitism/account-abstraction/7174d6d845618dbd11cee68eefa715f5263690b6(ethers@5.7.2)(hardhat@2.20.1)(lodash@4.17.21)(typechain@5.2.0) + '@rhinestone/modulekit': + specifier: workspace:* + version: link:../modulekit + ds-test: + specifier: github:dapphub/ds-test + version: github.com/dapphub/ds-test/e282159d5170298eb2455a6c05280ab5a73a4ef0 + erc7579: + specifier: github:erc7579/erc7579-implementation + version: github.com/erc7579/erc7579-implementation/1548b5bd9d20c257926d84952190cc6877ba7a57 + forge-std: + specifier: github:foundry-rs/forge-std + version: github.com/foundry-rs/forge-std/1d0766bc5d814f117c7b1e643828f7d85024fb51 + prettier: + specifier: ^2.8.8 + version: 2.8.8 + sentinellist: + specifier: github:zeroknots/sentinellist + version: github.com/zeroknots/sentinellist/6294bf412489c0f6d3b9c92ad0aceb08c5b8704b + solady: + specifier: github:vectorized/solady + version: github.com/vectorized/solady/72e47ca417d24a30801b2921584e8486462cfc7b + solhint: + specifier: ^4.1.1 + version: 4.1.1(typescript@5.3.3) + + packages/modulekit: + devDependencies: + '@ERC4337/account-abstraction': + specifier: github:kopy-kat/account-abstraction#develop + version: github.com/kopy-kat/account-abstraction/3c0127e9f7cb76e4a0fdb2d35cac51900f252bdc(ethers@5.4.0)(hardhat@2.20.1)(lodash@4.17.21)(typechain@5.2.0) + '@ERC4337/account-abstraction-v0.6': + specifier: github:eth-infinitism/account-abstraction#v0.6.0 + version: github.com/eth-infinitism/account-abstraction/7174d6d845618dbd11cee68eefa715f5263690b6(ethers@5.4.0)(hardhat@2.20.1)(lodash@4.17.21)(typechain@5.2.0) + '@openzeppelin/contracts': + specifier: 5.0.1 + version: 5.0.1 + '@prb/math': + specifier: ^4.0.2 + version: 4.0.2 + '@rhinestone/safe7579': + specifier: workspace:* + version: link:../../accounts/safe7579 + '@rhinestone/sessionkeymanager': + specifier: workspace:* + version: link:../SessionKeyManager + '@safe-global/safe-contracts': + specifier: ^1.4.1 + version: 1.4.1(ethers@5.4.0) + ds-test: + specifier: github:dapphub/ds-test + version: github.com/dapphub/ds-test/e282159d5170298eb2455a6c05280ab5a73a4ef0 + erc4337-validation: + specifier: github:rhinestonewtf/erc4337-validation + version: github.com/rhinestonewtf/erc4337-validation/19a97d86f8f29709664334078925b2a843be19e0 + erc7579: + specifier: github:erc7579/erc7579-implementation + version: github.com/erc7579/erc7579-implementation/1548b5bd9d20c257926d84952190cc6877ba7a57 + forge-std: + specifier: github:foundry-rs/forge-std + version: github.com/foundry-rs/forge-std/1d0766bc5d814f117c7b1e643828f7d85024fb51 + prettier: + specifier: ^2.8.8 + version: 2.8.8 + sentinellist: + specifier: github:zeroknots/sentinellist + version: github.com/zeroknots/sentinellist/6294bf412489c0f6d3b9c92ad0aceb08c5b8704b + solady: + specifier: github:vectorized/solady + version: github.com/vectorized/solady/72e47ca417d24a30801b2921584e8486462cfc7b + solarray: + specifier: github:sablier-labs/solarray + version: github.com/sablier-labs/solarray/6bf10cb34cdace52a3ba5fe437e78cc82df92684 + solhint: + specifier: ^4.1.1 + version: 4.1.1(typescript@5.3.3) packages: @@ -732,6 +898,14 @@ packages: ethers: 5.4.0 dev: true + /@gnosis.pm/safe-contracts@1.3.0(ethers@5.7.2): + resolution: {integrity: sha512-1p+1HwGvxGUVzVkFjNzglwHrLNA67U/axP0Ct85FzzH8yhGJb4t9jDjPYocVMzLorDoWAfKicGy1akPY9jXRVw==} + peerDependencies: + ethers: ^5.1.4 + dependencies: + ethers: 5.7.2 + dev: true + /@metamask/eth-sig-util@4.0.1: resolution: {integrity: sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ==} engines: {node: '>=12.0.0'} @@ -1089,6 +1263,7 @@ packages: /@openzeppelin/contracts@5.0.1: resolution: {integrity: sha512-yQJaT5HDp9hYOOp4jTYxMsR02gdFZFXhewX5HW9Jo4fsqSVqqyIO/xTHdWDaKX5a3pv1txmf076Lziz+sO7L1w==} + dev: true /@pnpm/config.env-replace@1.1.0: resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==} @@ -1113,7 +1288,7 @@ packages: /@prb/math@4.0.2: resolution: {integrity: sha512-kJgqvXR6iyU7+N959RzggSFhBdnRuSDnc/bs8u6MzdWw7aYIUaAr+uMVdpP6Dheypjerd7sfJgFOs19FRFhscg==} - dev: false + dev: true /@safe-global/safe-contracts@1.4.1(ethers@5.4.0): resolution: {integrity: sha512-fP1jewywSwsIniM04NsqPyVRFKPMAuirC3ftA/TA4X3Zc5EnwQp/UCJUU2PL/37/z/jMo8UUaJ+pnFNWmMU7dQ==} @@ -1275,13 +1450,13 @@ packages: /@types/bn.js@4.11.6: resolution: {integrity: sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==} dependencies: - '@types/node': 20.11.19 + '@types/node': 20.11.20 dev: true /@types/bn.js@5.1.5: resolution: {integrity: sha512-V46N0zwKRF5Q00AZ6hWtN0T8gGmDUaUzLWQvHFo5yThtVwK/VCenFY3wXVbOvNfajEpsTfQM4IN9k/d6gUVX3A==} dependencies: - '@types/node': 20.11.19 + '@types/node': 20.11.20 dev: true /@types/debug@4.1.12: @@ -1294,7 +1469,7 @@ packages: resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} dependencies: '@types/minimatch': 5.1.2 - '@types/node': 20.11.19 + '@types/node': 20.11.20 dev: true /@types/http-cache-semantics@4.0.4: @@ -1317,8 +1492,8 @@ packages: resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} dev: true - /@types/node@20.11.19: - resolution: {integrity: sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ==} + /@types/node@20.11.20: + resolution: {integrity: sha512-7/rR21OS+fq8IyHTgtLkDK949uzsa6n8BkziAKtPVpugIkO6D+/ooXMvzXxDnZrmtXVfjb1bKQafYpb8s89LOg==} dependencies: undici-types: 5.26.5 dev: true @@ -1326,7 +1501,7 @@ packages: /@types/pbkdf2@3.1.2: resolution: {integrity: sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew==} dependencies: - '@types/node': 20.11.19 + '@types/node': 20.11.20 dev: true /@types/prettier@2.7.3: @@ -1340,14 +1515,14 @@ packages: /@types/readable-stream@2.3.15: resolution: {integrity: sha512-oM5JSKQCcICF1wvGgmecmHldZ48OZamtMxcGGVICOJA8o8cahXC1zEVAif8iwoc5j8etxFaRFnf095+CDsuoFQ==} dependencies: - '@types/node': 20.11.19 + '@types/node': 20.11.20 safe-buffer: 5.1.2 dev: true /@types/secp256k1@4.0.6: resolution: {integrity: sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ==} dependencies: - '@types/node': 20.11.19 + '@types/node': 20.11.20 dev: true /abbrev@1.0.9: @@ -2574,6 +2749,16 @@ packages: hardhat: 2.20.1(typescript@5.3.3) dev: true + /hardhat-deploy-ethers@0.3.0-beta.13(ethers@5.7.2)(hardhat@2.20.1): + resolution: {integrity: sha512-PdWVcKB9coqWV1L7JTpfXRCI91Cgwsm7KLmBcwZ8f0COSm1xtABHZTyz3fvF6p42cTnz1VM0QnfDvMFlIRkSNw==} + peerDependencies: + ethers: ^5.0.0 + hardhat: ^2.0.0 + dependencies: + ethers: 5.7.2 + hardhat: 2.20.1(typescript@5.3.3) + dev: true + /hardhat-deploy@0.11.45: resolution: {integrity: sha512-aC8UNaq3JcORnEUIwV945iJuvBwi65tjHVDU3v6mOcqik7WAzHVCJ7cwmkkipsHrWysrB5YvGF1q9S1vIph83w==} dependencies: @@ -3076,7 +3261,7 @@ packages: resolution: {integrity: sha512-90Tvmg2NXwnKMgTafA01PRELsYNNRb/F2bj3nzdByTLLMUmgkgL8H/oeWcjZtVVffnBJyNjDcYxY7cdOE/WoHg==} engines: {node: '>=14.17'} dependencies: - '@types/node': 20.11.19 + '@types/node': 20.11.20 dev: true /md5.js@1.3.5: @@ -3810,8 +3995,8 @@ packages: - typescript dev: true - /solidity-coverage@0.8.7(hardhat@2.20.1): - resolution: {integrity: sha512-RzcPuNsIqVGq5F8rjQZPdI2EVdsRU7w2f1Uk1UY567n9eNcg5LSEQ3Q1WFoy9bi/2AD5SYbYK9SS/Nwh2oYbNw==} + /solidity-coverage@0.8.8(hardhat@2.20.1): + resolution: {integrity: sha512-7RN6/8YAFMQNeMdSulARtE0VC5JitBAUMwvkr10FkOK+nux5q+WykrgSZntkWrX/VHzRa096P4OOViO0T9Q9Cw==} hasBin: true peerDependencies: hardhat: ^2.11.0 @@ -4277,8 +4462,8 @@ packages: version: 1.0.0 dev: true - github.com/erc7579/erc7579-implementation/957cd05deeab6a9a85343bb8d1c9701705ed4ecf: - resolution: {tarball: https://codeload.github.com/erc7579/erc7579-implementation/tar.gz/957cd05deeab6a9a85343bb8d1c9701705ed4ecf} + github.com/erc7579/erc7579-implementation/1548b5bd9d20c257926d84952190cc6877ba7a57: + resolution: {tarball: https://codeload.github.com/erc7579/erc7579-implementation/tar.gz/1548b5bd9d20c257926d84952190cc6877ba7a57} name: micro-msa version: 0.3.1 dependencies: @@ -4301,7 +4486,38 @@ packages: ethereumjs-wallet: 1.0.2 hardhat-deploy: 0.11.45 hardhat-deploy-ethers: 0.3.0-beta.13(ethers@5.4.0)(hardhat@2.20.1) - solidity-coverage: 0.8.7(hardhat@2.20.1) + solidity-coverage: 0.8.8(hardhat@2.20.1) + source-map-support: 0.5.21 + table: 6.8.1 + typescript: 4.9.5 + transitivePeerDependencies: + - bufferutil + - encoding + - ethers + - hardhat + - lodash + - supports-color + - typechain + - utf-8-validate + dev: true + + github.com/eth-infinitism/account-abstraction/7174d6d845618dbd11cee68eefa715f5263690b6(ethers@5.7.2)(hardhat@2.20.1)(lodash@4.17.21)(typechain@5.2.0): + resolution: {tarball: https://codeload.github.com/eth-infinitism/account-abstraction/tar.gz/7174d6d845618dbd11cee68eefa715f5263690b6} + id: github.com/eth-infinitism/account-abstraction/7174d6d845618dbd11cee68eefa715f5263690b6 + name: accountabstraction + version: 0.6.0 + dependencies: + '@gnosis.pm/safe-contracts': 1.3.0(ethers@5.7.2) + '@nomiclabs/hardhat-etherscan': 2.1.8(hardhat@2.20.1) + '@openzeppelin/contracts': 4.9.5 + '@thehubbleproject/bls': 0.5.1 + '@typechain/hardhat': 2.3.1(hardhat@2.20.1)(lodash@4.17.21)(typechain@5.2.0) + '@types/mocha': 9.1.1 + ethereumjs-util: 7.1.5 + ethereumjs-wallet: 1.0.2 + hardhat-deploy: 0.11.45 + hardhat-deploy-ethers: 0.3.0-beta.13(ethers@5.7.2)(hardhat@2.20.1) + solidity-coverage: 0.8.8(hardhat@2.20.1) source-map-support: 0.5.21 table: 6.8.1 typescript: 4.9.5 @@ -4339,7 +4555,39 @@ packages: ethereumjs-wallet: 1.0.2 hardhat-deploy: 0.11.45 hardhat-deploy-ethers: 0.3.0-beta.13(ethers@5.4.0)(hardhat@2.20.1) - solidity-coverage: 0.8.7(hardhat@2.20.1) + solidity-coverage: 0.8.8(hardhat@2.20.1) + source-map-support: 0.5.21 + table: 6.8.1 + typescript: 4.9.5 + transitivePeerDependencies: + - bufferutil + - encoding + - ethers + - hardhat + - lodash + - supports-color + - typechain + - utf-8-validate + dev: true + + github.com/kopy-kat/account-abstraction/3c0127e9f7cb76e4a0fdb2d35cac51900f252bdc(ethers@5.7.2)(hardhat@2.20.1)(lodash@4.17.21)(typechain@5.2.0): + resolution: {tarball: https://codeload.github.com/kopy-kat/account-abstraction/tar.gz/3c0127e9f7cb76e4a0fdb2d35cac51900f252bdc} + id: github.com/kopy-kat/account-abstraction/3c0127e9f7cb76e4a0fdb2d35cac51900f252bdc + name: accountabstraction + version: 0.6.0 + dependencies: + '@nomiclabs/hardhat-etherscan': 2.1.8(hardhat@2.20.1) + '@openzeppelin/contracts': 5.0.1 + '@thehubbleproject/bls': 0.5.1 + '@typechain/hardhat': 2.3.1(hardhat@2.20.1)(lodash@4.17.21)(typechain@5.2.0) + '@types/debug': 4.1.12 + '@types/mocha': 9.1.1 + debug: 4.3.4(supports-color@8.1.1) + ethereumjs-util: 7.1.5 + ethereumjs-wallet: 1.0.2 + hardhat-deploy: 0.11.45 + hardhat-deploy-ethers: 0.3.0-beta.13(ethers@5.7.2)(hardhat@2.20.1) + solidity-coverage: 0.8.8(hardhat@2.20.1) source-map-support: 0.5.21 table: 6.8.1 typescript: 4.9.5 @@ -4360,13 +4608,7 @@ packages: version: 0.0.1 dependencies: '@openzeppelin/contracts': 5.0.1 - solady: github.com/vectorized/solady/1372606383445c0a247e6c58eb255a529734258a - dev: false - - github.com/rhinestonewtf/sessionkeymanager/96bb3be7444c0c304075b6fdb2d6fb4260e275cc: - resolution: {tarball: https://codeload.github.com/rhinestonewtf/sessionkeymanager/tar.gz/96bb3be7444c0c304075b6fdb2d6fb4260e275cc} - name: sessionkeyManager - version: 1.0.0 + solady: github.com/vectorized/solady/72e47ca417d24a30801b2921584e8486462cfc7b dev: true github.com/sablier-labs/solarray/6bf10cb34cdace52a3ba5fe437e78cc82df92684: @@ -4375,13 +4617,20 @@ packages: version: 1.0.0 dev: true - github.com/vectorized/solady/1372606383445c0a247e6c58eb255a529734258a: - resolution: {tarball: https://codeload.github.com/vectorized/solady/tar.gz/1372606383445c0a247e6c58eb255a529734258a} + github.com/transmissions11/solmate/c892309933b25c03d32b1b0d674df7ae292ba925: + resolution: {tarball: https://codeload.github.com/transmissions11/solmate/tar.gz/c892309933b25c03d32b1b0d674df7ae292ba925} + name: solmate + version: 6.2.0 + dev: true + + github.com/vectorized/solady/72e47ca417d24a30801b2921584e8486462cfc7b: + resolution: {tarball: https://codeload.github.com/vectorized/solady/tar.gz/72e47ca417d24a30801b2921584e8486462cfc7b} name: solady - version: 0.0.168 + version: 0.0.170 + dev: true - github.com/zeroknots/sentinellist/2783f466b6d9c457da0a240e392db183ca1607bb: - resolution: {tarball: https://codeload.github.com/zeroknots/sentinellist/tar.gz/2783f466b6d9c457da0a240e392db183ca1607bb} + github.com/zeroknots/sentinellist/6294bf412489c0f6d3b9c92ad0aceb08c5b8704b: + resolution: {tarball: https://codeload.github.com/zeroknots/sentinellist/tar.gz/6294bf412489c0f6d3b9c92ad0aceb08c5b8704b} name: sentinellist - version: 0.0.0 + version: 1.0.0 dev: true diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 00000000..460078c6 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,4 @@ +packages: + - accounts/** + - packages/** + - examples/ diff --git a/src/accounts/safe/pnpm-lock.yaml b/src/accounts/safe/pnpm-lock.yaml deleted file mode 100644 index df9e1d96..00000000 --- a/src/accounts/safe/pnpm-lock.yaml +++ /dev/null @@ -1,4456 +0,0 @@ -lockfileVersion: '6.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -devDependencies: - '@openzeppelin/contracts': - specifier: 5.0.1 - version: 5.0.1 - '@rhinestone/modulekit': - specifier: github:rhinestonewtf/modulekit - version: github.com/rhinestonewtf/modulekit/03c51550d68bfd46674bf8221f300318952439d4 - '@rhinestone/sessionkeymanager': - specifier: github:rhinestonewtf/sessionkeymanager - version: github.com/rhinestonewtf/sessionkeymanager/100f86b662bc16fbd7df374cd665a35c10f3a7b6 - '@safe-global/safe-contracts': - specifier: ^1.4.1 - version: 1.4.1(ethers@5.4.0) - account-abstraction: - specifier: github:eth-infinitism/account-abstraction#develop - version: github.com/eth-infinitism/account-abstraction/0766b38ad165bfaecdd60b46cf72db93aa6793a9(ethers@5.4.0)(hardhat@2.19.5)(lodash@4.17.21)(typechain@5.2.0) - ds-test: - specifier: github:dapphub/ds-test - version: github.com/dapphub/ds-test/e282159d5170298eb2455a6c05280ab5a73a4ef0 - erc7579: - specifier: github:erc7579/erc7579-implementation - version: github.com/erc7579/erc7579-implementation/15aa5bba6cbf287eeb2b094b4ade9d2567be3729 - forge-std: - specifier: github:foundry-rs/forge-std - version: github.com/foundry-rs/forge-std/4513bc2063f23c57bee6558799584b518d387a39 - prettier: - specifier: ^2.8.8 - version: 2.8.8 - sentinellist: - specifier: github:zeroknots/sentinellist - version: github.com/zeroknots/sentinellist/1f9ec0250f1b3f14ba5d200629e3d9f3264fde61 - solady: - specifier: github:vectorized/solady - version: github.com/vectorized/solady/54ea1543a229b88b44ccb6ec5ea570135811a7d9 - solarray: - specifier: github:sablier-labs/solarray - version: github.com/sablier-labs/solarray/6bf10cb34cdace52a3ba5fe437e78cc82df92684 - solhint: - specifier: ^4.1.1 - version: 4.1.1(typescript@5.3.3) - solmate: - specifier: github:transmissions11/solmate - version: github.com/transmissions11/solmate/c892309933b25c03d32b1b0d674df7ae292ba925 - -packages: - - /@babel/code-frame@7.23.5: - resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/highlight': 7.23.4 - chalk: 2.4.2 - dev: true - - /@babel/helper-validator-identifier@7.22.20: - resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/highlight@7.23.4: - resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-validator-identifier': 7.22.20 - chalk: 2.4.2 - js-tokens: 4.0.0 - dev: true - - /@chainsafe/as-sha256@0.3.1: - resolution: {integrity: sha512-hldFFYuf49ed7DAakWVXSJODuq3pzJEguD8tQ7h+sGkM18vja+OFoJI9krnGmgzyuZC2ETX0NOIcCTy31v2Mtg==} - dev: true - - /@chainsafe/persistent-merkle-tree@0.4.2: - resolution: {integrity: sha512-lLO3ihKPngXLTus/L7WHKaw9PnNJWizlOF1H9NNzHP6Xvh82vzg9F2bzkXhYIFshMZ2gTCEz8tq6STe7r5NDfQ==} - dependencies: - '@chainsafe/as-sha256': 0.3.1 - dev: true - - /@chainsafe/persistent-merkle-tree@0.5.0: - resolution: {integrity: sha512-l0V1b5clxA3iwQLXP40zYjyZYospQLZXzBVIhhr9kDg/1qHZfzzHw0jj4VPBijfYCArZDlPkRi1wZaV2POKeuw==} - dependencies: - '@chainsafe/as-sha256': 0.3.1 - dev: true - - /@chainsafe/ssz@0.10.2: - resolution: {integrity: sha512-/NL3Lh8K+0q7A3LsiFq09YXS9fPE+ead2rr7vM2QK8PLzrNsw3uqrif9bpRX5UxgeRjM+vYi+boCM3+GM4ovXg==} - dependencies: - '@chainsafe/as-sha256': 0.3.1 - '@chainsafe/persistent-merkle-tree': 0.5.0 - dev: true - - /@chainsafe/ssz@0.9.4: - resolution: {integrity: sha512-77Qtg2N1ayqs4Bg/wvnWfg5Bta7iy7IRh8XqXh7oNMeP2HBbBwx8m6yTpA8p0EHItWPEBkgZd5S5/LSlp3GXuQ==} - dependencies: - '@chainsafe/as-sha256': 0.3.1 - '@chainsafe/persistent-merkle-tree': 0.4.2 - case: 1.6.3 - dev: true - - /@ethereumjs/rlp@4.0.1: - resolution: {integrity: sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==} - engines: {node: '>=14'} - hasBin: true - dev: true - - /@ethereumjs/util@8.1.0: - resolution: {integrity: sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==} - engines: {node: '>=14'} - dependencies: - '@ethereumjs/rlp': 4.0.1 - ethereum-cryptography: 2.1.3 - micro-ftch: 0.3.1 - dev: true - - /@ethersproject/abi@5.4.0: - resolution: {integrity: sha512-9gU2H+/yK1j2eVMdzm6xvHSnMxk8waIHQGYCZg5uvAyH0rsAzxkModzBSpbAkAuhKFEovC2S9hM4nPuLym8IZw==} - dependencies: - '@ethersproject/address': 5.4.0 - '@ethersproject/bignumber': 5.4.0 - '@ethersproject/bytes': 5.4.0 - '@ethersproject/constants': 5.4.0 - '@ethersproject/hash': 5.4.0 - '@ethersproject/keccak256': 5.4.0 - '@ethersproject/logger': 5.4.0 - '@ethersproject/properties': 5.4.0 - '@ethersproject/strings': 5.4.0 - dev: true - - /@ethersproject/abi@5.7.0: - resolution: {integrity: sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==} - dependencies: - '@ethersproject/address': 5.7.0 - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/constants': 5.7.0 - '@ethersproject/hash': 5.7.0 - '@ethersproject/keccak256': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/properties': 5.7.0 - '@ethersproject/strings': 5.7.0 - dev: true - - /@ethersproject/abstract-provider@5.4.0: - resolution: {integrity: sha512-vPBR7HKUBY0lpdllIn7tLIzNN7DrVnhCLKSzY0l8WAwxz686m/aL7ASDzrVxV93GJtIub6N2t4dfZ29CkPOxgA==} - dependencies: - '@ethersproject/bignumber': 5.4.0 - '@ethersproject/bytes': 5.4.0 - '@ethersproject/logger': 5.4.0 - '@ethersproject/networks': 5.4.0 - '@ethersproject/properties': 5.4.0 - '@ethersproject/transactions': 5.4.0 - '@ethersproject/web': 5.4.0 - dev: true - - /@ethersproject/abstract-provider@5.7.0: - resolution: {integrity: sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==} - dependencies: - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/networks': 5.7.1 - '@ethersproject/properties': 5.7.0 - '@ethersproject/transactions': 5.7.0 - '@ethersproject/web': 5.7.1 - dev: true - - /@ethersproject/abstract-signer@5.4.0: - resolution: {integrity: sha512-AieQAzt05HJZS2bMofpuxMEp81AHufA5D6M4ScKwtolj041nrfIbIi8ciNW7+F59VYxXq+V4c3d568Q6l2m8ew==} - dependencies: - '@ethersproject/abstract-provider': 5.4.0 - '@ethersproject/bignumber': 5.4.0 - '@ethersproject/bytes': 5.4.0 - '@ethersproject/logger': 5.4.0 - '@ethersproject/properties': 5.4.0 - dev: true - - /@ethersproject/abstract-signer@5.7.0: - resolution: {integrity: sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==} - dependencies: - '@ethersproject/abstract-provider': 5.7.0 - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/properties': 5.7.0 - dev: true - - /@ethersproject/address@5.4.0: - resolution: {integrity: sha512-SD0VgOEkcACEG/C6xavlU1Hy3m5DGSXW3CUHkaaEHbAPPsgi0coP5oNPsxau8eTlZOk/bpa/hKeCNoK5IzVI2Q==} - dependencies: - '@ethersproject/bignumber': 5.4.0 - '@ethersproject/bytes': 5.4.0 - '@ethersproject/keccak256': 5.4.0 - '@ethersproject/logger': 5.4.0 - '@ethersproject/rlp': 5.4.0 - dev: true - - /@ethersproject/address@5.7.0: - resolution: {integrity: sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==} - dependencies: - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/keccak256': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/rlp': 5.7.0 - dev: true - - /@ethersproject/base64@5.4.0: - resolution: {integrity: sha512-CjQw6E17QDSSC5jiM9YpF7N1aSCHmYGMt9bWD8PWv6YPMxjsys2/Q8xLrROKI3IWJ7sFfZ8B3flKDTM5wlWuZQ==} - dependencies: - '@ethersproject/bytes': 5.4.0 - dev: true - - /@ethersproject/base64@5.7.0: - resolution: {integrity: sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==} - dependencies: - '@ethersproject/bytes': 5.7.0 - dev: true - - /@ethersproject/basex@5.4.0: - resolution: {integrity: sha512-J07+QCVJ7np2bcpxydFVf/CuYo9mZ7T73Pe7KQY4c1lRlrixMeblauMxHXD0MPwFmUHZIILDNViVkykFBZylbg==} - dependencies: - '@ethersproject/bytes': 5.4.0 - '@ethersproject/properties': 5.4.0 - dev: true - - /@ethersproject/basex@5.7.0: - resolution: {integrity: sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==} - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/properties': 5.7.0 - dev: true - - /@ethersproject/bignumber@5.4.0: - resolution: {integrity: sha512-OXUu9f9hO3vGRIPxU40cignXZVaYyfx6j9NNMjebKdnaCL3anCLSSy8/b8d03vY6dh7duCC0kW72GEC4tZer2w==} - dependencies: - '@ethersproject/bytes': 5.4.0 - '@ethersproject/logger': 5.4.0 - bn.js: 4.12.0 - dev: true - - /@ethersproject/bignumber@5.7.0: - resolution: {integrity: sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==} - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.7.0 - bn.js: 5.2.1 - dev: true - - /@ethersproject/bytes@5.4.0: - resolution: {integrity: sha512-H60ceqgTHbhzOj4uRc/83SCN9d+BSUnOkrr2intevqdtEMO1JFVZ1XL84OEZV+QjV36OaZYxtnt4lGmxcGsPfA==} - dependencies: - '@ethersproject/logger': 5.4.0 - dev: true - - /@ethersproject/bytes@5.7.0: - resolution: {integrity: sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==} - dependencies: - '@ethersproject/logger': 5.7.0 - dev: true - - /@ethersproject/constants@5.4.0: - resolution: {integrity: sha512-tzjn6S7sj9+DIIeKTJLjK9WGN2Tj0P++Z8ONEIlZjyoTkBuODN+0VfhAyYksKi43l1Sx9tX2VlFfzjfmr5Wl3Q==} - dependencies: - '@ethersproject/bignumber': 5.4.0 - dev: true - - /@ethersproject/constants@5.7.0: - resolution: {integrity: sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==} - dependencies: - '@ethersproject/bignumber': 5.7.0 - dev: true - - /@ethersproject/contracts@5.4.0: - resolution: {integrity: sha512-hkO3L3IhS1Z3ZtHtaAG/T87nQ7KiPV+/qnvutag35I0IkiQ8G3ZpCQ9NNOpSCzn4pWSW4CfzmtE02FcqnLI+hw==} - dependencies: - '@ethersproject/abi': 5.4.0 - '@ethersproject/abstract-provider': 5.4.0 - '@ethersproject/abstract-signer': 5.4.0 - '@ethersproject/address': 5.4.0 - '@ethersproject/bignumber': 5.4.0 - '@ethersproject/bytes': 5.4.0 - '@ethersproject/constants': 5.4.0 - '@ethersproject/logger': 5.4.0 - '@ethersproject/properties': 5.4.0 - '@ethersproject/transactions': 5.4.0 - dev: true - - /@ethersproject/contracts@5.7.0: - resolution: {integrity: sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==} - dependencies: - '@ethersproject/abi': 5.7.0 - '@ethersproject/abstract-provider': 5.7.0 - '@ethersproject/abstract-signer': 5.7.0 - '@ethersproject/address': 5.7.0 - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/constants': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/properties': 5.7.0 - '@ethersproject/transactions': 5.7.0 - dev: true - - /@ethersproject/hash@5.4.0: - resolution: {integrity: sha512-xymAM9tmikKgbktOCjW60Z5sdouiIIurkZUr9oW5NOex5uwxrbsYG09kb5bMcNjlVeJD3yPivTNzViIs1GCbqA==} - dependencies: - '@ethersproject/abstract-signer': 5.4.0 - '@ethersproject/address': 5.4.0 - '@ethersproject/bignumber': 5.4.0 - '@ethersproject/bytes': 5.4.0 - '@ethersproject/keccak256': 5.4.0 - '@ethersproject/logger': 5.4.0 - '@ethersproject/properties': 5.4.0 - '@ethersproject/strings': 5.4.0 - dev: true - - /@ethersproject/hash@5.7.0: - resolution: {integrity: sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==} - dependencies: - '@ethersproject/abstract-signer': 5.7.0 - '@ethersproject/address': 5.7.0 - '@ethersproject/base64': 5.7.0 - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/keccak256': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/properties': 5.7.0 - '@ethersproject/strings': 5.7.0 - dev: true - - /@ethersproject/hdnode@5.4.0: - resolution: {integrity: sha512-pKxdS0KAaeVGfZPp1KOiDLB0jba11tG6OP1u11QnYfb7pXn6IZx0xceqWRr6ygke8+Kw74IpOoSi7/DwANhy8Q==} - dependencies: - '@ethersproject/abstract-signer': 5.4.0 - '@ethersproject/basex': 5.4.0 - '@ethersproject/bignumber': 5.4.0 - '@ethersproject/bytes': 5.4.0 - '@ethersproject/logger': 5.4.0 - '@ethersproject/pbkdf2': 5.4.0 - '@ethersproject/properties': 5.4.0 - '@ethersproject/sha2': 5.4.0 - '@ethersproject/signing-key': 5.4.0 - '@ethersproject/strings': 5.4.0 - '@ethersproject/transactions': 5.4.0 - '@ethersproject/wordlists': 5.4.0 - dev: true - - /@ethersproject/hdnode@5.7.0: - resolution: {integrity: sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==} - dependencies: - '@ethersproject/abstract-signer': 5.7.0 - '@ethersproject/basex': 5.7.0 - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/pbkdf2': 5.7.0 - '@ethersproject/properties': 5.7.0 - '@ethersproject/sha2': 5.7.0 - '@ethersproject/signing-key': 5.7.0 - '@ethersproject/strings': 5.7.0 - '@ethersproject/transactions': 5.7.0 - '@ethersproject/wordlists': 5.7.0 - dev: true - - /@ethersproject/json-wallets@5.4.0: - resolution: {integrity: sha512-igWcu3fx4aiczrzEHwG1xJZo9l1cFfQOWzTqwRw/xcvxTk58q4f9M7cjh51EKphMHvrJtcezJ1gf1q1AUOfEQQ==} - dependencies: - '@ethersproject/abstract-signer': 5.4.0 - '@ethersproject/address': 5.4.0 - '@ethersproject/bytes': 5.4.0 - '@ethersproject/hdnode': 5.4.0 - '@ethersproject/keccak256': 5.4.0 - '@ethersproject/logger': 5.4.0 - '@ethersproject/pbkdf2': 5.4.0 - '@ethersproject/properties': 5.4.0 - '@ethersproject/random': 5.4.0 - '@ethersproject/strings': 5.4.0 - '@ethersproject/transactions': 5.4.0 - aes-js: 3.0.0 - scrypt-js: 3.0.1 - dev: true - - /@ethersproject/json-wallets@5.7.0: - resolution: {integrity: sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==} - dependencies: - '@ethersproject/abstract-signer': 5.7.0 - '@ethersproject/address': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/hdnode': 5.7.0 - '@ethersproject/keccak256': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/pbkdf2': 5.7.0 - '@ethersproject/properties': 5.7.0 - '@ethersproject/random': 5.7.0 - '@ethersproject/strings': 5.7.0 - '@ethersproject/transactions': 5.7.0 - aes-js: 3.0.0 - scrypt-js: 3.0.1 - dev: true - - /@ethersproject/keccak256@5.4.0: - resolution: {integrity: sha512-FBI1plWet+dPUvAzPAeHzRKiPpETQzqSUWR1wXJGHVWi4i8bOSrpC3NwpkPjgeXG7MnugVc1B42VbfnQikyC/A==} - dependencies: - '@ethersproject/bytes': 5.4.0 - js-sha3: 0.5.7 - dev: true - - /@ethersproject/keccak256@5.7.0: - resolution: {integrity: sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==} - dependencies: - '@ethersproject/bytes': 5.7.0 - js-sha3: 0.8.0 - dev: true - - /@ethersproject/logger@5.4.0: - resolution: {integrity: sha512-xYdWGGQ9P2cxBayt64d8LC8aPFJk6yWCawQi/4eJ4+oJdMMjEBMrIcIMZ9AxhwpPVmnBPrsB10PcXGmGAqgUEQ==} - dev: true - - /@ethersproject/logger@5.7.0: - resolution: {integrity: sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==} - dev: true - - /@ethersproject/networks@5.4.0: - resolution: {integrity: sha512-5fywtKRDcnaVeA5SjxXH3DOQqe/IbeD/plwydi94SdPps1fbDUrnO6SzDExaruBZXxpxJcO9upG9UComsei4bg==} - dependencies: - '@ethersproject/logger': 5.4.0 - dev: true - - /@ethersproject/networks@5.7.1: - resolution: {integrity: sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==} - dependencies: - '@ethersproject/logger': 5.7.0 - dev: true - - /@ethersproject/pbkdf2@5.4.0: - resolution: {integrity: sha512-x94aIv6tiA04g6BnazZSLoRXqyusawRyZWlUhKip2jvoLpzJuLb//KtMM6PEovE47pMbW+Qe1uw+68ameJjB7g==} - dependencies: - '@ethersproject/bytes': 5.4.0 - '@ethersproject/sha2': 5.4.0 - dev: true - - /@ethersproject/pbkdf2@5.7.0: - resolution: {integrity: sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==} - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/sha2': 5.7.0 - dev: true - - /@ethersproject/properties@5.4.0: - resolution: {integrity: sha512-7jczalGVRAJ+XSRvNA6D5sAwT4gavLq3OXPuV/74o3Rd2wuzSL035IMpIMgei4CYyBdialJMrTqkOnzccLHn4A==} - dependencies: - '@ethersproject/logger': 5.4.0 - dev: true - - /@ethersproject/properties@5.7.0: - resolution: {integrity: sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==} - dependencies: - '@ethersproject/logger': 5.7.0 - dev: true - - /@ethersproject/providers@5.4.0: - resolution: {integrity: sha512-XRmI9syLnkNdLA8ikEeg0duxmwSWTTt9S+xabnTOyI51JPJyhQ0QUNT+wvmod218ebb7rLupHDPQ7UVe2/+Tjg==} - dependencies: - '@ethersproject/abstract-provider': 5.4.0 - '@ethersproject/abstract-signer': 5.4.0 - '@ethersproject/address': 5.4.0 - '@ethersproject/basex': 5.4.0 - '@ethersproject/bignumber': 5.4.0 - '@ethersproject/bytes': 5.4.0 - '@ethersproject/constants': 5.4.0 - '@ethersproject/hash': 5.4.0 - '@ethersproject/logger': 5.4.0 - '@ethersproject/networks': 5.4.0 - '@ethersproject/properties': 5.4.0 - '@ethersproject/random': 5.4.0 - '@ethersproject/rlp': 5.4.0 - '@ethersproject/sha2': 5.4.0 - '@ethersproject/strings': 5.4.0 - '@ethersproject/transactions': 5.4.0 - '@ethersproject/web': 5.4.0 - bech32: 1.1.4 - ws: 7.4.6 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - dev: true - - /@ethersproject/providers@5.7.2: - resolution: {integrity: sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==} - dependencies: - '@ethersproject/abstract-provider': 5.7.0 - '@ethersproject/abstract-signer': 5.7.0 - '@ethersproject/address': 5.7.0 - '@ethersproject/base64': 5.7.0 - '@ethersproject/basex': 5.7.0 - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/constants': 5.7.0 - '@ethersproject/hash': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/networks': 5.7.1 - '@ethersproject/properties': 5.7.0 - '@ethersproject/random': 5.7.0 - '@ethersproject/rlp': 5.7.0 - '@ethersproject/sha2': 5.7.0 - '@ethersproject/strings': 5.7.0 - '@ethersproject/transactions': 5.7.0 - '@ethersproject/web': 5.7.1 - bech32: 1.1.4 - ws: 7.4.6 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - dev: true - - /@ethersproject/random@5.4.0: - resolution: {integrity: sha512-pnpWNQlf0VAZDEOVp1rsYQosmv2o0ITS/PecNw+mS2/btF8eYdspkN0vIXrCMtkX09EAh9bdk8GoXmFXM1eAKw==} - dependencies: - '@ethersproject/bytes': 5.4.0 - '@ethersproject/logger': 5.4.0 - dev: true - - /@ethersproject/random@5.7.0: - resolution: {integrity: sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==} - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.7.0 - dev: true - - /@ethersproject/rlp@5.4.0: - resolution: {integrity: sha512-0I7MZKfi+T5+G8atId9QaQKHRvvasM/kqLyAH4XxBCBchAooH2EX5rL9kYZWwcm3awYV+XC7VF6nLhfeQFKVPg==} - dependencies: - '@ethersproject/bytes': 5.4.0 - '@ethersproject/logger': 5.4.0 - dev: true - - /@ethersproject/rlp@5.7.0: - resolution: {integrity: sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==} - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.7.0 - dev: true - - /@ethersproject/sha2@5.4.0: - resolution: {integrity: sha512-siheo36r1WD7Cy+bDdE1BJ8y0bDtqXCOxRMzPa4bV1TGt/eTUUt03BHoJNB6reWJD8A30E/pdJ8WFkq+/uz4Gg==} - dependencies: - '@ethersproject/bytes': 5.4.0 - '@ethersproject/logger': 5.4.0 - hash.js: 1.1.7 - dev: true - - /@ethersproject/sha2@5.7.0: - resolution: {integrity: sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==} - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.7.0 - hash.js: 1.1.7 - dev: true - - /@ethersproject/signing-key@5.4.0: - resolution: {integrity: sha512-q8POUeywx6AKg2/jX9qBYZIAmKSB4ubGXdQ88l40hmATj29JnG5pp331nAWwwxPn2Qao4JpWHNZsQN+bPiSW9A==} - dependencies: - '@ethersproject/bytes': 5.4.0 - '@ethersproject/logger': 5.4.0 - '@ethersproject/properties': 5.4.0 - bn.js: 4.12.0 - elliptic: 6.5.4 - hash.js: 1.1.7 - dev: true - - /@ethersproject/signing-key@5.7.0: - resolution: {integrity: sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==} - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/properties': 5.7.0 - bn.js: 5.2.1 - elliptic: 6.5.4 - hash.js: 1.1.7 - dev: true - - /@ethersproject/solidity@5.4.0: - resolution: {integrity: sha512-XFQTZ7wFSHOhHcV1DpcWj7VXECEiSrBuv7JErJvB9Uo+KfCdc3QtUZV+Vjh/AAaYgezUEKbCtE6Khjm44seevQ==} - dependencies: - '@ethersproject/bignumber': 5.4.0 - '@ethersproject/bytes': 5.4.0 - '@ethersproject/keccak256': 5.4.0 - '@ethersproject/sha2': 5.4.0 - '@ethersproject/strings': 5.4.0 - dev: true - - /@ethersproject/solidity@5.7.0: - resolution: {integrity: sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==} - dependencies: - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/keccak256': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/sha2': 5.7.0 - '@ethersproject/strings': 5.7.0 - dev: true - - /@ethersproject/strings@5.4.0: - resolution: {integrity: sha512-k/9DkH5UGDhv7aReXLluFG5ExurwtIpUfnDNhQA29w896Dw3i4uDTz01Quaptbks1Uj9kI8wo9tmW73wcIEaWA==} - dependencies: - '@ethersproject/bytes': 5.4.0 - '@ethersproject/constants': 5.4.0 - '@ethersproject/logger': 5.4.0 - dev: true - - /@ethersproject/strings@5.7.0: - resolution: {integrity: sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==} - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/constants': 5.7.0 - '@ethersproject/logger': 5.7.0 - dev: true - - /@ethersproject/transactions@5.4.0: - resolution: {integrity: sha512-s3EjZZt7xa4BkLknJZ98QGoIza94rVjaEed0rzZ/jB9WrIuu/1+tjvYCWzVrystXtDswy7TPBeIepyXwSYa4WQ==} - dependencies: - '@ethersproject/address': 5.4.0 - '@ethersproject/bignumber': 5.4.0 - '@ethersproject/bytes': 5.4.0 - '@ethersproject/constants': 5.4.0 - '@ethersproject/keccak256': 5.4.0 - '@ethersproject/logger': 5.4.0 - '@ethersproject/properties': 5.4.0 - '@ethersproject/rlp': 5.4.0 - '@ethersproject/signing-key': 5.4.0 - dev: true - - /@ethersproject/transactions@5.7.0: - resolution: {integrity: sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==} - dependencies: - '@ethersproject/address': 5.7.0 - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/constants': 5.7.0 - '@ethersproject/keccak256': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/properties': 5.7.0 - '@ethersproject/rlp': 5.7.0 - '@ethersproject/signing-key': 5.7.0 - dev: true - - /@ethersproject/units@5.4.0: - resolution: {integrity: sha512-Z88krX40KCp+JqPCP5oPv5p750g+uU6gopDYRTBGcDvOASh6qhiEYCRatuM/suC4S2XW9Zz90QI35MfSrTIaFg==} - dependencies: - '@ethersproject/bignumber': 5.4.0 - '@ethersproject/constants': 5.4.0 - '@ethersproject/logger': 5.4.0 - dev: true - - /@ethersproject/units@5.7.0: - resolution: {integrity: sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==} - dependencies: - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/constants': 5.7.0 - '@ethersproject/logger': 5.7.0 - dev: true - - /@ethersproject/wallet@5.4.0: - resolution: {integrity: sha512-wU29majLjM6AjCjpat21mPPviG+EpK7wY1+jzKD0fg3ui5fgedf2zEu1RDgpfIMsfn8fJHJuzM4zXZ2+hSHaSQ==} - dependencies: - '@ethersproject/abstract-provider': 5.4.0 - '@ethersproject/abstract-signer': 5.4.0 - '@ethersproject/address': 5.4.0 - '@ethersproject/bignumber': 5.4.0 - '@ethersproject/bytes': 5.4.0 - '@ethersproject/hash': 5.4.0 - '@ethersproject/hdnode': 5.4.0 - '@ethersproject/json-wallets': 5.4.0 - '@ethersproject/keccak256': 5.4.0 - '@ethersproject/logger': 5.4.0 - '@ethersproject/properties': 5.4.0 - '@ethersproject/random': 5.4.0 - '@ethersproject/signing-key': 5.4.0 - '@ethersproject/transactions': 5.4.0 - '@ethersproject/wordlists': 5.4.0 - dev: true - - /@ethersproject/wallet@5.7.0: - resolution: {integrity: sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==} - dependencies: - '@ethersproject/abstract-provider': 5.7.0 - '@ethersproject/abstract-signer': 5.7.0 - '@ethersproject/address': 5.7.0 - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/hash': 5.7.0 - '@ethersproject/hdnode': 5.7.0 - '@ethersproject/json-wallets': 5.7.0 - '@ethersproject/keccak256': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/properties': 5.7.0 - '@ethersproject/random': 5.7.0 - '@ethersproject/signing-key': 5.7.0 - '@ethersproject/transactions': 5.7.0 - '@ethersproject/wordlists': 5.7.0 - dev: true - - /@ethersproject/web@5.4.0: - resolution: {integrity: sha512-1bUusGmcoRLYgMn6c1BLk1tOKUIFuTg8j+6N8lYlbMpDesnle+i3pGSagGNvwjaiLo4Y5gBibwctpPRmjrh4Og==} - dependencies: - '@ethersproject/base64': 5.4.0 - '@ethersproject/bytes': 5.4.0 - '@ethersproject/logger': 5.4.0 - '@ethersproject/properties': 5.4.0 - '@ethersproject/strings': 5.4.0 - dev: true - - /@ethersproject/web@5.7.1: - resolution: {integrity: sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==} - dependencies: - '@ethersproject/base64': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/properties': 5.7.0 - '@ethersproject/strings': 5.7.0 - dev: true - - /@ethersproject/wordlists@5.4.0: - resolution: {integrity: sha512-FemEkf6a+EBKEPxlzeVgUaVSodU7G0Na89jqKjmWMlDB0tomoU8RlEMgUvXyqtrg8N4cwpLh8nyRnm1Nay1isA==} - dependencies: - '@ethersproject/bytes': 5.4.0 - '@ethersproject/hash': 5.4.0 - '@ethersproject/logger': 5.4.0 - '@ethersproject/properties': 5.4.0 - '@ethersproject/strings': 5.4.0 - dev: true - - /@ethersproject/wordlists@5.7.0: - resolution: {integrity: sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==} - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/hash': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/properties': 5.7.0 - '@ethersproject/strings': 5.7.0 - dev: true - - /@fastify/busboy@2.1.0: - resolution: {integrity: sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==} - engines: {node: '>=14'} - dev: true - - /@metamask/eth-sig-util@4.0.1: - resolution: {integrity: sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ==} - engines: {node: '>=12.0.0'} - dependencies: - ethereumjs-abi: 0.6.8 - ethereumjs-util: 6.2.1 - ethjs-util: 0.1.6 - tweetnacl: 1.0.3 - tweetnacl-util: 0.15.1 - dev: true - - /@noble/curves@1.3.0: - resolution: {integrity: sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA==} - dependencies: - '@noble/hashes': 1.3.3 - dev: true - - /@noble/hashes@1.2.0: - resolution: {integrity: sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==} - dev: true - - /@noble/hashes@1.3.3: - resolution: {integrity: sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==} - engines: {node: '>= 16'} - dev: true - - /@noble/secp256k1@1.7.1: - resolution: {integrity: sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==} - dev: true - - /@nodelib/fs.scandir@2.1.5: - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - dev: true - - /@nodelib/fs.stat@2.0.5: - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - dev: true - - /@nodelib/fs.walk@1.2.8: - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.17.0 - dev: true - - /@nomicfoundation/ethereumjs-block@5.0.2: - resolution: {integrity: sha512-hSe6CuHI4SsSiWWjHDIzWhSiAVpzMUcDRpWYzN0T9l8/Rz7xNn3elwVOJ/tAyS0LqL6vitUD78Uk7lQDXZun7Q==} - engines: {node: '>=14'} - dependencies: - '@nomicfoundation/ethereumjs-common': 4.0.2 - '@nomicfoundation/ethereumjs-rlp': 5.0.2 - '@nomicfoundation/ethereumjs-trie': 6.0.2 - '@nomicfoundation/ethereumjs-tx': 5.0.2 - '@nomicfoundation/ethereumjs-util': 9.0.2 - ethereum-cryptography: 0.1.3 - ethers: 5.7.2 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - dev: true - - /@nomicfoundation/ethereumjs-blockchain@7.0.2: - resolution: {integrity: sha512-8UUsSXJs+MFfIIAKdh3cG16iNmWzWC/91P40sazNvrqhhdR/RtGDlFk2iFTGbBAZPs2+klZVzhRX8m2wvuvz3w==} - engines: {node: '>=14'} - dependencies: - '@nomicfoundation/ethereumjs-block': 5.0.2 - '@nomicfoundation/ethereumjs-common': 4.0.2 - '@nomicfoundation/ethereumjs-ethash': 3.0.2 - '@nomicfoundation/ethereumjs-rlp': 5.0.2 - '@nomicfoundation/ethereumjs-trie': 6.0.2 - '@nomicfoundation/ethereumjs-tx': 5.0.2 - '@nomicfoundation/ethereumjs-util': 9.0.2 - abstract-level: 1.0.4 - debug: 4.3.4(supports-color@8.1.1) - ethereum-cryptography: 0.1.3 - level: 8.0.1 - lru-cache: 5.1.1 - memory-level: 1.0.0 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - dev: true - - /@nomicfoundation/ethereumjs-common@4.0.2: - resolution: {integrity: sha512-I2WGP3HMGsOoycSdOTSqIaES0ughQTueOsddJ36aYVpI3SN8YSusgRFLwzDJwRFVIYDKx/iJz0sQ5kBHVgdDwg==} - dependencies: - '@nomicfoundation/ethereumjs-util': 9.0.2 - crc-32: 1.2.2 - dev: true - - /@nomicfoundation/ethereumjs-ethash@3.0.2: - resolution: {integrity: sha512-8PfoOQCcIcO9Pylq0Buijuq/O73tmMVURK0OqdjhwqcGHYC2PwhbajDh7GZ55ekB0Px197ajK3PQhpKoiI/UPg==} - engines: {node: '>=14'} - dependencies: - '@nomicfoundation/ethereumjs-block': 5.0.2 - '@nomicfoundation/ethereumjs-rlp': 5.0.2 - '@nomicfoundation/ethereumjs-util': 9.0.2 - abstract-level: 1.0.4 - bigint-crypto-utils: 3.3.0 - ethereum-cryptography: 0.1.3 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - dev: true - - /@nomicfoundation/ethereumjs-evm@2.0.2: - resolution: {integrity: sha512-rBLcUaUfANJxyOx9HIdMX6uXGin6lANCulIm/pjMgRqfiCRMZie3WKYxTSd8ZE/d+qT+zTedBF4+VHTdTSePmQ==} - engines: {node: '>=14'} - dependencies: - '@ethersproject/providers': 5.7.2 - '@nomicfoundation/ethereumjs-common': 4.0.2 - '@nomicfoundation/ethereumjs-tx': 5.0.2 - '@nomicfoundation/ethereumjs-util': 9.0.2 - debug: 4.3.4(supports-color@8.1.1) - ethereum-cryptography: 0.1.3 - mcl-wasm: 0.7.9 - rustbn.js: 0.2.0 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - dev: true - - /@nomicfoundation/ethereumjs-rlp@5.0.2: - resolution: {integrity: sha512-QwmemBc+MMsHJ1P1QvPl8R8p2aPvvVcKBbvHnQOKBpBztEo0omN0eaob6FeZS/e3y9NSe+mfu3nNFBHszqkjTA==} - engines: {node: '>=14'} - hasBin: true - dev: true - - /@nomicfoundation/ethereumjs-statemanager@2.0.2: - resolution: {integrity: sha512-dlKy5dIXLuDubx8Z74sipciZnJTRSV/uHG48RSijhgm1V7eXYFC567xgKtsKiVZB1ViTP9iFL4B6Je0xD6X2OA==} - dependencies: - '@nomicfoundation/ethereumjs-common': 4.0.2 - '@nomicfoundation/ethereumjs-rlp': 5.0.2 - debug: 4.3.4(supports-color@8.1.1) - ethereum-cryptography: 0.1.3 - ethers: 5.7.2 - js-sdsl: 4.4.2 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - dev: true - - /@nomicfoundation/ethereumjs-trie@6.0.2: - resolution: {integrity: sha512-yw8vg9hBeLYk4YNg5MrSJ5H55TLOv2FSWUTROtDtTMMmDGROsAu+0tBjiNGTnKRi400M6cEzoFfa89Fc5k8NTQ==} - engines: {node: '>=14'} - dependencies: - '@nomicfoundation/ethereumjs-rlp': 5.0.2 - '@nomicfoundation/ethereumjs-util': 9.0.2 - '@types/readable-stream': 2.3.15 - ethereum-cryptography: 0.1.3 - readable-stream: 3.6.2 - dev: true - - /@nomicfoundation/ethereumjs-tx@5.0.2: - resolution: {integrity: sha512-T+l4/MmTp7VhJeNloMkM+lPU3YMUaXdcXgTGCf8+ZFvV9NYZTRLFekRwlG6/JMmVfIfbrW+dRRJ9A6H5Q/Z64g==} - engines: {node: '>=14'} - dependencies: - '@chainsafe/ssz': 0.9.4 - '@ethersproject/providers': 5.7.2 - '@nomicfoundation/ethereumjs-common': 4.0.2 - '@nomicfoundation/ethereumjs-rlp': 5.0.2 - '@nomicfoundation/ethereumjs-util': 9.0.2 - ethereum-cryptography: 0.1.3 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - dev: true - - /@nomicfoundation/ethereumjs-util@9.0.2: - resolution: {integrity: sha512-4Wu9D3LykbSBWZo8nJCnzVIYGvGCuyiYLIJa9XXNVt1q1jUzHdB+sJvx95VGCpPkCT+IbLecW6yfzy3E1bQrwQ==} - engines: {node: '>=14'} - dependencies: - '@chainsafe/ssz': 0.10.2 - '@nomicfoundation/ethereumjs-rlp': 5.0.2 - ethereum-cryptography: 0.1.3 - dev: true - - /@nomicfoundation/ethereumjs-vm@7.0.2: - resolution: {integrity: sha512-Bj3KZT64j54Tcwr7Qm/0jkeZXJMfdcAtRBedou+Hx0dPOSIgqaIr0vvLwP65TpHbak2DmAq+KJbW2KNtIoFwvA==} - engines: {node: '>=14'} - dependencies: - '@nomicfoundation/ethereumjs-block': 5.0.2 - '@nomicfoundation/ethereumjs-blockchain': 7.0.2 - '@nomicfoundation/ethereumjs-common': 4.0.2 - '@nomicfoundation/ethereumjs-evm': 2.0.2 - '@nomicfoundation/ethereumjs-rlp': 5.0.2 - '@nomicfoundation/ethereumjs-statemanager': 2.0.2 - '@nomicfoundation/ethereumjs-trie': 6.0.2 - '@nomicfoundation/ethereumjs-tx': 5.0.2 - '@nomicfoundation/ethereumjs-util': 9.0.2 - debug: 4.3.4(supports-color@8.1.1) - ethereum-cryptography: 0.1.3 - mcl-wasm: 0.7.9 - rustbn.js: 0.2.0 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - dev: true - - /@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.1: - resolution: {integrity: sha512-KcTodaQw8ivDZyF+D76FokN/HdpgGpfjc/gFCImdLUyqB6eSWVaZPazMbeAjmfhx3R0zm/NYVzxwAokFKgrc0w==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@nomicfoundation/solidity-analyzer-darwin-x64@0.1.1: - resolution: {integrity: sha512-XhQG4BaJE6cIbjAVtzGOGbK3sn1BO9W29uhk9J8y8fZF1DYz0Doj8QDMfpMu+A6TjPDs61lbsmeYodIDnfveSA==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@nomicfoundation/solidity-analyzer-freebsd-x64@0.1.1: - resolution: {integrity: sha512-GHF1VKRdHW3G8CndkwdaeLkVBi5A9u2jwtlS7SLhBc8b5U/GcoL39Q+1CSO3hYqePNP+eV5YI7Zgm0ea6kMHoA==} - engines: {node: '>= 10'} - cpu: [x64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /@nomicfoundation/solidity-analyzer-linux-arm64-gnu@0.1.1: - resolution: {integrity: sha512-g4Cv2fO37ZsUENQ2vwPnZc2zRenHyAxHcyBjKcjaSmmkKrFr64yvzeNO8S3GBFCo90rfochLs99wFVGT/0owpg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@nomicfoundation/solidity-analyzer-linux-arm64-musl@0.1.1: - resolution: {integrity: sha512-WJ3CE5Oek25OGE3WwzK7oaopY8xMw9Lhb0mlYuJl/maZVo+WtP36XoQTb7bW/i8aAdHW5Z+BqrHMux23pvxG3w==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@nomicfoundation/solidity-analyzer-linux-x64-gnu@0.1.1: - resolution: {integrity: sha512-5WN7leSr5fkUBBjE4f3wKENUy9HQStu7HmWqbtknfXkkil+eNWiBV275IOlpXku7v3uLsXTOKpnnGHJYI2qsdA==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@nomicfoundation/solidity-analyzer-linux-x64-musl@0.1.1: - resolution: {integrity: sha512-KdYMkJOq0SYPQMmErv/63CwGwMm5XHenEna9X9aB8mQmhDBrYrlAOSsIPgFCUSL0hjxE3xHP65/EPXR/InD2+w==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@nomicfoundation/solidity-analyzer-win32-arm64-msvc@0.1.1: - resolution: {integrity: sha512-VFZASBfl4qiBYwW5xeY20exWhmv6ww9sWu/krWSesv3q5hA0o1JuzmPHR4LPN6SUZj5vcqci0O6JOL8BPw+APg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@nomicfoundation/solidity-analyzer-win32-ia32-msvc@0.1.1: - resolution: {integrity: sha512-JnFkYuyCSA70j6Si6cS1A9Gh1aHTEb8kOTBApp/c7NRTFGNMH8eaInKlyuuiIbvYFhlXW4LicqyYuWNNq9hkpQ==} - engines: {node: '>= 10'} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@nomicfoundation/solidity-analyzer-win32-x64-msvc@0.1.1: - resolution: {integrity: sha512-HrVJr6+WjIXGnw3Q9u6KQcbZCtk0caVWhCdFADySvRyUxJ8PnzlaP+MhwNE8oyT8OZ6ejHBRrrgjSqDCFXGirw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@nomicfoundation/solidity-analyzer@0.1.1: - resolution: {integrity: sha512-1LMtXj1puAxyFusBgUIy5pZk3073cNXYnXUpuNKFghHbIit/xZgbk0AokpUADbNm3gyD6bFWl3LRFh3dhVdREg==} - engines: {node: '>= 12'} - optionalDependencies: - '@nomicfoundation/solidity-analyzer-darwin-arm64': 0.1.1 - '@nomicfoundation/solidity-analyzer-darwin-x64': 0.1.1 - '@nomicfoundation/solidity-analyzer-freebsd-x64': 0.1.1 - '@nomicfoundation/solidity-analyzer-linux-arm64-gnu': 0.1.1 - '@nomicfoundation/solidity-analyzer-linux-arm64-musl': 0.1.1 - '@nomicfoundation/solidity-analyzer-linux-x64-gnu': 0.1.1 - '@nomicfoundation/solidity-analyzer-linux-x64-musl': 0.1.1 - '@nomicfoundation/solidity-analyzer-win32-arm64-msvc': 0.1.1 - '@nomicfoundation/solidity-analyzer-win32-ia32-msvc': 0.1.1 - '@nomicfoundation/solidity-analyzer-win32-x64-msvc': 0.1.1 - dev: true - - /@nomiclabs/hardhat-etherscan@2.1.8(hardhat@2.19.5): - resolution: {integrity: sha512-0+rj0SsZotVOcTLyDOxnOc3Gulo8upo0rsw/h+gBPcmtj91YqYJNhdARHoBxOhhE8z+5IUQPx+Dii04lXT14PA==} - deprecated: The @nomiclabs/hardhat-etherscan package is deprecated, please use @nomicfoundation/hardhat-verify instead - peerDependencies: - hardhat: ^2.0.4 - dependencies: - '@ethersproject/abi': 5.7.0 - '@ethersproject/address': 5.7.0 - cbor: 5.2.0 - debug: 4.3.4(supports-color@8.1.1) - fs-extra: 7.0.1 - hardhat: 2.19.5(typescript@5.3.3) - node-fetch: 2.7.0 - semver: 6.3.1 - transitivePeerDependencies: - - encoding - - supports-color - dev: true - - /@openzeppelin/contracts@5.0.1: - resolution: {integrity: sha512-yQJaT5HDp9hYOOp4jTYxMsR02gdFZFXhewX5HW9Jo4fsqSVqqyIO/xTHdWDaKX5a3pv1txmf076Lziz+sO7L1w==} - dev: true - - /@pnpm/config.env-replace@1.1.0: - resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==} - engines: {node: '>=12.22.0'} - dev: true - - /@pnpm/network.ca-file@1.0.2: - resolution: {integrity: sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==} - engines: {node: '>=12.22.0'} - dependencies: - graceful-fs: 4.2.10 - dev: true - - /@pnpm/npm-conf@2.2.2: - resolution: {integrity: sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA==} - engines: {node: '>=12'} - dependencies: - '@pnpm/config.env-replace': 1.1.0 - '@pnpm/network.ca-file': 1.0.2 - config-chain: 1.1.13 - dev: true - - /@safe-global/safe-contracts@1.4.1(ethers@5.4.0): - resolution: {integrity: sha512-fP1jewywSwsIniM04NsqPyVRFKPMAuirC3ftA/TA4X3Zc5EnwQp/UCJUU2PL/37/z/jMo8UUaJ+pnFNWmMU7dQ==} - peerDependencies: - ethers: 5.4.0 - dependencies: - ethers: 5.4.0 - dev: true - - /@scure/base@1.1.5: - resolution: {integrity: sha512-Brj9FiG2W1MRQSTB212YVPRrcbjkv48FoZi/u4l/zds/ieRrqsh7aUf6CLwkAq61oKXr/ZlTzlY66gLIj3TFTQ==} - dev: true - - /@scure/bip32@1.1.5: - resolution: {integrity: sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==} - dependencies: - '@noble/hashes': 1.2.0 - '@noble/secp256k1': 1.7.1 - '@scure/base': 1.1.5 - dev: true - - /@scure/bip32@1.3.3: - resolution: {integrity: sha512-LJaN3HwRbfQK0X1xFSi0Q9amqOgzQnnDngIt+ZlsBC3Bm7/nE7K0kwshZHyaru79yIVRv/e1mQAjZyuZG6jOFQ==} - dependencies: - '@noble/curves': 1.3.0 - '@noble/hashes': 1.3.3 - '@scure/base': 1.1.5 - dev: true - - /@scure/bip39@1.1.1: - resolution: {integrity: sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==} - dependencies: - '@noble/hashes': 1.2.0 - '@scure/base': 1.1.5 - dev: true - - /@scure/bip39@1.2.2: - resolution: {integrity: sha512-HYf9TUXG80beW+hGAt3TRM8wU6pQoYur9iNypTROm42dorCGmLnFe3eWjz3gOq6G62H2WRh0FCzAR1PI+29zIA==} - dependencies: - '@noble/hashes': 1.3.3 - '@scure/base': 1.1.5 - dev: true - - /@sentry/core@5.30.0: - resolution: {integrity: sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg==} - engines: {node: '>=6'} - dependencies: - '@sentry/hub': 5.30.0 - '@sentry/minimal': 5.30.0 - '@sentry/types': 5.30.0 - '@sentry/utils': 5.30.0 - tslib: 1.14.1 - dev: true - - /@sentry/hub@5.30.0: - resolution: {integrity: sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ==} - engines: {node: '>=6'} - dependencies: - '@sentry/types': 5.30.0 - '@sentry/utils': 5.30.0 - tslib: 1.14.1 - dev: true - - /@sentry/minimal@5.30.0: - resolution: {integrity: sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw==} - engines: {node: '>=6'} - dependencies: - '@sentry/hub': 5.30.0 - '@sentry/types': 5.30.0 - tslib: 1.14.1 - dev: true - - /@sentry/node@5.30.0: - resolution: {integrity: sha512-Br5oyVBF0fZo6ZS9bxbJZG4ApAjRqAnqFFurMVJJdunNb80brh7a5Qva2kjhm+U6r9NJAB5OmDyPkA1Qnt+QVg==} - engines: {node: '>=6'} - dependencies: - '@sentry/core': 5.30.0 - '@sentry/hub': 5.30.0 - '@sentry/tracing': 5.30.0 - '@sentry/types': 5.30.0 - '@sentry/utils': 5.30.0 - cookie: 0.4.2 - https-proxy-agent: 5.0.1 - lru_map: 0.3.3 - tslib: 1.14.1 - transitivePeerDependencies: - - supports-color - dev: true - - /@sentry/tracing@5.30.0: - resolution: {integrity: sha512-dUFowCr0AIMwiLD7Fs314Mdzcug+gBVo/+NCMyDw8tFxJkwWAKl7Qa2OZxLQ0ZHjakcj1hNKfCQJ9rhyfOl4Aw==} - engines: {node: '>=6'} - dependencies: - '@sentry/hub': 5.30.0 - '@sentry/minimal': 5.30.0 - '@sentry/types': 5.30.0 - '@sentry/utils': 5.30.0 - tslib: 1.14.1 - dev: true - - /@sentry/types@5.30.0: - resolution: {integrity: sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw==} - engines: {node: '>=6'} - dev: true - - /@sentry/utils@5.30.0: - resolution: {integrity: sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==} - engines: {node: '>=6'} - dependencies: - '@sentry/types': 5.30.0 - tslib: 1.14.1 - dev: true - - /@sindresorhus/is@5.6.0: - resolution: {integrity: sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==} - engines: {node: '>=14.16'} - dev: true - - /@solidity-parser/parser@0.16.2: - resolution: {integrity: sha512-PI9NfoA3P8XK2VBkK5oIfRgKDsicwDZfkVq9ZTBCQYGOP1N2owgY2dyLGyU5/J/hQs8KRk55kdmvTLjy3Mu3vg==} - dependencies: - antlr4ts: 0.5.0-alpha.4 - dev: true - - /@solidity-parser/parser@0.18.0: - resolution: {integrity: sha512-yfORGUIPgLck41qyN7nbwJRAx17/jAIXCTanHOJZhB6PJ1iAk/84b/xlsVKFSyNyLXIj0dhppoE0+CRws7wlzA==} - dev: true - - /@szmarczak/http-timer@5.0.1: - resolution: {integrity: sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==} - engines: {node: '>=14.16'} - dependencies: - defer-to-connect: 2.0.1 - dev: true - - /@thehubbleproject/bls@0.5.1: - resolution: {integrity: sha512-g5zeMZ8js/yg6MjFoC+pt0eqfCL2jC46yLY1LbKNriyqftB1tE3jpG/FMMDIW3x9/yRg/AgUb8Nluqj15tQs+A==} - dependencies: - ethers: 5.7.2 - mcl-wasm: 1.4.0 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - dev: true - - /@typechain/hardhat@2.3.1(hardhat@2.19.5)(lodash@4.17.21)(typechain@5.2.0): - resolution: {integrity: sha512-BQV8OKQi0KAzLXCdsPO0pZBNQQ6ra8A2ucC26uFX/kquRBtJu1yEyWnVSmtr07b5hyRoJRpzUeINLnyqz4/MAw==} - peerDependencies: - hardhat: ^2.0.10 - lodash: ^4.17.15 - typechain: ^5.1.2 - dependencies: - fs-extra: 9.1.0 - hardhat: 2.19.5(typescript@5.3.3) - lodash: 4.17.21 - typechain: 5.2.0(typescript@5.3.3) - dev: true - - /@types/bn.js@4.11.6: - resolution: {integrity: sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==} - dependencies: - '@types/node': 20.11.16 - dev: true - - /@types/bn.js@5.1.5: - resolution: {integrity: sha512-V46N0zwKRF5Q00AZ6hWtN0T8gGmDUaUzLWQvHFo5yThtVwK/VCenFY3wXVbOvNfajEpsTfQM4IN9k/d6gUVX3A==} - dependencies: - '@types/node': 20.11.16 - dev: true - - /@types/glob@7.2.0: - resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} - dependencies: - '@types/minimatch': 5.1.2 - '@types/node': 20.11.16 - dev: true - - /@types/http-cache-semantics@4.0.4: - resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} - dev: true - - /@types/lru-cache@5.1.1: - resolution: {integrity: sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==} - dev: true - - /@types/minimatch@5.1.2: - resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} - dev: true - - /@types/mocha@9.1.1: - resolution: {integrity: sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==} - dev: true - - /@types/node@20.11.16: - resolution: {integrity: sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ==} - dependencies: - undici-types: 5.26.5 - dev: true - - /@types/pbkdf2@3.1.2: - resolution: {integrity: sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew==} - dependencies: - '@types/node': 20.11.16 - dev: true - - /@types/prettier@2.7.3: - resolution: {integrity: sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==} - dev: true - - /@types/qs@6.9.11: - resolution: {integrity: sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==} - dev: true - - /@types/readable-stream@2.3.15: - resolution: {integrity: sha512-oM5JSKQCcICF1wvGgmecmHldZ48OZamtMxcGGVICOJA8o8cahXC1zEVAif8iwoc5j8etxFaRFnf095+CDsuoFQ==} - dependencies: - '@types/node': 20.11.16 - safe-buffer: 5.1.2 - dev: true - - /@types/secp256k1@4.0.6: - resolution: {integrity: sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ==} - dependencies: - '@types/node': 20.11.16 - dev: true - - /abbrev@1.0.9: - resolution: {integrity: sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q==} - dev: true - - /abstract-level@1.0.4: - resolution: {integrity: sha512-eUP/6pbXBkMbXFdx4IH2fVgvB7M0JvR7/lIL33zcs0IBcwjdzSSl31TOJsaCzmKSSDF9h8QYSOJux4Nd4YJqFg==} - engines: {node: '>=12'} - dependencies: - buffer: 6.0.3 - catering: 2.1.1 - is-buffer: 2.0.5 - level-supports: 4.0.1 - level-transcoder: 1.0.1 - module-error: 1.0.2 - queue-microtask: 1.2.3 - dev: true - - /address@1.2.2: - resolution: {integrity: sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==} - engines: {node: '>= 10.0.0'} - dev: true - - /adm-zip@0.4.16: - resolution: {integrity: sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==} - engines: {node: '>=0.3.0'} - dev: true - - /aes-js@3.0.0: - resolution: {integrity: sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==} - dev: true - - /aes-js@3.1.2: - resolution: {integrity: sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ==} - dev: true - - /agent-base@6.0.2: - resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} - engines: {node: '>= 6.0.0'} - dependencies: - debug: 4.3.4(supports-color@8.1.1) - transitivePeerDependencies: - - supports-color - dev: true - - /aggregate-error@3.1.0: - resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} - engines: {node: '>=8'} - dependencies: - clean-stack: 2.2.0 - indent-string: 4.0.0 - dev: true - - /ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - dev: true - - /ajv@8.12.0: - resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} - dependencies: - fast-deep-equal: 3.1.3 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - uri-js: 4.4.1 - dev: true - - /amdefine@1.0.1: - resolution: {integrity: sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==} - engines: {node: '>=0.4.2'} - requiresBuild: true - dev: true - optional: true - - /ansi-align@3.0.1: - resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} - dependencies: - string-width: 4.2.3 - dev: true - - /ansi-colors@4.1.1: - resolution: {integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==} - engines: {node: '>=6'} - dev: true - - /ansi-colors@4.1.3: - resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} - engines: {node: '>=6'} - dev: true - - /ansi-escapes@4.3.2: - resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} - engines: {node: '>=8'} - dependencies: - type-fest: 0.21.3 - dev: true - - /ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - dev: true - - /ansi-styles@3.2.1: - resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} - engines: {node: '>=4'} - dependencies: - color-convert: 1.9.3 - dev: true - - /ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - dependencies: - color-convert: 2.0.1 - dev: true - - /antlr4@4.13.1: - resolution: {integrity: sha512-kiXTspaRYvnIArgE97z5YVVf/cDVQABr3abFRR6mE7yesLMkgu4ujuyV/sgxafQ8wgve0DJQUJ38Z8tkgA2izA==} - engines: {node: '>=16'} - dev: true - - /antlr4ts@0.5.0-alpha.4: - resolution: {integrity: sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==} - dev: true - - /anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} - dependencies: - normalize-path: 3.0.0 - picomatch: 2.3.1 - dev: true - - /argparse@1.0.10: - resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} - dependencies: - sprintf-js: 1.0.3 - dev: true - - /argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - dev: true - - /array-back@1.0.4: - resolution: {integrity: sha512-1WxbZvrmyhkNoeYcizokbmh5oiOCIfyvGtcqbK3Ls1v1fKcquzxnQSceOx6tzq7jmai2kFLWIpGND2cLhH6TPw==} - engines: {node: '>=0.12.0'} - dependencies: - typical: 2.6.1 - dev: true - - /array-back@2.0.0: - resolution: {integrity: sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==} - engines: {node: '>=4'} - dependencies: - typical: 2.6.1 - dev: true - - /array-union@2.1.0: - resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} - engines: {node: '>=8'} - dev: true - - /ast-parents@0.0.1: - resolution: {integrity: sha512-XHusKxKz3zoYk1ic8Un640joHbFMhbqneyoZfoKnEGtf2ey9Uh/IdpcQplODdO/kENaMIWsD0nJm4+wX3UNLHA==} - dev: true - - /astral-regex@2.0.0: - resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} - engines: {node: '>=8'} - dev: true - - /async@1.5.2: - resolution: {integrity: sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==} - dev: true - - /asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - dev: true - - /at-least-node@1.0.0: - resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} - engines: {node: '>= 4.0.0'} - dev: true - - /axios@0.21.4(debug@4.3.4): - resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==} - dependencies: - follow-redirects: 1.15.5(debug@4.3.4) - transitivePeerDependencies: - - debug - dev: true - - /balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: true - - /base-x@3.0.9: - resolution: {integrity: sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==} - dependencies: - safe-buffer: 5.2.1 - dev: true - - /base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - dev: true - - /bech32@1.1.4: - resolution: {integrity: sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==} - dev: true - - /bigint-crypto-utils@3.3.0: - resolution: {integrity: sha512-jOTSb+drvEDxEq6OuUybOAv/xxoh3cuYRUIPyu8sSHQNKM303UQ2R1DAo45o1AkcIXw6fzbaFI1+xGGdaXs2lg==} - engines: {node: '>=14.0.0'} - dev: true - - /bignumber.js@9.1.2: - resolution: {integrity: sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==} - dev: true - - /binary-extensions@2.2.0: - resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} - engines: {node: '>=8'} - dev: true - - /blakejs@1.2.1: - resolution: {integrity: sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==} - dev: true - - /bn.js@4.11.6: - resolution: {integrity: sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==} - dev: true - - /bn.js@4.12.0: - resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==} - dev: true - - /bn.js@5.2.1: - resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} - dev: true - - /boxen@5.1.2: - resolution: {integrity: sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==} - engines: {node: '>=10'} - dependencies: - ansi-align: 3.0.1 - camelcase: 6.3.0 - chalk: 4.1.2 - cli-boxes: 2.2.1 - string-width: 4.2.3 - type-fest: 0.20.2 - widest-line: 3.1.0 - wrap-ansi: 7.0.0 - dev: true - - /brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - dev: true - - /brace-expansion@2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} - dependencies: - balanced-match: 1.0.2 - dev: true - - /braces@3.0.2: - resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} - engines: {node: '>=8'} - dependencies: - fill-range: 7.0.1 - dev: true - - /brorand@1.1.0: - resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} - dev: true - - /browser-level@1.0.1: - resolution: {integrity: sha512-XECYKJ+Dbzw0lbydyQuJzwNXtOpbMSq737qxJN11sIRTErOMShvDpbzTlgju7orJKvx4epULolZAuJGLzCmWRQ==} - dependencies: - abstract-level: 1.0.4 - catering: 2.1.1 - module-error: 1.0.2 - run-parallel-limit: 1.1.0 - dev: true - - /browser-stdout@1.3.1: - resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} - dev: true - - /browserify-aes@1.2.0: - resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==} - dependencies: - buffer-xor: 1.0.3 - cipher-base: 1.0.4 - create-hash: 1.2.0 - evp_bytestokey: 1.0.3 - inherits: 2.0.4 - safe-buffer: 5.2.1 - dev: true - - /bs58@4.0.1: - resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==} - dependencies: - base-x: 3.0.9 - dev: true - - /bs58check@2.1.2: - resolution: {integrity: sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==} - dependencies: - bs58: 4.0.1 - create-hash: 1.2.0 - safe-buffer: 5.2.1 - dev: true - - /buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - dev: true - - /buffer-xor@1.0.3: - resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} - dev: true - - /buffer@6.0.3: - resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - dev: true - - /bytes@3.1.2: - resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} - engines: {node: '>= 0.8'} - dev: true - - /cacheable-lookup@7.0.0: - resolution: {integrity: sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==} - engines: {node: '>=14.16'} - dev: true - - /cacheable-request@10.2.14: - resolution: {integrity: sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==} - engines: {node: '>=14.16'} - dependencies: - '@types/http-cache-semantics': 4.0.4 - get-stream: 6.0.1 - http-cache-semantics: 4.1.1 - keyv: 4.5.4 - mimic-response: 4.0.0 - normalize-url: 8.0.0 - responselike: 3.0.0 - dev: true - - /call-bind@1.0.5: - resolution: {integrity: sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==} - dependencies: - function-bind: 1.1.2 - get-intrinsic: 1.2.2 - set-function-length: 1.2.0 - dev: true - - /callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - dev: true - - /camelcase@6.3.0: - resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} - engines: {node: '>=10'} - dev: true - - /case@1.6.3: - resolution: {integrity: sha512-mzDSXIPaFwVDvZAHqZ9VlbyF4yyXRuX6IvB06WvPYkqJVO24kX1PPhv9bfpKNFZyxYFmmgo03HUiD8iklmJYRQ==} - engines: {node: '>= 0.8.0'} - dev: true - - /catering@2.1.1: - resolution: {integrity: sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w==} - engines: {node: '>=6'} - dev: true - - /cbor@5.2.0: - resolution: {integrity: sha512-5IMhi9e1QU76ppa5/ajP1BmMWZ2FHkhAhjeVKQ/EFCgYSEaeVaoGtL7cxJskf9oCCk+XjzaIdc3IuU/dbA/o2A==} - engines: {node: '>=6.0.0'} - dependencies: - bignumber.js: 9.1.2 - nofilter: 1.0.4 - dev: true - - /chalk@2.4.2: - resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} - engines: {node: '>=4'} - dependencies: - ansi-styles: 3.2.1 - escape-string-regexp: 1.0.5 - supports-color: 5.5.0 - dev: true - - /chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - dev: true - - /chokidar@3.5.3: - resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} - engines: {node: '>= 8.10.0'} - dependencies: - anymatch: 3.1.3 - braces: 3.0.2 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.6.0 - optionalDependencies: - fsevents: 2.3.3 - dev: true - - /ci-info@2.0.0: - resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} - dev: true - - /cipher-base@1.0.4: - resolution: {integrity: sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==} - dependencies: - inherits: 2.0.4 - safe-buffer: 5.2.1 - dev: true - - /classic-level@1.4.1: - resolution: {integrity: sha512-qGx/KJl3bvtOHrGau2WklEZuXhS3zme+jf+fsu6Ej7W7IP/C49v7KNlWIsT1jZu0YnfzSIYDGcEWpCa1wKGWXQ==} - engines: {node: '>=12'} - requiresBuild: true - dependencies: - abstract-level: 1.0.4 - catering: 2.1.1 - module-error: 1.0.2 - napi-macros: 2.2.2 - node-gyp-build: 4.8.0 - dev: true - - /clean-stack@2.2.0: - resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} - engines: {node: '>=6'} - dev: true - - /cli-boxes@2.2.1: - resolution: {integrity: sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==} - engines: {node: '>=6'} - dev: true - - /cliui@7.0.4: - resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - dev: true - - /color-convert@1.9.3: - resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} - dependencies: - color-name: 1.1.3 - dev: true - - /color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - dependencies: - color-name: 1.1.4 - dev: true - - /color-name@1.1.3: - resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - dev: true - - /color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: true - - /combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} - dependencies: - delayed-stream: 1.0.0 - dev: true - - /command-exists@1.2.9: - resolution: {integrity: sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==} - dev: true - - /command-line-args@4.0.7: - resolution: {integrity: sha512-aUdPvQRAyBvQd2n7jXcsMDz68ckBJELXNzBybCHOibUWEg0mWTnaYCSRU8h9R+aNRSvDihJtssSRCiDRpLaezA==} - hasBin: true - dependencies: - array-back: 2.0.0 - find-replace: 1.0.3 - typical: 2.6.1 - dev: true - - /commander@10.0.1: - resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} - engines: {node: '>=14'} - dev: true - - /commander@3.0.2: - resolution: {integrity: sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==} - dev: true - - /concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - dev: true - - /config-chain@1.1.13: - resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} - dependencies: - ini: 1.3.8 - proto-list: 1.2.4 - dev: true - - /cookie@0.4.2: - resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==} - engines: {node: '>= 0.6'} - dev: true - - /cosmiconfig@8.3.6(typescript@5.3.3): - resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} - engines: {node: '>=14'} - peerDependencies: - typescript: '>=4.9.5' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - import-fresh: 3.3.0 - js-yaml: 4.1.0 - parse-json: 5.2.0 - path-type: 4.0.0 - typescript: 5.3.3 - dev: true - - /crc-32@1.2.2: - resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} - engines: {node: '>=0.8'} - hasBin: true - dev: true - - /create-hash@1.2.0: - resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} - dependencies: - cipher-base: 1.0.4 - inherits: 2.0.4 - md5.js: 1.3.5 - ripemd160: 2.0.2 - sha.js: 2.4.11 - dev: true - - /create-hmac@1.1.7: - resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==} - dependencies: - cipher-base: 1.0.4 - create-hash: 1.2.0 - inherits: 2.0.4 - ripemd160: 2.0.2 - safe-buffer: 5.2.1 - sha.js: 2.4.11 - dev: true - - /death@1.1.0: - resolution: {integrity: sha512-vsV6S4KVHvTGxbEcij7hkWRv0It+sGGWVOM67dQde/o5Xjnr+KmLjxWJii2uEObIrt1CcM9w0Yaovx+iOlIL+w==} - dev: true - - /debug@4.3.4(supports-color@8.1.1): - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.2 - supports-color: 8.1.1 - dev: true - - /decamelize@4.0.0: - resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} - engines: {node: '>=10'} - dev: true - - /decompress-response@6.0.0: - resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} - engines: {node: '>=10'} - dependencies: - mimic-response: 3.1.0 - dev: true - - /deep-extend@0.6.0: - resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} - engines: {node: '>=4.0.0'} - dev: true - - /deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - dev: true - - /defer-to-connect@2.0.1: - resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} - engines: {node: '>=10'} - dev: true - - /define-data-property@1.1.1: - resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==} - engines: {node: '>= 0.4'} - dependencies: - get-intrinsic: 1.2.2 - gopd: 1.0.1 - has-property-descriptors: 1.0.1 - dev: true - - /delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - dev: true - - /depd@2.0.0: - resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} - engines: {node: '>= 0.8'} - dev: true - - /detect-port@1.5.1: - resolution: {integrity: sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ==} - hasBin: true - dependencies: - address: 1.2.2 - debug: 4.3.4(supports-color@8.1.1) - transitivePeerDependencies: - - supports-color - dev: true - - /diff@5.0.0: - resolution: {integrity: sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==} - engines: {node: '>=0.3.1'} - dev: true - - /difflib@0.2.4: - resolution: {integrity: sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==} - dependencies: - heap: 0.2.7 - dev: true - - /dir-glob@3.0.1: - resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} - engines: {node: '>=8'} - dependencies: - path-type: 4.0.0 - dev: true - - /elliptic@6.5.4: - resolution: {integrity: sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==} - dependencies: - bn.js: 4.12.0 - brorand: 1.1.0 - hash.js: 1.1.7 - hmac-drbg: 1.0.1 - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - minimalistic-crypto-utils: 1.0.1 - dev: true - - /emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - dev: true - - /encode-utf8@1.0.3: - resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==} - dev: true - - /enquirer@2.4.1: - resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} - engines: {node: '>=8.6'} - dependencies: - ansi-colors: 4.1.3 - strip-ansi: 6.0.1 - dev: true - - /env-paths@2.2.1: - resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} - engines: {node: '>=6'} - dev: true - - /error-ex@1.3.2: - resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} - dependencies: - is-arrayish: 0.2.1 - dev: true - - /escalade@3.1.1: - resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} - engines: {node: '>=6'} - dev: true - - /escape-string-regexp@1.0.5: - resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} - engines: {node: '>=0.8.0'} - dev: true - - /escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - dev: true - - /escodegen@1.8.1: - resolution: {integrity: sha512-yhi5S+mNTOuRvyW4gWlg5W1byMaQGWWSYHXsuFZ7GBo7tpyOwi2EdzMP/QWxh9hwkD2m+wDVHJsxhRIj+v/b/A==} - engines: {node: '>=0.12.0'} - hasBin: true - dependencies: - esprima: 2.7.3 - estraverse: 1.9.3 - esutils: 2.0.3 - optionator: 0.8.3 - optionalDependencies: - source-map: 0.2.0 - dev: true - - /esprima@2.7.3: - resolution: {integrity: sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==} - engines: {node: '>=0.10.0'} - hasBin: true - dev: true - - /esprima@4.0.1: - resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} - engines: {node: '>=4'} - hasBin: true - dev: true - - /estraverse@1.9.3: - resolution: {integrity: sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA==} - engines: {node: '>=0.10.0'} - dev: true - - /esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - dev: true - - /ethereum-bloom-filters@1.0.10: - resolution: {integrity: sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA==} - dependencies: - js-sha3: 0.8.0 - dev: true - - /ethereum-cryptography@0.1.3: - resolution: {integrity: sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==} - dependencies: - '@types/pbkdf2': 3.1.2 - '@types/secp256k1': 4.0.6 - blakejs: 1.2.1 - browserify-aes: 1.2.0 - bs58check: 2.1.2 - create-hash: 1.2.0 - create-hmac: 1.1.7 - hash.js: 1.1.7 - keccak: 3.0.4 - pbkdf2: 3.1.2 - randombytes: 2.1.0 - safe-buffer: 5.2.1 - scrypt-js: 3.0.1 - secp256k1: 4.0.3 - setimmediate: 1.0.5 - dev: true - - /ethereum-cryptography@1.2.0: - resolution: {integrity: sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==} - dependencies: - '@noble/hashes': 1.2.0 - '@noble/secp256k1': 1.7.1 - '@scure/bip32': 1.1.5 - '@scure/bip39': 1.1.1 - dev: true - - /ethereum-cryptography@2.1.3: - resolution: {integrity: sha512-BlwbIL7/P45W8FGW2r7LGuvoEZ+7PWsniMvQ4p5s2xCyw9tmaDlpfsN9HjAucbF+t/qpVHwZUisgfK24TCW8aA==} - dependencies: - '@noble/curves': 1.3.0 - '@noble/hashes': 1.3.3 - '@scure/bip32': 1.3.3 - '@scure/bip39': 1.2.2 - dev: true - - /ethereumjs-abi@0.6.8: - resolution: {integrity: sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==} - dependencies: - bn.js: 4.12.0 - ethereumjs-util: 6.2.1 - dev: true - - /ethereumjs-util@6.2.1: - resolution: {integrity: sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==} - dependencies: - '@types/bn.js': 4.11.6 - bn.js: 4.12.0 - create-hash: 1.2.0 - elliptic: 6.5.4 - ethereum-cryptography: 0.1.3 - ethjs-util: 0.1.6 - rlp: 2.2.7 - dev: true - - /ethereumjs-util@7.1.5: - resolution: {integrity: sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==} - engines: {node: '>=10.0.0'} - dependencies: - '@types/bn.js': 5.1.5 - bn.js: 5.2.1 - create-hash: 1.2.0 - ethereum-cryptography: 0.1.3 - rlp: 2.2.7 - dev: true - - /ethereumjs-wallet@1.0.2: - resolution: {integrity: sha512-CCWV4RESJgRdHIvFciVQFnCHfqyhXWchTPlkfp28Qc53ufs+doi5I/cV2+xeK9+qEo25XCWfP9MiL+WEPAZfdA==} - dependencies: - aes-js: 3.1.2 - bs58check: 2.1.2 - ethereum-cryptography: 0.1.3 - ethereumjs-util: 7.1.5 - randombytes: 2.1.0 - scrypt-js: 3.0.1 - utf8: 3.0.0 - uuid: 8.3.2 - dev: true - - /ethers@5.4.0: - resolution: {integrity: sha512-hqN1x0CV8VMpQ25WnNEjaMqtB3nA4DRAb2FSmmNaUbD1dF6kWbHs8YaXbVvD37FCg3GTEyc4rV9Pxafk1ByHKw==} - dependencies: - '@ethersproject/abi': 5.4.0 - '@ethersproject/abstract-provider': 5.4.0 - '@ethersproject/abstract-signer': 5.4.0 - '@ethersproject/address': 5.4.0 - '@ethersproject/base64': 5.4.0 - '@ethersproject/basex': 5.4.0 - '@ethersproject/bignumber': 5.4.0 - '@ethersproject/bytes': 5.4.0 - '@ethersproject/constants': 5.4.0 - '@ethersproject/contracts': 5.4.0 - '@ethersproject/hash': 5.4.0 - '@ethersproject/hdnode': 5.4.0 - '@ethersproject/json-wallets': 5.4.0 - '@ethersproject/keccak256': 5.4.0 - '@ethersproject/logger': 5.4.0 - '@ethersproject/networks': 5.4.0 - '@ethersproject/pbkdf2': 5.4.0 - '@ethersproject/properties': 5.4.0 - '@ethersproject/providers': 5.4.0 - '@ethersproject/random': 5.4.0 - '@ethersproject/rlp': 5.4.0 - '@ethersproject/sha2': 5.4.0 - '@ethersproject/signing-key': 5.4.0 - '@ethersproject/solidity': 5.4.0 - '@ethersproject/strings': 5.4.0 - '@ethersproject/transactions': 5.4.0 - '@ethersproject/units': 5.4.0 - '@ethersproject/wallet': 5.4.0 - '@ethersproject/web': 5.4.0 - '@ethersproject/wordlists': 5.4.0 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - dev: true - - /ethers@5.7.2: - resolution: {integrity: sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==} - dependencies: - '@ethersproject/abi': 5.7.0 - '@ethersproject/abstract-provider': 5.7.0 - '@ethersproject/abstract-signer': 5.7.0 - '@ethersproject/address': 5.7.0 - '@ethersproject/base64': 5.7.0 - '@ethersproject/basex': 5.7.0 - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/constants': 5.7.0 - '@ethersproject/contracts': 5.7.0 - '@ethersproject/hash': 5.7.0 - '@ethersproject/hdnode': 5.7.0 - '@ethersproject/json-wallets': 5.7.0 - '@ethersproject/keccak256': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/networks': 5.7.1 - '@ethersproject/pbkdf2': 5.7.0 - '@ethersproject/properties': 5.7.0 - '@ethersproject/providers': 5.7.2 - '@ethersproject/random': 5.7.0 - '@ethersproject/rlp': 5.7.0 - '@ethersproject/sha2': 5.7.0 - '@ethersproject/signing-key': 5.7.0 - '@ethersproject/solidity': 5.7.0 - '@ethersproject/strings': 5.7.0 - '@ethersproject/transactions': 5.7.0 - '@ethersproject/units': 5.7.0 - '@ethersproject/wallet': 5.7.0 - '@ethersproject/web': 5.7.1 - '@ethersproject/wordlists': 5.7.0 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - dev: true - - /ethjs-unit@0.1.6: - resolution: {integrity: sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==} - engines: {node: '>=6.5.0', npm: '>=3'} - dependencies: - bn.js: 4.11.6 - number-to-bn: 1.7.0 - dev: true - - /ethjs-util@0.1.6: - resolution: {integrity: sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==} - engines: {node: '>=6.5.0', npm: '>=3'} - dependencies: - is-hex-prefixed: 1.0.0 - strip-hex-prefix: 1.0.0 - dev: true - - /evp_bytestokey@1.0.3: - resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} - dependencies: - md5.js: 1.3.5 - safe-buffer: 5.2.1 - dev: true - - /fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - dev: true - - /fast-diff@1.3.0: - resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} - dev: true - - /fast-glob@3.3.2: - resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} - engines: {node: '>=8.6.0'} - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.5 - dev: true - - /fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - dev: true - - /fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - dev: true - - /fastq@1.17.0: - resolution: {integrity: sha512-zGygtijUMT7jnk3h26kUms3BkSDp4IfIKjmnqI2tvx6nuBfiF1UqOxbnLfzdv+apBy+53oaImsKtMw/xYbW+1w==} - dependencies: - reusify: 1.0.4 - dev: true - - /fill-range@7.0.1: - resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} - engines: {node: '>=8'} - dependencies: - to-regex-range: 5.0.1 - dev: true - - /find-replace@1.0.3: - resolution: {integrity: sha512-KrUnjzDCD9426YnCP56zGYy/eieTnhtK6Vn++j+JJzmlsWWwEkDnsyVF575spT6HJ6Ow9tlbT3TQTDsa+O4UWA==} - engines: {node: '>=4.0.0'} - dependencies: - array-back: 1.0.4 - test-value: 2.1.0 - dev: true - - /find-up@2.1.0: - resolution: {integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==} - engines: {node: '>=4'} - dependencies: - locate-path: 2.0.0 - dev: true - - /find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - dev: true - - /flat@5.0.2: - resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} - hasBin: true - dev: true - - /fmix@0.1.0: - resolution: {integrity: sha512-Y6hyofImk9JdzU8k5INtTXX1cu8LDlePWDFU5sftm9H+zKCr5SGrVjdhkvsim646cw5zD0nADj8oHyXMZmCZ9w==} - dependencies: - imul: 1.0.1 - dev: true - - /follow-redirects@1.15.5(debug@4.3.4): - resolution: {integrity: sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==} - engines: {node: '>=4.0'} - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true - dependencies: - debug: 4.3.4(supports-color@8.1.1) - dev: true - - /form-data-encoder@2.1.4: - resolution: {integrity: sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==} - engines: {node: '>= 14.17'} - dev: true - - /form-data@4.0.0: - resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} - engines: {node: '>= 6'} - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - mime-types: 2.1.35 - dev: true - - /fp-ts@1.19.3: - resolution: {integrity: sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg==} - dev: true - - /fs-extra@0.30.0: - resolution: {integrity: sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==} - dependencies: - graceful-fs: 4.2.11 - jsonfile: 2.4.0 - klaw: 1.3.1 - path-is-absolute: 1.0.1 - rimraf: 2.7.1 - dev: true - - /fs-extra@10.1.0: - resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} - engines: {node: '>=12'} - dependencies: - graceful-fs: 4.2.11 - jsonfile: 6.1.0 - universalify: 2.0.1 - dev: true - - /fs-extra@7.0.1: - resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} - engines: {node: '>=6 <7 || >=8'} - dependencies: - graceful-fs: 4.2.11 - jsonfile: 4.0.0 - universalify: 0.1.2 - dev: true - - /fs-extra@8.1.0: - resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} - engines: {node: '>=6 <7 || >=8'} - dependencies: - graceful-fs: 4.2.11 - jsonfile: 4.0.0 - universalify: 0.1.2 - dev: true - - /fs-extra@9.1.0: - resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} - engines: {node: '>=10'} - dependencies: - at-least-node: 1.0.0 - graceful-fs: 4.2.11 - jsonfile: 6.1.0 - universalify: 2.0.1 - dev: true - - /fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - dev: true - - /fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - dev: true - - /functional-red-black-tree@1.0.1: - resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} - dev: true - - /get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - dev: true - - /get-intrinsic@1.2.2: - resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==} - dependencies: - function-bind: 1.1.2 - has-proto: 1.0.1 - has-symbols: 1.0.3 - hasown: 2.0.0 - dev: true - - /get-stream@6.0.1: - resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} - engines: {node: '>=10'} - dev: true - - /ghost-testrpc@0.0.2: - resolution: {integrity: sha512-i08dAEgJ2g8z5buJIrCTduwPIhih3DP+hOCTyyryikfV8T0bNvHnGXO67i0DD1H4GBDETTclPy9njZbfluQYrQ==} - hasBin: true - dependencies: - chalk: 2.4.2 - node-emoji: 1.11.0 - dev: true - - /glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} - dependencies: - is-glob: 4.0.3 - dev: true - - /glob@5.0.15: - resolution: {integrity: sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==} - dependencies: - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - dev: true - - /glob@7.2.0: - resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==} - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - dev: true - - /glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - dev: true - - /glob@8.1.0: - resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} - engines: {node: '>=12'} - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 5.1.6 - once: 1.4.0 - dev: true - - /global-modules@2.0.0: - resolution: {integrity: sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==} - engines: {node: '>=6'} - dependencies: - global-prefix: 3.0.0 - dev: true - - /global-prefix@3.0.0: - resolution: {integrity: sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==} - engines: {node: '>=6'} - dependencies: - ini: 1.3.8 - kind-of: 6.0.3 - which: 1.3.1 - dev: true - - /globby@10.0.2: - resolution: {integrity: sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==} - engines: {node: '>=8'} - dependencies: - '@types/glob': 7.2.0 - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.3.2 - glob: 7.2.3 - ignore: 5.3.1 - merge2: 1.4.1 - slash: 3.0.0 - dev: true - - /gopd@1.0.1: - resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} - dependencies: - get-intrinsic: 1.2.2 - dev: true - - /got@12.6.1: - resolution: {integrity: sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==} - engines: {node: '>=14.16'} - dependencies: - '@sindresorhus/is': 5.6.0 - '@szmarczak/http-timer': 5.0.1 - cacheable-lookup: 7.0.0 - cacheable-request: 10.2.14 - decompress-response: 6.0.0 - form-data-encoder: 2.1.4 - get-stream: 6.0.1 - http2-wrapper: 2.2.1 - lowercase-keys: 3.0.0 - p-cancelable: 3.0.0 - responselike: 3.0.0 - dev: true - - /graceful-fs@4.2.10: - resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} - dev: true - - /graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - dev: true - - /handlebars@4.7.8: - resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==} - engines: {node: '>=0.4.7'} - hasBin: true - dependencies: - minimist: 1.2.8 - neo-async: 2.6.2 - source-map: 0.6.1 - wordwrap: 1.0.0 - optionalDependencies: - uglify-js: 3.17.4 - dev: true - - /hardhat-deploy-ethers@0.3.0-beta.13(ethers@5.4.0)(hardhat@2.19.5): - resolution: {integrity: sha512-PdWVcKB9coqWV1L7JTpfXRCI91Cgwsm7KLmBcwZ8f0COSm1xtABHZTyz3fvF6p42cTnz1VM0QnfDvMFlIRkSNw==} - peerDependencies: - ethers: ^5.0.0 - hardhat: ^2.0.0 - dependencies: - ethers: 5.4.0 - hardhat: 2.19.5(typescript@5.3.3) - dev: true - - /hardhat-deploy@0.11.45: - resolution: {integrity: sha512-aC8UNaq3JcORnEUIwV945iJuvBwi65tjHVDU3v6mOcqik7WAzHVCJ7cwmkkipsHrWysrB5YvGF1q9S1vIph83w==} - dependencies: - '@ethersproject/abi': 5.7.0 - '@ethersproject/abstract-signer': 5.7.0 - '@ethersproject/address': 5.7.0 - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/constants': 5.7.0 - '@ethersproject/contracts': 5.7.0 - '@ethersproject/providers': 5.7.2 - '@ethersproject/solidity': 5.7.0 - '@ethersproject/transactions': 5.7.0 - '@ethersproject/wallet': 5.7.0 - '@types/qs': 6.9.11 - axios: 0.21.4(debug@4.3.4) - chalk: 4.1.2 - chokidar: 3.5.3 - debug: 4.3.4(supports-color@8.1.1) - enquirer: 2.4.1 - ethers: 5.7.2 - form-data: 4.0.0 - fs-extra: 10.1.0 - match-all: 1.2.6 - murmur-128: 0.2.1 - qs: 6.11.2 - zksync-web3: 0.14.4(ethers@5.7.2) - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - dev: true - - /hardhat@2.19.5(typescript@5.3.3): - resolution: {integrity: sha512-vx8R7zWCYVgM56vA6o0Wqx2bIIptkN4TMs9QwDqZVNGRhMzBfzqUeEYbp+69gxWp1neg2V2nYQUaaUv7aom1kw==} - hasBin: true - peerDependencies: - ts-node: '*' - typescript: '*' - peerDependenciesMeta: - ts-node: - optional: true - typescript: - optional: true - dependencies: - '@ethersproject/abi': 5.7.0 - '@metamask/eth-sig-util': 4.0.1 - '@nomicfoundation/ethereumjs-block': 5.0.2 - '@nomicfoundation/ethereumjs-blockchain': 7.0.2 - '@nomicfoundation/ethereumjs-common': 4.0.2 - '@nomicfoundation/ethereumjs-evm': 2.0.2 - '@nomicfoundation/ethereumjs-rlp': 5.0.2 - '@nomicfoundation/ethereumjs-statemanager': 2.0.2 - '@nomicfoundation/ethereumjs-trie': 6.0.2 - '@nomicfoundation/ethereumjs-tx': 5.0.2 - '@nomicfoundation/ethereumjs-util': 9.0.2 - '@nomicfoundation/ethereumjs-vm': 7.0.2 - '@nomicfoundation/solidity-analyzer': 0.1.1 - '@sentry/node': 5.30.0 - '@types/bn.js': 5.1.5 - '@types/lru-cache': 5.1.1 - adm-zip: 0.4.16 - aggregate-error: 3.1.0 - ansi-escapes: 4.3.2 - boxen: 5.1.2 - chalk: 2.4.2 - chokidar: 3.5.3 - ci-info: 2.0.0 - debug: 4.3.4(supports-color@8.1.1) - enquirer: 2.4.1 - env-paths: 2.2.1 - ethereum-cryptography: 1.2.0 - ethereumjs-abi: 0.6.8 - find-up: 2.1.0 - fp-ts: 1.19.3 - fs-extra: 7.0.1 - glob: 7.2.0 - immutable: 4.3.5 - io-ts: 1.10.4 - keccak: 3.0.4 - lodash: 4.17.21 - mnemonist: 0.38.5 - mocha: 10.2.0 - p-map: 4.0.0 - raw-body: 2.5.2 - resolve: 1.17.0 - semver: 6.3.1 - solc: 0.7.3(debug@4.3.4) - source-map-support: 0.5.21 - stacktrace-parser: 0.1.10 - tsort: 0.0.1 - typescript: 5.3.3 - undici: 5.28.2 - uuid: 8.3.2 - ws: 7.5.9 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - dev: true - - /has-flag@1.0.0: - resolution: {integrity: sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==} - engines: {node: '>=0.10.0'} - dev: true - - /has-flag@3.0.0: - resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} - engines: {node: '>=4'} - dev: true - - /has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - dev: true - - /has-property-descriptors@1.0.1: - resolution: {integrity: sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==} - dependencies: - get-intrinsic: 1.2.2 - dev: true - - /has-proto@1.0.1: - resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} - engines: {node: '>= 0.4'} - dev: true - - /has-symbols@1.0.3: - resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} - engines: {node: '>= 0.4'} - dev: true - - /hash-base@3.1.0: - resolution: {integrity: sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==} - engines: {node: '>=4'} - dependencies: - inherits: 2.0.4 - readable-stream: 3.6.2 - safe-buffer: 5.2.1 - dev: true - - /hash.js@1.1.7: - resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} - dependencies: - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - dev: true - - /hasown@2.0.0: - resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==} - engines: {node: '>= 0.4'} - dependencies: - function-bind: 1.1.2 - dev: true - - /he@1.2.0: - resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} - hasBin: true - dev: true - - /heap@0.2.7: - resolution: {integrity: sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==} - dev: true - - /hmac-drbg@1.0.1: - resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} - dependencies: - hash.js: 1.1.7 - minimalistic-assert: 1.0.1 - minimalistic-crypto-utils: 1.0.1 - dev: true - - /http-cache-semantics@4.1.1: - resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} - dev: true - - /http-errors@2.0.0: - resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} - engines: {node: '>= 0.8'} - dependencies: - depd: 2.0.0 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 2.0.1 - toidentifier: 1.0.1 - dev: true - - /http2-wrapper@2.2.1: - resolution: {integrity: sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==} - engines: {node: '>=10.19.0'} - dependencies: - quick-lru: 5.1.1 - resolve-alpn: 1.2.1 - dev: true - - /https-proxy-agent@5.0.1: - resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} - engines: {node: '>= 6'} - dependencies: - agent-base: 6.0.2 - debug: 4.3.4(supports-color@8.1.1) - transitivePeerDependencies: - - supports-color - dev: true - - /iconv-lite@0.4.24: - resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} - engines: {node: '>=0.10.0'} - dependencies: - safer-buffer: 2.1.2 - dev: true - - /ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - dev: true - - /ignore@5.3.1: - resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} - engines: {node: '>= 4'} - dev: true - - /immutable@4.3.5: - resolution: {integrity: sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==} - dev: true - - /import-fresh@3.3.0: - resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} - engines: {node: '>=6'} - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - dev: true - - /imul@1.0.1: - resolution: {integrity: sha512-WFAgfwPLAjU66EKt6vRdTlKj4nAgIDQzh29JonLa4Bqtl6D8JrIMvWjCnx7xEjVNmP3U0fM5o8ZObk7d0f62bA==} - engines: {node: '>=0.10.0'} - dev: true - - /indent-string@4.0.0: - resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} - engines: {node: '>=8'} - dev: true - - /inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - dev: true - - /inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - dev: true - - /ini@1.3.8: - resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - dev: true - - /interpret@1.4.0: - resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} - engines: {node: '>= 0.10'} - dev: true - - /io-ts@1.10.4: - resolution: {integrity: sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g==} - dependencies: - fp-ts: 1.19.3 - dev: true - - /is-arrayish@0.2.1: - resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - dev: true - - /is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} - dependencies: - binary-extensions: 2.2.0 - dev: true - - /is-buffer@2.0.5: - resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==} - engines: {node: '>=4'} - dev: true - - /is-core-module@2.13.1: - resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} - dependencies: - hasown: 2.0.0 - dev: true - - /is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - dev: true - - /is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - dev: true - - /is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - dependencies: - is-extglob: 2.1.1 - dev: true - - /is-hex-prefixed@1.0.0: - resolution: {integrity: sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==} - engines: {node: '>=6.5.0', npm: '>=3'} - dev: true - - /is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - dev: true - - /is-plain-obj@2.1.0: - resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} - engines: {node: '>=8'} - dev: true - - /is-unicode-supported@0.1.0: - resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} - engines: {node: '>=10'} - dev: true - - /isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - dev: true - - /js-sdsl@4.4.2: - resolution: {integrity: sha512-dwXFwByc/ajSV6m5bcKAPwe4yDDF6D614pxmIi5odytzxRlwqF6nwoiCek80Ixc7Cvma5awClxrzFtxCQvcM8w==} - dev: true - - /js-sha3@0.5.7: - resolution: {integrity: sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==} - dev: true - - /js-sha3@0.8.0: - resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==} - dev: true - - /js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - dev: true - - /js-yaml@3.14.1: - resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} - hasBin: true - dependencies: - argparse: 1.0.10 - esprima: 4.0.1 - dev: true - - /js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} - hasBin: true - dependencies: - argparse: 2.0.1 - dev: true - - /json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - dev: true - - /json-parse-even-better-errors@2.3.1: - resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - dev: true - - /json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - dev: true - - /json-schema-traverse@1.0.0: - resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - dev: true - - /jsonfile@2.4.0: - resolution: {integrity: sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==} - optionalDependencies: - graceful-fs: 4.2.11 - dev: true - - /jsonfile@4.0.0: - resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} - optionalDependencies: - graceful-fs: 4.2.11 - dev: true - - /jsonfile@6.1.0: - resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} - dependencies: - universalify: 2.0.1 - optionalDependencies: - graceful-fs: 4.2.11 - dev: true - - /jsonschema@1.4.1: - resolution: {integrity: sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==} - dev: true - - /keccak@3.0.4: - resolution: {integrity: sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==} - engines: {node: '>=10.0.0'} - requiresBuild: true - dependencies: - node-addon-api: 2.0.2 - node-gyp-build: 4.8.0 - readable-stream: 3.6.2 - dev: true - - /keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - dependencies: - json-buffer: 3.0.1 - dev: true - - /kind-of@6.0.3: - resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} - engines: {node: '>=0.10.0'} - dev: true - - /klaw@1.3.1: - resolution: {integrity: sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==} - optionalDependencies: - graceful-fs: 4.2.11 - dev: true - - /latest-version@7.0.0: - resolution: {integrity: sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==} - engines: {node: '>=14.16'} - dependencies: - package-json: 8.1.1 - dev: true - - /level-supports@4.0.1: - resolution: {integrity: sha512-PbXpve8rKeNcZ9C1mUicC9auIYFyGpkV9/i6g76tLgANwWhtG2v7I4xNBUlkn3lE2/dZF3Pi0ygYGtLc4RXXdA==} - engines: {node: '>=12'} - dev: true - - /level-transcoder@1.0.1: - resolution: {integrity: sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w==} - engines: {node: '>=12'} - dependencies: - buffer: 6.0.3 - module-error: 1.0.2 - dev: true - - /level@8.0.1: - resolution: {integrity: sha512-oPBGkheysuw7DmzFQYyFe8NAia5jFLAgEnkgWnK3OXAuJr8qFT+xBQIwokAZPME2bhPFzS8hlYcL16m8UZrtwQ==} - engines: {node: '>=12'} - dependencies: - abstract-level: 1.0.4 - browser-level: 1.0.1 - classic-level: 1.4.1 - dev: true - - /levn@0.3.0: - resolution: {integrity: sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==} - engines: {node: '>= 0.8.0'} - dependencies: - prelude-ls: 1.1.2 - type-check: 0.3.2 - dev: true - - /lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - dev: true - - /locate-path@2.0.0: - resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==} - engines: {node: '>=4'} - dependencies: - p-locate: 2.0.0 - path-exists: 3.0.0 - dev: true - - /locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} - dependencies: - p-locate: 5.0.0 - dev: true - - /lodash.truncate@4.4.2: - resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} - dev: true - - /lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - dev: true - - /log-symbols@4.1.0: - resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} - engines: {node: '>=10'} - dependencies: - chalk: 4.1.2 - is-unicode-supported: 0.1.0 - dev: true - - /lowercase-keys@3.0.0: - resolution: {integrity: sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dev: true - - /lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - dependencies: - yallist: 3.1.1 - dev: true - - /lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} - dependencies: - yallist: 4.0.0 - dev: true - - /lru_map@0.3.3: - resolution: {integrity: sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==} - dev: true - - /match-all@1.2.6: - resolution: {integrity: sha512-0EESkXiTkWzrQQntBu2uzKvLu6vVkUGz40nGPbSZuegcfE5UuSzNjLaIu76zJWuaT/2I3Z/8M06OlUOZLGwLlQ==} - dev: true - - /mcl-wasm@0.7.9: - resolution: {integrity: sha512-iJIUcQWA88IJB/5L15GnJVnSQJmf/YaxxV6zRavv83HILHaJQb6y0iFyDMdDO0gN8X37tdxmAOrH/P8B6RB8sQ==} - engines: {node: '>=8.9.0'} - dev: true - - /mcl-wasm@1.4.0: - resolution: {integrity: sha512-90Tvmg2NXwnKMgTafA01PRELsYNNRb/F2bj3nzdByTLLMUmgkgL8H/oeWcjZtVVffnBJyNjDcYxY7cdOE/WoHg==} - engines: {node: '>=14.17'} - dependencies: - '@types/node': 20.11.16 - dev: true - - /md5.js@1.3.5: - resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} - dependencies: - hash-base: 3.1.0 - inherits: 2.0.4 - safe-buffer: 5.2.1 - dev: true - - /memory-level@1.0.0: - resolution: {integrity: sha512-UXzwewuWeHBz5krr7EvehKcmLFNoXxGcvuYhC41tRnkrTbJohtS7kVn9akmgirtRygg+f7Yjsfi8Uu5SGSQ4Og==} - engines: {node: '>=12'} - dependencies: - abstract-level: 1.0.4 - functional-red-black-tree: 1.0.1 - module-error: 1.0.2 - dev: true - - /memorystream@0.3.1: - resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==} - engines: {node: '>= 0.10.0'} - dev: true - - /merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - dev: true - - /micro-ftch@0.3.1: - resolution: {integrity: sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==} - dev: true - - /micromatch@4.0.5: - resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} - engines: {node: '>=8.6'} - dependencies: - braces: 3.0.2 - picomatch: 2.3.1 - dev: true - - /mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - dev: true - - /mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} - dependencies: - mime-db: 1.52.0 - dev: true - - /mimic-response@3.1.0: - resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} - engines: {node: '>=10'} - dev: true - - /mimic-response@4.0.0: - resolution: {integrity: sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dev: true - - /minimalistic-assert@1.0.1: - resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} - dev: true - - /minimalistic-crypto-utils@1.0.1: - resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} - dev: true - - /minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - dependencies: - brace-expansion: 1.1.11 - dev: true - - /minimatch@5.0.1: - resolution: {integrity: sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==} - engines: {node: '>=10'} - dependencies: - brace-expansion: 2.0.1 - dev: true - - /minimatch@5.1.6: - resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} - engines: {node: '>=10'} - dependencies: - brace-expansion: 2.0.1 - dev: true - - /minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - dev: true - - /mkdirp@0.5.6: - resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} - hasBin: true - dependencies: - minimist: 1.2.8 - dev: true - - /mkdirp@1.0.4: - resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} - engines: {node: '>=10'} - hasBin: true - dev: true - - /mnemonist@0.38.5: - resolution: {integrity: sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg==} - dependencies: - obliterator: 2.0.4 - dev: true - - /mocha@10.2.0: - resolution: {integrity: sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==} - engines: {node: '>= 14.0.0'} - hasBin: true - dependencies: - ansi-colors: 4.1.1 - browser-stdout: 1.3.1 - chokidar: 3.5.3 - debug: 4.3.4(supports-color@8.1.1) - diff: 5.0.0 - escape-string-regexp: 4.0.0 - find-up: 5.0.0 - glob: 7.2.0 - he: 1.2.0 - js-yaml: 4.1.0 - log-symbols: 4.1.0 - minimatch: 5.0.1 - ms: 2.1.3 - nanoid: 3.3.3 - serialize-javascript: 6.0.0 - strip-json-comments: 3.1.1 - supports-color: 8.1.1 - workerpool: 6.2.1 - yargs: 16.2.0 - yargs-parser: 20.2.4 - yargs-unparser: 2.0.0 - dev: true - - /module-error@1.0.2: - resolution: {integrity: sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA==} - engines: {node: '>=10'} - dev: true - - /ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - dev: true - - /ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - dev: true - - /murmur-128@0.2.1: - resolution: {integrity: sha512-WseEgiRkI6aMFBbj8Cg9yBj/y+OdipwVC7zUo3W2W1JAJITwouUOtpqsmGSg67EQmwwSyod7hsVsWY5LsrfQVg==} - dependencies: - encode-utf8: 1.0.3 - fmix: 0.1.0 - imul: 1.0.1 - dev: true - - /nanoid@3.3.3: - resolution: {integrity: sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - dev: true - - /napi-macros@2.2.2: - resolution: {integrity: sha512-hmEVtAGYzVQpCKdbQea4skABsdXW4RUh5t5mJ2zzqowJS2OyXZTU1KhDVFhx+NlWZ4ap9mqR9TcDO3LTTttd+g==} - dev: true - - /neo-async@2.6.2: - resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - dev: true - - /node-addon-api@2.0.2: - resolution: {integrity: sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==} - dev: true - - /node-emoji@1.11.0: - resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==} - dependencies: - lodash: 4.17.21 - dev: true - - /node-fetch@2.7.0: - resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} - engines: {node: 4.x || >=6.0.0} - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - dependencies: - whatwg-url: 5.0.0 - dev: true - - /node-gyp-build@4.8.0: - resolution: {integrity: sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==} - hasBin: true - dev: true - - /nofilter@1.0.4: - resolution: {integrity: sha512-N8lidFp+fCz+TD51+haYdbDGrcBWwuHX40F5+z0qkUjMJ5Tp+rdSuAkMJ9N9eoolDlEVTf6u5icM+cNKkKW2mA==} - engines: {node: '>=8'} - dev: true - - /nopt@3.0.6: - resolution: {integrity: sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==} - hasBin: true - dependencies: - abbrev: 1.0.9 - dev: true - - /normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - dev: true - - /normalize-url@8.0.0: - resolution: {integrity: sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==} - engines: {node: '>=14.16'} - dev: true - - /number-to-bn@1.7.0: - resolution: {integrity: sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig==} - engines: {node: '>=6.5.0', npm: '>=3'} - dependencies: - bn.js: 4.11.6 - strip-hex-prefix: 1.0.0 - dev: true - - /object-inspect@1.13.1: - resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} - dev: true - - /obliterator@2.0.4: - resolution: {integrity: sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==} - dev: true - - /once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - dependencies: - wrappy: 1.0.2 - dev: true - - /optionator@0.8.3: - resolution: {integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==} - engines: {node: '>= 0.8.0'} - dependencies: - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.3.0 - prelude-ls: 1.1.2 - type-check: 0.3.2 - word-wrap: 1.2.5 - dev: true - - /os-tmpdir@1.0.2: - resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} - engines: {node: '>=0.10.0'} - dev: true - - /p-cancelable@3.0.0: - resolution: {integrity: sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==} - engines: {node: '>=12.20'} - dev: true - - /p-limit@1.3.0: - resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==} - engines: {node: '>=4'} - dependencies: - p-try: 1.0.0 - dev: true - - /p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} - dependencies: - yocto-queue: 0.1.0 - dev: true - - /p-locate@2.0.0: - resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==} - engines: {node: '>=4'} - dependencies: - p-limit: 1.3.0 - dev: true - - /p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} - dependencies: - p-limit: 3.1.0 - dev: true - - /p-map@4.0.0: - resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} - engines: {node: '>=10'} - dependencies: - aggregate-error: 3.1.0 - dev: true - - /p-try@1.0.0: - resolution: {integrity: sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==} - engines: {node: '>=4'} - dev: true - - /package-json@8.1.1: - resolution: {integrity: sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==} - engines: {node: '>=14.16'} - dependencies: - got: 12.6.1 - registry-auth-token: 5.0.2 - registry-url: 6.0.1 - semver: 7.5.4 - dev: true - - /parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} - dependencies: - callsites: 3.1.0 - dev: true - - /parse-json@5.2.0: - resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} - engines: {node: '>=8'} - dependencies: - '@babel/code-frame': 7.23.5 - error-ex: 1.3.2 - json-parse-even-better-errors: 2.3.1 - lines-and-columns: 1.2.4 - dev: true - - /path-exists@3.0.0: - resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} - engines: {node: '>=4'} - dev: true - - /path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - dev: true - - /path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - dev: true - - /path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - dev: true - - /path-type@4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} - dev: true - - /pbkdf2@3.1.2: - resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} - engines: {node: '>=0.12'} - dependencies: - create-hash: 1.2.0 - create-hmac: 1.1.7 - ripemd160: 2.0.2 - safe-buffer: 5.2.1 - sha.js: 2.4.11 - dev: true - - /picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - dev: true - - /pify@4.0.1: - resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} - engines: {node: '>=6'} - dev: true - - /pluralize@8.0.0: - resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} - engines: {node: '>=4'} - dev: true - - /prelude-ls@1.1.2: - resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==} - engines: {node: '>= 0.8.0'} - dev: true - - /prettier@2.8.8: - resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} - engines: {node: '>=10.13.0'} - hasBin: true - dev: true - - /proto-list@1.2.4: - resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} - dev: true - - /punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - dev: true - - /qs@6.11.2: - resolution: {integrity: sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==} - engines: {node: '>=0.6'} - dependencies: - side-channel: 1.0.4 - dev: true - - /queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - dev: true - - /quick-lru@5.1.1: - resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} - engines: {node: '>=10'} - dev: true - - /randombytes@2.1.0: - resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - dependencies: - safe-buffer: 5.2.1 - dev: true - - /raw-body@2.5.2: - resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} - engines: {node: '>= 0.8'} - dependencies: - bytes: 3.1.2 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - unpipe: 1.0.0 - dev: true - - /rc@1.2.8: - resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} - hasBin: true - dependencies: - deep-extend: 0.6.0 - ini: 1.3.8 - minimist: 1.2.8 - strip-json-comments: 2.0.1 - dev: true - - /readable-stream@3.6.2: - resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} - engines: {node: '>= 6'} - dependencies: - inherits: 2.0.4 - string_decoder: 1.3.0 - util-deprecate: 1.0.2 - dev: true - - /readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} - dependencies: - picomatch: 2.3.1 - dev: true - - /rechoir@0.6.2: - resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} - engines: {node: '>= 0.10'} - dependencies: - resolve: 1.22.8 - dev: true - - /recursive-readdir@2.2.3: - resolution: {integrity: sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==} - engines: {node: '>=6.0.0'} - dependencies: - minimatch: 3.1.2 - dev: true - - /registry-auth-token@5.0.2: - resolution: {integrity: sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==} - engines: {node: '>=14'} - dependencies: - '@pnpm/npm-conf': 2.2.2 - dev: true - - /registry-url@6.0.1: - resolution: {integrity: sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==} - engines: {node: '>=12'} - dependencies: - rc: 1.2.8 - dev: true - - /require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - dev: true - - /require-from-string@2.0.2: - resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} - engines: {node: '>=0.10.0'} - dev: true - - /resolve-alpn@1.2.1: - resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} - dev: true - - /resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - dev: true - - /resolve@1.1.7: - resolution: {integrity: sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==} - dev: true - - /resolve@1.17.0: - resolution: {integrity: sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==} - dependencies: - path-parse: 1.0.7 - dev: true - - /resolve@1.22.8: - resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} - hasBin: true - dependencies: - is-core-module: 2.13.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - dev: true - - /responselike@3.0.0: - resolution: {integrity: sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==} - engines: {node: '>=14.16'} - dependencies: - lowercase-keys: 3.0.0 - dev: true - - /reusify@1.0.4: - resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - dev: true - - /rimraf@2.7.1: - resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} - hasBin: true - dependencies: - glob: 7.2.0 - dev: true - - /ripemd160@2.0.2: - resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==} - dependencies: - hash-base: 3.1.0 - inherits: 2.0.4 - dev: true - - /rlp@2.2.7: - resolution: {integrity: sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==} - hasBin: true - dependencies: - bn.js: 5.2.1 - dev: true - - /run-parallel-limit@1.1.0: - resolution: {integrity: sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw==} - dependencies: - queue-microtask: 1.2.3 - dev: true - - /run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - dependencies: - queue-microtask: 1.2.3 - dev: true - - /rustbn.js@0.2.0: - resolution: {integrity: sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA==} - dev: true - - /safe-buffer@5.1.2: - resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} - dev: true - - /safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - dev: true - - /safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - dev: true - - /sc-istanbul@0.4.6: - resolution: {integrity: sha512-qJFF/8tW/zJsbyfh/iT/ZM5QNHE3CXxtLJbZsL+CzdJLBsPD7SedJZoUA4d8iAcN2IoMp/Dx80shOOd2x96X/g==} - hasBin: true - dependencies: - abbrev: 1.0.9 - async: 1.5.2 - escodegen: 1.8.1 - esprima: 2.7.3 - glob: 5.0.15 - handlebars: 4.7.8 - js-yaml: 3.14.1 - mkdirp: 0.5.6 - nopt: 3.0.6 - once: 1.4.0 - resolve: 1.1.7 - supports-color: 3.2.3 - which: 1.3.1 - wordwrap: 1.0.0 - dev: true - - /scrypt-js@3.0.1: - resolution: {integrity: sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==} - dev: true - - /secp256k1@4.0.3: - resolution: {integrity: sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==} - engines: {node: '>=10.0.0'} - requiresBuild: true - dependencies: - elliptic: 6.5.4 - node-addon-api: 2.0.2 - node-gyp-build: 4.8.0 - dev: true - - /semver@5.7.2: - resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} - hasBin: true - dev: true - - /semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - dev: true - - /semver@7.5.4: - resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} - engines: {node: '>=10'} - hasBin: true - dependencies: - lru-cache: 6.0.0 - dev: true - - /serialize-javascript@6.0.0: - resolution: {integrity: sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==} - dependencies: - randombytes: 2.1.0 - dev: true - - /set-function-length@1.2.0: - resolution: {integrity: sha512-4DBHDoyHlM1IRPGYcoxexgh67y4ueR53FKV1yyxwFMY7aCqcN/38M1+SwZ/qJQ8iLv7+ck385ot4CcisOAPT9w==} - engines: {node: '>= 0.4'} - dependencies: - define-data-property: 1.1.1 - function-bind: 1.1.2 - get-intrinsic: 1.2.2 - gopd: 1.0.1 - has-property-descriptors: 1.0.1 - dev: true - - /setimmediate@1.0.5: - resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} - dev: true - - /setprototypeof@1.2.0: - resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - dev: true - - /sha.js@2.4.11: - resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==} - hasBin: true - dependencies: - inherits: 2.0.4 - safe-buffer: 5.2.1 - dev: true - - /shelljs@0.8.5: - resolution: {integrity: sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==} - engines: {node: '>=4'} - hasBin: true - dependencies: - glob: 7.2.3 - interpret: 1.4.0 - rechoir: 0.6.2 - dev: true - - /side-channel@1.0.4: - resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} - dependencies: - call-bind: 1.0.5 - get-intrinsic: 1.2.2 - object-inspect: 1.13.1 - dev: true - - /slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} - dev: true - - /slice-ansi@4.0.0: - resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} - engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - astral-regex: 2.0.0 - is-fullwidth-code-point: 3.0.0 - dev: true - - /solc@0.7.3(debug@4.3.4): - resolution: {integrity: sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA==} - engines: {node: '>=8.0.0'} - hasBin: true - dependencies: - command-exists: 1.2.9 - commander: 3.0.2 - follow-redirects: 1.15.5(debug@4.3.4) - fs-extra: 0.30.0 - js-sha3: 0.8.0 - memorystream: 0.3.1 - require-from-string: 2.0.2 - semver: 5.7.2 - tmp: 0.0.33 - transitivePeerDependencies: - - debug - dev: true - - /solhint@4.1.1(typescript@5.3.3): - resolution: {integrity: sha512-7G4iF8H5hKHc0tR+/uyZesSKtfppFIMvPSW+Ku6MSL25oVRuyFeqNhOsXHfkex64wYJyXs4fe+pvhB069I19Tw==} - hasBin: true - dependencies: - '@solidity-parser/parser': 0.16.2 - ajv: 6.12.6 - antlr4: 4.13.1 - ast-parents: 0.0.1 - chalk: 4.1.2 - commander: 10.0.1 - cosmiconfig: 8.3.6(typescript@5.3.3) - fast-diff: 1.3.0 - glob: 8.1.0 - ignore: 5.3.1 - js-yaml: 4.1.0 - latest-version: 7.0.0 - lodash: 4.17.21 - pluralize: 8.0.0 - semver: 7.5.4 - strip-ansi: 6.0.1 - table: 6.8.1 - text-table: 0.2.0 - optionalDependencies: - prettier: 2.8.8 - transitivePeerDependencies: - - typescript - dev: true - - /solidity-coverage@0.8.6(hardhat@2.19.5): - resolution: {integrity: sha512-vV03mA/0nNMskOdVwNarUcqk0N/aYdelxAbf6RZ5l84FcYHbqDTr2JXyeYMp4bT48qHtAQjnKrygW1FrECyWNw==} - hasBin: true - peerDependencies: - hardhat: ^2.11.0 - dependencies: - '@ethersproject/abi': 5.7.0 - '@solidity-parser/parser': 0.18.0 - chalk: 2.4.2 - death: 1.1.0 - detect-port: 1.5.1 - difflib: 0.2.4 - fs-extra: 8.1.0 - ghost-testrpc: 0.0.2 - global-modules: 2.0.0 - globby: 10.0.2 - hardhat: 2.19.5(typescript@5.3.3) - jsonschema: 1.4.1 - lodash: 4.17.21 - mocha: 10.2.0 - node-emoji: 1.11.0 - pify: 4.0.1 - recursive-readdir: 2.2.3 - sc-istanbul: 0.4.6 - semver: 7.5.4 - shelljs: 0.8.5 - web3-utils: 1.10.3 - transitivePeerDependencies: - - supports-color - dev: true - - /source-map-support@0.5.21: - resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} - dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 - dev: true - - /source-map@0.2.0: - resolution: {integrity: sha512-CBdZ2oa/BHhS4xj5DlhjWNHcan57/5YuvfdLf17iVmIpd9KRm+DFLmC6nBNj+6Ua7Kt3TmOjDpQT1aTYOQtoUA==} - engines: {node: '>=0.8.0'} - requiresBuild: true - dependencies: - amdefine: 1.0.1 - dev: true - optional: true - - /source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} - dev: true - - /sprintf-js@1.0.3: - resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - dev: true - - /stacktrace-parser@0.1.10: - resolution: {integrity: sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==} - engines: {node: '>=6'} - dependencies: - type-fest: 0.7.1 - dev: true - - /statuses@2.0.1: - resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} - engines: {node: '>= 0.8'} - dev: true - - /string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - dev: true - - /string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - dependencies: - safe-buffer: 5.2.1 - dev: true - - /strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - dependencies: - ansi-regex: 5.0.1 - dev: true - - /strip-hex-prefix@1.0.0: - resolution: {integrity: sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==} - engines: {node: '>=6.5.0', npm: '>=3'} - dependencies: - is-hex-prefixed: 1.0.0 - dev: true - - /strip-json-comments@2.0.1: - resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} - engines: {node: '>=0.10.0'} - dev: true - - /strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - dev: true - - /supports-color@3.2.3: - resolution: {integrity: sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==} - engines: {node: '>=0.8.0'} - dependencies: - has-flag: 1.0.0 - dev: true - - /supports-color@5.5.0: - resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} - engines: {node: '>=4'} - dependencies: - has-flag: 3.0.0 - dev: true - - /supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - dependencies: - has-flag: 4.0.0 - dev: true - - /supports-color@8.1.1: - resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} - engines: {node: '>=10'} - dependencies: - has-flag: 4.0.0 - dev: true - - /supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - dev: true - - /table@6.8.1: - resolution: {integrity: sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==} - engines: {node: '>=10.0.0'} - dependencies: - ajv: 8.12.0 - lodash.truncate: 4.4.2 - slice-ansi: 4.0.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - dev: true - - /test-value@2.1.0: - resolution: {integrity: sha512-+1epbAxtKeXttkGFMTX9H42oqzOTufR1ceCF+GYA5aOmvaPq9wd4PUS8329fn2RRLGNeUkgRLnVpycjx8DsO2w==} - engines: {node: '>=0.10.0'} - dependencies: - array-back: 1.0.4 - typical: 2.6.1 - dev: true - - /text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - dev: true - - /tmp@0.0.33: - resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} - engines: {node: '>=0.6.0'} - dependencies: - os-tmpdir: 1.0.2 - dev: true - - /to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - dependencies: - is-number: 7.0.0 - dev: true - - /toidentifier@1.0.1: - resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} - engines: {node: '>=0.6'} - dev: true - - /tr46@0.0.3: - resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - dev: true - - /ts-essentials@7.0.3(typescript@5.3.3): - resolution: {integrity: sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==} - peerDependencies: - typescript: '>=3.7.0' - dependencies: - typescript: 5.3.3 - dev: true - - /tslib@1.14.1: - resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - dev: true - - /tsort@0.0.1: - resolution: {integrity: sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==} - dev: true - - /tweetnacl-util@0.15.1: - resolution: {integrity: sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==} - dev: true - - /tweetnacl@1.0.3: - resolution: {integrity: sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==} - dev: true - - /type-check@0.3.2: - resolution: {integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==} - engines: {node: '>= 0.8.0'} - dependencies: - prelude-ls: 1.1.2 - dev: true - - /type-fest@0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} - dev: true - - /type-fest@0.21.3: - resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} - engines: {node: '>=10'} - dev: true - - /type-fest@0.7.1: - resolution: {integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==} - engines: {node: '>=8'} - dev: true - - /typechain@5.2.0(typescript@5.3.3): - resolution: {integrity: sha512-0INirvQ+P+MwJOeMct+WLkUE4zov06QxC96D+i3uGFEHoiSkZN70MKDQsaj8zkL86wQwByJReI2e7fOUwECFuw==} - hasBin: true - peerDependencies: - typescript: '>=4.1.0' - dependencies: - '@types/prettier': 2.7.3 - command-line-args: 4.0.7 - debug: 4.3.4(supports-color@8.1.1) - fs-extra: 7.0.1 - glob: 7.2.3 - js-sha3: 0.8.0 - lodash: 4.17.21 - mkdirp: 1.0.4 - prettier: 2.8.8 - ts-essentials: 7.0.3(typescript@5.3.3) - typescript: 5.3.3 - transitivePeerDependencies: - - supports-color - dev: true - - /typescript@4.9.5: - resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} - engines: {node: '>=4.2.0'} - hasBin: true - dev: true - - /typescript@5.3.3: - resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} - engines: {node: '>=14.17'} - hasBin: true - dev: true - - /typical@2.6.1: - resolution: {integrity: sha512-ofhi8kjIje6npGozTip9Fr8iecmYfEbS06i0JnIg+rh51KakryWF4+jX8lLKZVhy6N+ID45WYSFCxPOdTWCzNg==} - dev: true - - /uglify-js@3.17.4: - resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==} - engines: {node: '>=0.8.0'} - hasBin: true - requiresBuild: true - dev: true - optional: true - - /undici-types@5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - dev: true - - /undici@5.28.2: - resolution: {integrity: sha512-wh1pHJHnUeQV5Xa8/kyQhO7WFa8M34l026L5P/+2TYiakvGy5Rdc8jWZVyG7ieht/0WgJLEd3kcU5gKx+6GC8w==} - engines: {node: '>=14.0'} - dependencies: - '@fastify/busboy': 2.1.0 - dev: true - - /universalify@0.1.2: - resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} - engines: {node: '>= 4.0.0'} - dev: true - - /universalify@2.0.1: - resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} - engines: {node: '>= 10.0.0'} - dev: true - - /unpipe@1.0.0: - resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} - engines: {node: '>= 0.8'} - dev: true - - /uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - dependencies: - punycode: 2.3.1 - dev: true - - /utf8@3.0.0: - resolution: {integrity: sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==} - dev: true - - /util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - dev: true - - /uuid@8.3.2: - resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} - hasBin: true - dev: true - - /web3-utils@1.10.3: - resolution: {integrity: sha512-OqcUrEE16fDBbGoQtZXWdavsPzbGIDc5v3VrRTZ0XrIpefC/viZ1ZU9bGEemazyS0catk/3rkOOxpzTfY+XsyQ==} - engines: {node: '>=8.0.0'} - dependencies: - '@ethereumjs/util': 8.1.0 - bn.js: 5.2.1 - ethereum-bloom-filters: 1.0.10 - ethereum-cryptography: 2.1.3 - ethjs-unit: 0.1.6 - number-to-bn: 1.7.0 - randombytes: 2.1.0 - utf8: 3.0.0 - dev: true - - /webidl-conversions@3.0.1: - resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - dev: true - - /whatwg-url@5.0.0: - resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} - dependencies: - tr46: 0.0.3 - webidl-conversions: 3.0.1 - dev: true - - /which@1.3.1: - resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} - hasBin: true - dependencies: - isexe: 2.0.0 - dev: true - - /widest-line@3.1.0: - resolution: {integrity: sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==} - engines: {node: '>=8'} - dependencies: - string-width: 4.2.3 - dev: true - - /word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - dev: true - - /wordwrap@1.0.0: - resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} - dev: true - - /workerpool@6.2.1: - resolution: {integrity: sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==} - dev: true - - /wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - dev: true - - /wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - dev: true - - /ws@7.4.6: - resolution: {integrity: sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==} - engines: {node: '>=8.3.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - dev: true - - /ws@7.5.9: - resolution: {integrity: sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==} - engines: {node: '>=8.3.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - dev: true - - /y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - dev: true - - /yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - dev: true - - /yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - dev: true - - /yargs-parser@20.2.4: - resolution: {integrity: sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==} - engines: {node: '>=10'} - dev: true - - /yargs-unparser@2.0.0: - resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} - engines: {node: '>=10'} - dependencies: - camelcase: 6.3.0 - decamelize: 4.0.0 - flat: 5.0.2 - is-plain-obj: 2.1.0 - dev: true - - /yargs@16.2.0: - resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} - engines: {node: '>=10'} - dependencies: - cliui: 7.0.4 - escalade: 3.1.1 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 20.2.4 - dev: true - - /yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - dev: true - - /zksync-web3@0.14.4(ethers@5.7.2): - resolution: {integrity: sha512-kYehMD/S6Uhe1g434UnaMN+sBr9nQm23Ywn0EUP5BfQCsbjcr3ORuS68PosZw8xUTu3pac7G6YMSnNHk+fwzvg==} - deprecated: This package has been deprecated in favor of zksync-ethers@5.0.0 - peerDependencies: - ethers: ^5.7.0 - dependencies: - ethers: 5.7.2 - dev: true - - github.com/dapphub/ds-test/e282159d5170298eb2455a6c05280ab5a73a4ef0: - resolution: {tarball: https://codeload.github.com/dapphub/ds-test/tar.gz/e282159d5170298eb2455a6c05280ab5a73a4ef0} - name: ds-test - version: 1.0.0 - dev: true - - github.com/erc7579/erc7579-implementation/15aa5bba6cbf287eeb2b094b4ade9d2567be3729: - resolution: {tarball: https://codeload.github.com/erc7579/erc7579-implementation/tar.gz/15aa5bba6cbf287eeb2b094b4ade9d2567be3729} - name: micro-msa - version: 0.3.1 - dependencies: - '@openzeppelin/contracts': 5.0.1 - dev: true - - github.com/eth-infinitism/account-abstraction/0766b38ad165bfaecdd60b46cf72db93aa6793a9(ethers@5.4.0)(hardhat@2.19.5)(lodash@4.17.21)(typechain@5.2.0): - resolution: {tarball: https://codeload.github.com/eth-infinitism/account-abstraction/tar.gz/0766b38ad165bfaecdd60b46cf72db93aa6793a9} - id: github.com/eth-infinitism/account-abstraction/0766b38ad165bfaecdd60b46cf72db93aa6793a9 - name: accountabstraction - version: 0.6.0 - dependencies: - '@nomiclabs/hardhat-etherscan': 2.1.8(hardhat@2.19.5) - '@openzeppelin/contracts': 5.0.1 - '@thehubbleproject/bls': 0.5.1 - '@typechain/hardhat': 2.3.1(hardhat@2.19.5)(lodash@4.17.21)(typechain@5.2.0) - '@types/mocha': 9.1.1 - ethereumjs-util: 7.1.5 - ethereumjs-wallet: 1.0.2 - hardhat-deploy: 0.11.45 - hardhat-deploy-ethers: 0.3.0-beta.13(ethers@5.4.0)(hardhat@2.19.5) - solidity-coverage: 0.8.6(hardhat@2.19.5) - source-map-support: 0.5.21 - table: 6.8.1 - typescript: 4.9.5 - transitivePeerDependencies: - - bufferutil - - encoding - - ethers - - hardhat - - lodash - - supports-color - - typechain - - utf-8-validate - dev: true - - github.com/foundry-rs/forge-std/4513bc2063f23c57bee6558799584b518d387a39: - resolution: {tarball: https://codeload.github.com/foundry-rs/forge-std/tar.gz/4513bc2063f23c57bee6558799584b518d387a39} - name: forge-std - version: 1.7.6 - dev: true - - github.com/rhinestonewtf/modulekit/03c51550d68bfd46674bf8221f300318952439d4: - resolution: {tarball: https://codeload.github.com/rhinestonewtf/modulekit/tar.gz/03c51550d68bfd46674bf8221f300318952439d4} - name: '@rhinestone/modulekit' - version: 0.3.1 - dependencies: - '@openzeppelin/contracts': 5.0.1 - dev: true - - github.com/rhinestonewtf/sessionkeymanager/100f86b662bc16fbd7df374cd665a35c10f3a7b6: - resolution: {tarball: https://codeload.github.com/rhinestonewtf/sessionkeymanager/tar.gz/100f86b662bc16fbd7df374cd665a35c10f3a7b6} - name: sessionkeyManager - version: 1.0.0 - dev: true - - github.com/sablier-labs/solarray/6bf10cb34cdace52a3ba5fe437e78cc82df92684: - resolution: {tarball: https://codeload.github.com/sablier-labs/solarray/tar.gz/6bf10cb34cdace52a3ba5fe437e78cc82df92684} - name: solarray - version: 1.0.0 - dev: true - - github.com/transmissions11/solmate/c892309933b25c03d32b1b0d674df7ae292ba925: - resolution: {tarball: https://codeload.github.com/transmissions11/solmate/tar.gz/c892309933b25c03d32b1b0d674df7ae292ba925} - name: solmate - version: 6.2.0 - dev: true - - github.com/vectorized/solady/54ea1543a229b88b44ccb6ec5ea570135811a7d9: - resolution: {tarball: https://codeload.github.com/vectorized/solady/tar.gz/54ea1543a229b88b44ccb6ec5ea570135811a7d9} - name: solady - version: 0.0.166 - dev: true - - github.com/zeroknots/sentinellist/1f9ec0250f1b3f14ba5d200629e3d9f3264fde61: - resolution: {tarball: https://codeload.github.com/zeroknots/sentinellist/tar.gz/1f9ec0250f1b3f14ba5d200629e3d9f3264fde61} - name: sentinellist - version: 0.0.0 - dev: true diff --git a/src/accounts/safe/remappings.txt b/src/accounts/safe/remappings.txt deleted file mode 100644 index 1902faa9..00000000 --- a/src/accounts/safe/remappings.txt +++ /dev/null @@ -1,15 +0,0 @@ -ds-test/=node_modules/ds-test/src/ -forge-std/=node_modules/forge-std/src/ -modulekit/=node_modules/@rhinestone/modulekit/src/ -modulekit/SessionKeyManager/=node_modules/@rhinestone/sessionkeymanager/src/ -account-abstraction/=node_modules/account-abstraction/contracts/ -erc7579/=node_modules/erc7579/src/ -sentinellist/=node_modules/sentinellist/src/ -solmate/=node_modules/solmate/src/ -solady/=node_modules/solady/ -solarray/=node_modules/solarray/src/ -@openzeppelin/=node_modules/@openzeppelin/ -@rhinestone/modulekit/=node_modules/@rhinestone/modulekit/src/ -@rhinestone/sessionkeymanager/=node_modules/@rhinestone/sessionkeymanager/src/ -umsa/=node_modules/micro-msa/src/ -@safe-global/=node_modules/@safe-global/ diff --git a/src/accounts/safe/src/Account.sol b/src/accounts/safe/src/Account.sol deleted file mode 100644 index 006666e5..00000000 --- a/src/accounts/safe/src/Account.sol +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.23; - -import "forge-std/Test.sol"; -import { SafeERC7579 } from "./SafeERC7579.sol"; - -import "@safe-global/safe-contracts/contracts/Safe.sol"; -import { LibClone } from "solady/src/utils/LibClone.sol"; - -contract AccountFactory is Test { - // singletons - SafeERC7579 erc7579Mod = new SafeERC7579(); - Safe safeImpl = new Safe(); - Safe safe; - - function safeSetup( - address[] memory signers, - uint256 threshold, - address defaultValidator, - address defaultExecutor - ) - public - returns (address _clone) - { - Safe clone = Safe(payable(LibClone.clone(address(safeImpl)))); - _clone = address(clone); - - clone.setup({ - _owners: signers, - _threshold: threshold, - to: address(0), // optional delegatecall - data: "", - fallbackHandler: address(erc7579Mod), - paymentToken: address(0), // optional payment token - payment: 0, - paymentReceiver: payable(address(0)) // optional payment receiver - }); - - vm.startPrank(address(clone)); - clone.enableModule(address(erc7579Mod)); - address[] memory validators = new address[](1); - validators[0] = address(defaultValidator); - - address[] memory executors = new address[](1); - executors[0] = address(defaultExecutor); - erc7579Mod.initializeAccount(abi.encode(validators, executors)); - vm.stopPrank(); - } -} diff --git a/src/accounts/safe/src/ExecutionHelper.sol b/src/accounts/safe/src/ExecutionHelper.sol deleted file mode 100644 index b2d12bd6..00000000 --- a/src/accounts/safe/src/ExecutionHelper.sol +++ /dev/null @@ -1,58 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.0 <0.9.0; - -import { Execution } from "erc7579/interfaces/IERC7579Account.sol"; -import "./interfaces/ISafe.sol"; -import "forge-std/console2.sol"; - -contract ExecutionHelper { - function _execute( - address safe, - address target, - uint256 value, - bytes calldata callData - ) - internal - { - bool success = ISafe(safe).execTransactionFromModule(target, value, callData, 0); - require(success, "Execution failed"); - } - - function _executeReturnData( - address safe, - address target, - uint256 value, - bytes calldata callData - ) - internal - returns (bytes memory returnData) - { - bool success; - (success, returnData) = - ISafe(safe).execTransactionFromModuleReturnData(target, value, callData, 0); - require(success, "Execution failed"); - } - - function _execute(address safe, Execution[] calldata executions) internal { - uint256 length = executions.length; - for (uint256 i; i < length; i++) { - _execute(safe, executions[i].target, executions[i].value, executions[i].callData); - } - } - - function _executeReturnData( - address safe, - Execution[] calldata executions - ) - internal - returns (bytes[] memory retData) - { - uint256 length = executions.length; - retData = new bytes[](length); - for (uint256 i; i < length; i++) { - retData[i] = _executeReturnData( - safe, executions[i].target, executions[i].value, executions[i].callData - ); - } - } -} diff --git a/src/accounts/safe/src/HookManager.sol b/src/accounts/safe/src/HookManager.sol deleted file mode 100644 index 56088dc7..00000000 --- a/src/accounts/safe/src/HookManager.sol +++ /dev/null @@ -1,67 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.23; - -import "./ModuleManager.sol"; -import "erc7579/interfaces/IERC7579Account.sol"; -import "erc7579/interfaces/IERC7579Module.sol"; -/** - * @title reference implementation of HookManager - * @author zeroknots.eth | rhinestone.wtf - */ - -abstract contract HookManager is ModuleManager { - /// @custom:storage-location erc7201:hookmanager.storage.msa - struct HookManagerStorage { - IHook _hook; - } - - mapping(address smartAccount => HookManagerStorage) private _hookManagerStorage; - - // keccak256("hookmanager.storage.msa"); - bytes32 constant HOOKMANAGER_STORAGE_LOCATION = - 0x36e05829dd1b9a4411d96a3549582172d7f071c1c0db5c573fcf94eb28431608; - - error HookPostCheckFailed(); - error HookAlreadyInstalled(address currentHook); - - modifier withHook() { - address hook = _getHook(msg.sender); - if (hook == address(0)) { - _; - } else { - bytes memory hookData = IHook(hook).preCheck(_msgSender(), msg.data); - _; - if (!IHook(hook).postCheck(hookData)) revert HookPostCheckFailed(); - } - } - - function _setHook(address hook) internal virtual { - _hookManagerStorage[msg.sender]._hook = IHook(hook); - } - - function _installHook(address hook, bytes calldata data) internal virtual { - address currentHook = _getHook(msg.sender); - if (currentHook != address(0)) { - revert HookAlreadyInstalled(currentHook); - } - _setHook(hook); - IHook(hook).onInstall(data); - } - - function _uninstallHook(address hook, bytes calldata data) internal virtual { - _setHook(address(0)); - IHook(hook).onUninstall(data); - } - - function _getHook(address smartAccount) internal view returns (address _hook) { - return address(_hookManagerStorage[smartAccount]._hook); - } - - function _isHookInstalled(address module) internal view returns (bool) { - return _getHook(msg.sender) == module; - } - - function getActiveHook() external view returns (address hook) { - return _getHook(msg.sender); - } -} diff --git a/src/accounts/safe/src/ModuleManager.sol b/src/accounts/safe/src/ModuleManager.sol deleted file mode 100644 index bc1114e6..00000000 --- a/src/accounts/safe/src/ModuleManager.sol +++ /dev/null @@ -1,328 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.23; - -import { SentinelListLib, SENTINEL } from "sentinellist/SentinelList.sol"; -import { AccountBase } from "erc7579/core/AccountBase.sol"; -import "erc7579/interfaces/IERC7579Module.sol"; -import { Receiver } from "erc7579/core/Receiver.sol"; -import "./AccessControl.sol"; -import "./interfaces/ISafe.sol"; - -import "forge-std/console2.sol"; - -struct ValidatorManagerStorage { - // linked list of validators. List is initialized by initializeAccount() - SentinelListLib.SentinelList _validators; -} - -struct ModuleManagerStorage { - // linked list of executors. List is initialized by initializeAccount() - SentinelListLib.SentinelList _executors; - // single fallback handler for all fallbacks - // account vendors may implement this differently. This is just a reference implementation - address fallbackHandler; - // single hook - address hook; -} - -// keccak256("modulemanager.storage.msa"); -bytes32 constant MODULEMANAGER_STORAGE_LOCATION = - 0xf88ce1fdb7fb1cbd3282e49729100fa3f2d6ee9f797961fe4fb1871cea89ea02; - -function _getValidatorStorage() pure returns (ValidatorManagerStorage storage ims) { - bytes32 position = MODULEMANAGER_STORAGE_LOCATION; - assembly { - ims.slot := position - } -} - -contract ModuleStorage { - using SentinelListLib for SentinelListLib.SentinelList; - - function initModuleManager() external virtual { - ValidatorManagerStorage storage ims = _getValidatorStorage(); - ims._validators.init(); - } - ///////////////////////////////////////////////////// - // Manage Validators - //////////////////////////////////////////////////// - - function installValidator(address validator, bytes calldata data) external virtual { - SentinelListLib.SentinelList storage _validators = _getValidatorStorage()._validators; - _validators.push(validator); - IValidator(validator).onInstall(data); - } - - function uninstallValidator(address validator, bytes calldata data) external { - // TODO: check if its the last validator. this might brick the account - SentinelListLib.SentinelList storage _validators = _getValidatorStorage()._validators; - (address prev, bytes memory disableModuleData) = abi.decode(data, (address, bytes)); - _validators.pop(prev, validator); - IValidator(validator).onUninstall(disableModuleData); - } - - function isValidatorInstalled(address validator) external view virtual returns (bool) { - SentinelListLib.SentinelList storage _validators = _getValidatorStorage()._validators; - return _validators.contains(validator); - } -} - -/** - * @title ModuleManager - * @author zeroknots.eth | rhinestone.wtf - */ -abstract contract ModuleManager is AccessControl, Receiver { - using SentinelListLib for SentinelListLib.SentinelList; - - error InvalidModule(address module); - error CannotRemoveLastValidator(); - - ModuleStorage immutable STORAGE_MANAGER; - - mapping(address smartAccount => ModuleManagerStorage) private _moduleManagerStorage; - - constructor() { - STORAGE_MANAGER = new ModuleStorage(); - } - - function _getModuleManagerStorage(address account) - internal - view - returns (ModuleManagerStorage storage ims) - { - return _moduleManagerStorage[account]; - } - - modifier onlyExecutorModule() { - if (!_isExecutorInstalled(_msgSender())) revert InvalidModule(_msgSender()); - _; - } - - function _initModuleManager() internal { - bool success = ISafe(msg.sender).execTransactionFromModule({ - to: address(STORAGE_MANAGER), - value: 0, - data: abi.encodeCall(ModuleStorage.initModuleManager, ()), - operation: 1 - }); - require(success, "ModuleManager: failed to initialize module manager"); - - ModuleManagerStorage storage ims = _getModuleManagerStorage(msg.sender); - ims._executors.init(); - } - - ///////////////////////////////////////////////////// - // Manage Validators - //////////////////////////////////////////////////// - function _installValidator(address validator, bytes calldata data) internal virtual { - bool success = ISafe(msg.sender).execTransactionFromModule({ - to: address(STORAGE_MANAGER), - value: 0, - data: abi.encodeCall(ModuleStorage.installValidator, (validator, data)), - operation: 1 - }); - require(success, "ModuleManager: failed to install validator"); - } - - function _uninstallValidator(address validator, bytes calldata data) internal { - bool success = ISafe(msg.sender).execTransactionFromModule({ - to: address(STORAGE_MANAGER), - value: 0, - data: abi.encodeCall(ModuleStorage.uninstallValidator, (validator, data)), - operation: 1 - }); - require(success, "ModuleManager: failed to uninstall validator"); - } - - function getKeyEncodedWithMappingIndex( - SentinelListLib.SentinelList storage linkedList, - address key - ) - private - pure - returns (bytes32 hash) - { - bytes32 slot; - assembly { - slot := linkedList.slot - mstore(0, key) - mstore(0x20, slot) - hash := keccak256(0, 0x40) - } - } - - function _isValidatorInstalled(address validator) internal view virtual returns (bool) { - // calculate slot for linked list - SentinelListLib.SentinelList storage _validators = _getValidatorStorage()._validators; - bytes32 slot = getKeyEncodedWithMappingIndex(_validators, validator); - bytes32 value = bytes32(ISafe(msg.sender).getStorageAt(uint256(slot), 1)); - address link = address(uint160(uint256(value))); - bool ok = SENTINEL != validator && link != address(0); - return ok; - } - - /** - * THIS IS NOT PART OF THE STANDARD - * Helper Function to access linked list - */ - function getValidatorPaginated( - address start, - uint256 pageSize - ) - external - view - virtual - returns (address[] memory array, address next) - { - if (start != SENTINEL && _isExecutorInstalled(start)) revert(); - if (pageSize == 0) revert(); - - array = new address[](pageSize); - - // Populate return array - uint256 entryCount = 0; - SentinelListLib.SentinelList storage _validators = _getValidatorStorage()._validators; - bytes32 slot = getKeyEncodedWithMappingIndex(_validators, start); - bytes32 value = bytes32(ISafe(msg.sender).getStorageAt(uint256(slot), 1)); - address next = address(uint160(uint256(value))); - while (next != address(0) && next != SENTINEL && entryCount < pageSize) { - array[entryCount] = next; - bytes32 slot = getKeyEncodedWithMappingIndex(_validators, next); - bytes32 value = bytes32(ISafe(msg.sender).getStorageAt(uint256(slot), 1)); - address next = address(uint160(uint256(value))); - entryCount++; - } - - /** - * Because of the argument validation, we can assume that the loop will always iterate over - * the valid entry list values - * and the `next` variable will either be an enabled entry or a sentinel address - * (signalling the end). - * - * If we haven't reached the end inside the loop, we need to set the next pointer to - * the last element of the entry array - * because the `next` variable (which is a entry by itself) acting as a pointer to the - * start of the next page is neither - * incSENTINELrent page, nor will it be included in the next one if you pass it as a - * start. - */ - if (next != SENTINEL) { - next = array[entryCount - 1]; - } - // Set correct size of returned array - // solhint-disable-next-line no-inline-assembly - /// @solidity memory-safe-assembly - assembly { - mstore(array, entryCount) - } - } - - ///////////////////////////////////////////////////// - // Manage Executors - //////////////////////////////////////////////////// - - function _installExecutor(address executor, bytes calldata data) internal { - SentinelListLib.SentinelList storage _executors = - _getModuleManagerStorage(msg.sender)._executors; - _executors.push(executor); - IExecutor(executor).onInstall(data); - } - - function _uninstallExecutor(address executor, bytes calldata data) internal { - SentinelListLib.SentinelList storage _executors = - _getModuleManagerStorage(msg.sender)._executors; - (address prev, bytes memory disableModuleData) = abi.decode(data, (address, bytes)); - _executors.pop(prev, executor); - IExecutor(executor).onUninstall(disableModuleData); - } - - function _isExecutorInstalled(address executor) internal view virtual returns (bool) { - SentinelListLib.SentinelList storage _executors = - _getModuleManagerStorage(msg.sender)._executors; - return _executors.contains(executor); - } - /** - * THIS IS NOT PART OF THE STANDARD - * Helper Function to access linked list - */ - - function getExecutorsPaginated( - address cursor, - uint256 size - ) - external - view - virtual - returns (address[] memory array, address next) - { - SentinelListLib.SentinelList storage _executors = - _getModuleManagerStorage(msg.sender)._executors; - return _executors.getEntriesPaginated(cursor, size); - } - - ///////////////////////////////////////////////////// - // Manage Fallback - //////////////////////////////////////////////////// - - function _installFallbackHandler(address handler, bytes calldata initData) internal virtual { - ModuleManagerStorage storage ims = _getModuleManagerStorage(msg.sender); - ims.fallbackHandler = handler; - IFallback(handler).onInstall(initData); - } - - function _uninstallFallbackHandler(address handler, bytes calldata initData) internal virtual { - ModuleManagerStorage storage ims = _getModuleManagerStorage(msg.sender); - ims.fallbackHandler = address(0); - IFallback(handler).onUninstall(initData); - } - - function _getFallbackHandler() internal view virtual returns (address fallbackHandler) { - ModuleManagerStorage storage ims = _getModuleManagerStorage(msg.sender); - return ims.fallbackHandler; - } - - function _isFallbackHandlerInstalled(address _handler) internal view virtual returns (bool) { - return _getFallbackHandler() == _handler; - } - - function getActiveFallbackHandler() external view virtual returns (address) { - return _getFallbackHandler(); - } - - // FALLBACK - fallback() external payable override(Receiver) receiverFallback { - address handler = _getFallbackHandler(); - if (handler == address(0)) revert(); - /* solhint-disable no-inline-assembly */ - /// @solidity memory-safe-assembly - assembly { - // When compiled with the optimizer, the compiler relies on a certain assumptions on how - // the - // memory is used, therefore we need to guarantee memory safety (keeping the free memory - // point 0x40 slot intact, - // not going beyond the scratch space, etc) - // Solidity docs: https://docs.soliditylang.org/en/latest/assembly.html#memory-safety - function allocate(length) -> pos { - pos := mload(0x40) - mstore(0x40, add(pos, length)) - } - - let calldataPtr := allocate(calldatasize()) - calldatacopy(calldataPtr, 0, calldatasize()) - - // The msg.sender address is shifted to the left by 12 bytes to remove the padding - // Then the address without padding is stored right after the calldata - let senderPtr := allocate(20) - mstore(senderPtr, shl(96, caller())) - - // Add 20 bytes for the address appended add the end - let success := call(gas(), handler, 0, calldataPtr, add(calldatasize(), 20), 0, 0) - - let returnDataPtr := allocate(returndatasize()) - returndatacopy(returnDataPtr, 0, returndatasize()) - if iszero(success) { revert(returnDataPtr, returndatasize()) } - return(returnDataPtr, returndatasize()) - } - /* solhint-enable no-inline-assembly */ - } -} diff --git a/src/external/ERC4337.sol b/src/external/ERC4337.sol deleted file mode 100644 index 262064ef..00000000 --- a/src/external/ERC4337.sol +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.23; - -/* solhint-disable no-unused-import */ -import { PackedUserOperation } from "account-abstraction/interfaces/PackedUserOperation.sol"; -import { UserOperationLib } from "account-abstraction/core/UserOperationLib.sol"; -import { IEntryPoint } from "account-abstraction/interfaces/IEntryPoint.sol"; -import { IEntryPointSimulations } from "account-abstraction/interfaces/IEntryPointSimulations.sol"; -import { ValidationData, _packValidationData } from "account-abstraction/core/Helpers.sol"; -import { IStakeManager } from "account-abstraction/interfaces/IStakeManager.sol"; - -/* solhint-enable no-unused-import */ diff --git a/src/modules/ERC7579HookDestruct.sol b/src/modules/ERC7579HookDestruct.sol deleted file mode 100644 index 0adcbaea..00000000 --- a/src/modules/ERC7579HookDestruct.sol +++ /dev/null @@ -1,148 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.23; - -import { ERC7579HookBase } from "./ERC7579HookBase.sol"; -import { IERC7579Account } from "../Accounts.sol"; -import { ExecutionLib, Execution } from "erc7579/lib/ExecutionLib.sol"; -import { - ModeLib, - CallType, - ModeCode, - CALLTYPE_SINGLE, - CALLTYPE_BATCH, - CALLTYPE_DELEGATECALL -} from "erc7579/lib/ModeLib.sol"; - -abstract contract ERC7579HookDestruct is ERC7579HookBase { - error HookInvalidSelector(); - - /*////////////////////////////////////////////////////////////////////////// - CALLDATA DECODING - //////////////////////////////////////////////////////////////////////////*/ - - function preCheck( - address msgSender, - bytes calldata msgData - ) - external - override - returns (bytes memory hookData) - { - bytes4 selector = bytes4(msgData[0:4]); - - if (selector == IERC7579Account.execute.selector) { - ModeCode mode = ModeCode.wrap(bytes32(msgData[4:36])); - CallType calltype = ModeLib.getCallType(mode); - if (calltype == CALLTYPE_SINGLE) { - (address to, uint256 value, bytes calldata callData) = - ExecutionLib.decodeSingle(msgData[36:]); - return onExecute(msgSender, to, value, callData); - } else if (calltype == CALLTYPE_BATCH) { - Execution[] calldata execs = ExecutionLib.decodeBatch(msgData[36:]); - return onExecuteBatch(msgSender, execs); - } else { - revert HookInvalidSelector(); - } - } else if (selector == IERC7579Account.executeFromExecutor.selector) { - ModeCode mode = ModeCode.wrap(bytes32(msgData[4:36])); - CallType calltype = ModeLib.getCallType(mode); - if (calltype == CALLTYPE_SINGLE) { - (address to, uint256 value, bytes calldata callData) = - ExecutionLib.decodeSingle(msgData[36:]); - return onExecuteFromExecutor(msgSender, to, value, callData); - } else if (calltype == CALLTYPE_BATCH) { - Execution[] calldata execs = ExecutionLib.decodeBatch(msgData[36:]); - return onExecuteBatchFromExecutor(msgSender, execs); - } else { - revert HookInvalidSelector(); - } - } else if (selector == IERC7579Account.installModule.selector) { - uint256 moduleType = uint256(bytes32(msgData[4:24])); - address module = address(bytes20(msgData[24:36])); - bytes calldata initData = msgData[36:]; - onInstallModule(msgSender, moduleType, module, initData); - } else if (selector == IERC7579Account.uninstallModule.selector) { - uint256 moduleType = uint256(bytes32(msgData[4:24])); - address module = address(bytes20(msgData[24:36])); - bytes calldata initData = msgData[36:]; - onUninstallModule(msgSender, moduleType, module, initData); - } else { - revert HookInvalidSelector(); - } - } - - function postCheck(bytes calldata hookData) external override returns (bool success) { - if (hookData.length == 0) return true; - return onPostCheck(hookData); - } - - /*////////////////////////////////////////////////////////////////////////// - EXECUTION - //////////////////////////////////////////////////////////////////////////*/ - - function onExecute( - address msgSender, - address target, - uint256 value, - bytes calldata callData - ) - internal - virtual - returns (bytes memory hookData); - - function onExecuteBatch( - address msgSender, - Execution[] calldata - ) - internal - virtual - returns (bytes memory hookData); - - function onExecuteFromExecutor( - address msgSender, - address target, - uint256 value, - bytes calldata callData - ) - internal - virtual - returns (bytes memory hookData); - - function onExecuteBatchFromExecutor( - address msgSender, - Execution[] calldata - ) - internal - virtual - returns (bytes memory hookData); - - /*////////////////////////////////////////////////////////////////////////// - CONFIG - //////////////////////////////////////////////////////////////////////////*/ - - function onInstallModule( - address msgSender, - uint256 moduleType, - address module, - bytes calldata initData - ) - internal - virtual - returns (bytes memory hookData); - - function onUninstallModule( - address msgSender, - uint256 moduleType, - address module, - bytes calldata deInitData - ) - internal - virtual - returns (bytes memory hookData); - - /*////////////////////////////////////////////////////////////////////////// - POSTCHECK - //////////////////////////////////////////////////////////////////////////*/ - - function onPostCheck(bytes calldata hookData) internal virtual returns (bool success); -}