From 1526387dc54b6f83da5de9ededa2eb39d5ce7993 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Mon, 4 Mar 2024 14:27:53 +0700 Subject: [PATCH 01/64] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Addin?= =?UTF-8?q?g=20safe=20query=20on=207579=20acocuntId()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- accounts/safe7579/src/SafeERC7579.sol | 4 +++- accounts/safe7579/src/interfaces/ISafe.sol | 2 ++ accounts/safe7579/test/Base.t.sol | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index 03945dd4..6cf768f5 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -264,7 +264,9 @@ contract SafeERC7579 is ISafeOp, IERC7579Account, AccessControl, IMSA, HookManag * @inheritdoc IERC7579Account */ function accountId() external pure override returns (string memory accountImplementationId) { - return "safe-erc7579.v0.0.0"; + // TODO: concat safe version + string memory safeVersion = ISafe(_msgSender()).VERSION(); + return abi.encodePackedad(safeVersion, "erc7579.v0.0.0"); } /** diff --git a/accounts/safe7579/src/interfaces/ISafe.sol b/accounts/safe7579/src/interfaces/ISafe.sol index 04c6b4a5..25ee4efb 100644 --- a/accounts/safe7579/src/interfaces/ISafe.sol +++ b/accounts/safe7579/src/interfaces/ISafe.sol @@ -82,4 +82,6 @@ interface ISafe { * @param module Module to be enabled. */ function enableModule(address module) external; + + function VERSION() external view returns (string memory); } diff --git a/accounts/safe7579/test/Base.t.sol b/accounts/safe7579/test/Base.t.sol index 70978819..82cd0099 100644 --- a/accounts/safe7579/test/Base.t.sol +++ b/accounts/safe7579/test/Base.t.sol @@ -76,6 +76,7 @@ contract TestBaseUtil is Test { signers[0] = signer1.addr; signers[1] = signer2.addr; + // TODO: think about launchpad impl see: passkey for safe. clone.setup({ _owners: signers, _threshold: 2, From b14fc84aba7d20f2bf914b3d294d1583bdffb82f Mon Sep 17 00:00:00 2001 From: zeroknots Date: Fri, 8 Mar 2024 10:16:37 +0700 Subject: [PATCH 02/64] proxy creation --- accounts/safe7579/src/SafeERC7579.sol | 20 +- .../safe7579/src/core/ExecutionHelper.sol | 19 + accounts/safe7579/src/utils/SafeLaunchpad.sol | 364 ++++++++++++++++++ .../src/utils/SignatureValidatorConstants.sol | 15 + accounts/safe7579/src/utils/SignerFactory.sol | 18 + accounts/safe7579/test/Launchpad.t.sol | 91 +++++ 6 files changed, 524 insertions(+), 3 deletions(-) create mode 100644 accounts/safe7579/src/utils/SafeLaunchpad.sol create mode 100644 accounts/safe7579/src/utils/SignatureValidatorConstants.sol create mode 100644 accounts/safe7579/src/utils/SignerFactory.sol create mode 100644 accounts/safe7579/test/Launchpad.t.sol diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index 6cf768f5..52f5bae7 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -4,7 +4,12 @@ pragma solidity ^0.8.23; import { IERC7579Account, Execution } from "erc7579/interfaces/IERC7579Account.sol"; import { IMSA } from "erc7579/interfaces/IMSA.sol"; import { - CallType, ModeCode, ModeLib, CALLTYPE_SINGLE, CALLTYPE_BATCH + CallType, + ModeCode, + ModeLib, + CALLTYPE_SINGLE, + CALLTYPE_BATCH, + CALLTYPE_DELEGATECALL } from "erc7579/lib/ModeLib.sol"; import { ExecutionLib } from "erc7579/lib/ExecutionLib.sol"; import { @@ -62,6 +67,10 @@ contract SafeERC7579 is ISafeOp, IERC7579Account, AccessControl, IMSA, HookManag (address target, uint256 value, bytes calldata callData) = executionCalldata.decodeSingle(); _execute(msg.sender, target, value, callData); + } else if (callType == CALLTYPE_DELEGATECALL) { + address target = address(bytes20(executionCalldata[:20])); + bytes calldata callData = executionCalldata[20:]; + _executeDelegateCall(msg.sender, target, callData); } else { revert UnsupportedCallType(callType); } @@ -91,6 +100,11 @@ contract SafeERC7579 is ISafeOp, IERC7579Account, AccessControl, IMSA, HookManag executionCalldata.decodeSingle(); returnData = new bytes[](1); returnData[0] = _executeReturnData(msg.sender, target, value, callData); + } else if (callType == CALLTYPE_DELEGATECALL) { + address target = address(bytes20(executionCalldata[:20])); + bytes calldata callData = executionCalldata[20:]; + returnData = new bytes[](1); + returnData[0] = _executeDelegateCallReturnData(msg.sender, target, callData); } else { revert UnsupportedCallType(callType); } @@ -263,10 +277,10 @@ contract SafeERC7579 is ISafeOp, IERC7579Account, AccessControl, IMSA, HookManag /** * @inheritdoc IERC7579Account */ - function accountId() external pure override returns (string memory accountImplementationId) { + function accountId() external view override returns (string memory accountImplementationId) { // TODO: concat safe version string memory safeVersion = ISafe(_msgSender()).VERSION(); - return abi.encodePackedad(safeVersion, "erc7579.v0.0.0"); + return string(abi.encodePacked(safeVersion, "erc7579.v0.0.0")); } /** diff --git a/accounts/safe7579/src/core/ExecutionHelper.sol b/accounts/safe7579/src/core/ExecutionHelper.sol index 8cf4953d..298d4d80 100644 --- a/accounts/safe7579/src/core/ExecutionHelper.sol +++ b/accounts/safe7579/src/core/ExecutionHelper.sol @@ -71,6 +71,25 @@ abstract contract ExecutionHelper { } } + function _executeDelegateCall(address safe, address target, bytes calldata callData) internal { + bool success = ISafe(safe).execTransactionFromModule(target, 0, callData, 1); + if (!success) revert ExecutionFailed(); + } + + function _executeDelegateCallReturnData( + address safe, + address target, + bytes calldata callData + ) + internal + returns (bytes memory returnData) + { + bool success; + (success, returnData) = + ISafe(safe).execTransactionFromModuleReturnData(target, 0, callData, 1); + if (!success) revert ExecutionFailed(); + } + /** * Execute call on Safe * @dev This function will revert if the call fails diff --git a/accounts/safe7579/src/utils/SafeLaunchpad.sol b/accounts/safe7579/src/utils/SafeLaunchpad.sol new file mode 100644 index 00000000..0f14a07a --- /dev/null +++ b/accounts/safe7579/src/utils/SafeLaunchpad.sol @@ -0,0 +1,364 @@ +// SPDX-License-Identifier: LGPL-3.0-only +pragma solidity >=0.8.0 <0.9.0; + +import { IAccount } from "@ERC4337/account-abstraction/contracts/interfaces/IAccount.sol"; + +import { + PackedUserOperation, + UserOperationLib +} from "@ERC4337/account-abstraction/contracts/core/UserOperationLib.sol"; +import { _packValidationData } from "@ERC4337/account-abstraction/contracts/core/Helpers.sol"; +import { SafeStorage } from "@safe-global/safe-contracts/contracts/libraries/SafeStorage.sol"; +import { SignatureValidatorConstants } from "./SignatureValidatorConstants.sol"; + +interface IUniqueSignerFactory { + /** + * @notice Gets the unique signer address for the specified data. + * @dev The unique signer address must be unique for some given data. The signer is not + * guaranteed to be created yet. + * @param data The signer specific data. + * @return signer The signer address. + */ + function getSigner(bytes memory data) external view returns (address signer); + + /** + * @notice Create a new unique signer for the specified data. + * @dev The unique signer address must be unique for some given data. This must not revert if + * the unique owner already exists. + * @param data The signer specific data. + * @return signer The signer address. + */ + function createSigner(bytes memory data) external returns (address signer); + + /** + * @notice Verifies a signature for the specified address without deploying it. + * @dev This must be equivalent to first deploying the signer with the factory, and then + * verifying the signature + * with it directly: `factory.createSigner(signerData).isValidSignature(message, signature)` + * @param message The signed message. + * @param signature The signature bytes. + * @param signerData The signer data to verify signature for. + * @return magicValue Returns a legacy EIP-1271 magic value + * (`bytes4(keccak256(isValidSignature(bytes,bytes))`) when the signature is valid. Reverting or + * returning any other value implies an invalid signature. + */ + function isValidSignatureForSigner( + bytes32 message, + bytes calldata signature, + bytes calldata signerData + ) + external + view + returns (bytes4 magicValue); +} + +/** + * @title SafeOpLaunchpad - A contract for Safe initialization with custom unique signers that would + * violate ERC-4337 factory rules. + * @dev The is intended to be set as a Safe proxy's implementation for ERC-4337 user operation that + * deploys the account. + */ +contract SafeSignerLaunchpad is IAccount, SafeStorage, SignatureValidatorConstants { + bytes32 private constant DOMAIN_SEPARATOR_TYPEHASH = + keccak256("EIP712Domain(uint256 chainId,address verifyingContract)"); + + // keccak256("SafeSignerLaunchpad.initHash") - 1 + uint256 private constant INIT_HASH_SLOT = + 0x1d2f0b9dbb6ed3f829c9614e6c5d2ea2285238801394dc57e8500e0e306d8f80; + + /** + * @notice The keccak256 hash of the EIP-712 SafeInit struct, representing the structure of a + * ERC-4337 compatible deferred Safe initialization. + * {address} singleton - The singleton to evolve into during the setup. + * {address} signerFactory - The unique signer factory to use for creating an owner. + * {bytes} signerData - The signer data to use the owner. + * {address} setupTo - The contract to delegatecall during setup. + * {bytes} setupData - The calldata for the setup delegatecall. + * {address} fallbackHandler - The fallback handler to initialize the Safe with. + */ + bytes32 private constant SAFE_INIT_TYPEHASH = keccak256( + "SafeInit(address singleton,address signerFactory,bytes signerData,address setupTo,bytes setupData,address fallbackHandler)" + ); + + /** + * @notice The keccak256 hash of the EIP-712 SafeInitOp struct, representing the user operation + * to execute alongside initialization. + * {bytes32} userOpHash - The user operation hash being executed. + * {uint48} validAfter - A timestamp representing from when the user operation is valid. + * {uint48} validUntil - A timestamp representing until when the user operation is valid, or 0 + * to indicated "forever". + * {address} entryPoint - The address of the entry point that will execute the user operation. + */ + bytes32 private constant SAFE_INIT_OP_TYPEHASH = keccak256( + "SafeInitOp(bytes32 userOpHash,uint48 validAfter,uint48 validUntil,address entryPoint)" + ); + + address private immutable SELF; + address public immutable SUPPORTED_ENTRYPOINT; + + constructor(address entryPoint) { + require(entryPoint != address(0), "Invalid entry point"); + + SELF = address(this); + SUPPORTED_ENTRYPOINT = entryPoint; + } + + modifier onlyProxy() { + require(singleton == SELF, "Not called from proxy"); + _; + } + + modifier onlySupportedEntryPoint() { + require(msg.sender == SUPPORTED_ENTRYPOINT, "Unsupported entry point"); + _; + } + + receive() external payable { } + + function preValidationSetup( + bytes32 initHash, + address to, + bytes calldata preInit + ) + external + onlyProxy + { + _setInitHash(initHash); + if (to != address(0)) { + (bool success,) = to.delegatecall(preInit); + require(success, "Pre-initialization failed"); + } + } + + function getInitHash( + address singleton, + address signerFactory, + bytes memory signerData, + address setupTo, + bytes memory setupData, + address fallbackHandler + ) + public + view + returns (bytes32 initHash) + { + initHash = keccak256( + abi.encodePacked( + bytes1(0x19), + bytes1(0x01), + _domainSeparator(), + keccak256( + abi.encode( + SAFE_INIT_TYPEHASH, + singleton, + signerFactory, + keccak256(signerData), + setupTo, + keccak256(setupData), + fallbackHandler + ) + ) + ) + ); + } + + function getOperationHash( + bytes32 userOpHash, + uint48 validAfter, + uint48 validUntil + ) + public + view + returns (bytes32 operationHash) + { + operationHash = keccak256(_getOperationData(userOpHash, validAfter, validUntil)); + } + + function validateUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash, + uint256 missingAccountFunds + ) + external + override + onlyProxy + onlySupportedEntryPoint + returns (uint256 validationData) + { + address signerFactory; + bytes memory signerData; + { + require( + this.initializeThenUserOp.selector == bytes4(userOp.callData[:4]), + "invalid user operation data" + ); + + address singleton; + address setupTo; + bytes memory setupData; + address fallbackHandler; + (singleton, signerFactory, signerData, setupTo, setupData, fallbackHandler,) = abi + .decode(userOp.callData[4:], (address, address, bytes, address, bytes, address, bytes)); + bytes32 initHash = getInitHash( + singleton, signerFactory, signerData, setupTo, setupData, fallbackHandler + ); + + require(initHash == _initHash(), "invalid init hash"); + } + + validationData = _validateSignatures(userOp, userOpHash, signerFactory, signerData); + if (missingAccountFunds > 0) { + // solhint-disable-next-line no-inline-assembly + assembly ("memory-safe") { + // The `pop` is necessary here because solidity 0.5.0 + // enforces "strict" assembly blocks and "statements (elements of a block) are + // disallowed if they return something onto the stack at the end." + // This is not well documented, the quote is taken from here: + // https://github.com/ethereum/solidity/issues/1820 + // The compiler will throw an error if we keep the success value on the stack + pop(call(gas(), caller(), missingAccountFunds, 0, 0, 0, 0)) + } + } + } + + /** + * @dev Validates that the user operation is correctly signed and returns an ERC-4337 packed + * validation data + * of `validAfter || validUntil || authorizer`: + * - `authorizer`: 20-byte address, 0 for valid signature or 1 to mark signature failure (this + * module does not make use of signature aggregators). + * - `validUntil`: 6-byte timestamp value, or zero for "infinite". The user operation is valid + * only up to this time. + * - `validAfter`: 6-byte timestamp. The user operation is valid only after this time. + * @param userOp User operation struct. + * @return validationData An integer indicating the result of the validation. + */ + function _validateSignatures( + PackedUserOperation calldata userOp, + bytes32 userOpHash, + address signerFactory, + bytes memory signerData + ) + internal + view + returns (uint256 validationData) + { + uint48 validAfter; + uint48 validUntil; + bytes calldata signature; + { + bytes calldata sig = userOp.signature; + validAfter = uint48(bytes6(sig[0:6])); + validUntil = uint48(bytes6(sig[6:12])); + signature = sig[12:]; + } + + bytes memory operationData = _getOperationData(userOpHash, validAfter, validUntil); + bytes32 operationHash = keccak256(operationData); + try IUniqueSignerFactory(signerFactory).isValidSignatureForSigner( + operationHash, signature, signerData + ) returns (bytes4 magicValue) { + // The timestamps are validated by the entry point, therefore we will not check them + // again + validationData = + _packValidationData(magicValue != EIP1271_MAGIC_VALUE, validUntil, validAfter); + } catch { + validationData = _packValidationData(true, validUntil, validAfter); + } + } + + function initializeThenUserOp( + address singleton, + address signerFactory, + bytes calldata signerData, + address setupTo, + bytes calldata setupData, + address fallbackHandler, + bytes memory callData + ) + external + onlySupportedEntryPoint + { + SafeStorage.singleton = singleton; + { + address[] memory owners = new address[](1); + owners[0] = IUniqueSignerFactory(signerFactory).createSigner(signerData); + + SafeSetup(address(this)).setup( + owners, 1, setupTo, setupData, fallbackHandler, address(0), 0, payable(address(0)) + ); + } + + (bool success, bytes memory returnData) = address(this).delegatecall(callData); + if (!success) { + // solhint-disable-next-line no-inline-assembly + assembly ("memory-safe") { + revert(add(returnData, 0x20), mload(returnData)) + } + } + + _setInitHash(0); + } + + function _domainSeparator() internal view returns (bytes32) { + return keccak256(abi.encode(DOMAIN_SEPARATOR_TYPEHASH, block.chainid, SELF)); + } + + function _getOperationData( + bytes32 userOpHash, + uint48 validAfter, + uint48 validUntil + ) + internal + view + returns (bytes memory operationData) + { + operationData = abi.encodePacked( + bytes1(0x19), + bytes1(0x01), + _domainSeparator(), + keccak256( + abi.encode( + SAFE_INIT_OP_TYPEHASH, userOpHash, validAfter, validUntil, SUPPORTED_ENTRYPOINT + ) + ) + ); + } + + function _initHash() public view returns (bytes32 value) { + // solhint-disable-next-line no-inline-assembly + assembly ("memory-safe") { + value := sload(INIT_HASH_SLOT) + } + } + + function _setInitHash(bytes32 value) internal { + // solhint-disable-next-line no-inline-assembly + assembly ("memory-safe") { + sstore(INIT_HASH_SLOT, value) + } + } + + function _isContract(address account) internal view returns (bool) { + uint256 size; + // solhint-disable-next-line no-inline-assembly + assembly ("memory-safe") { + size := extcodesize(account) + } + return size > 0; + } +} + +interface SafeSetup { + function setup( + address[] calldata _owners, + uint256 _threshold, + address to, + bytes calldata data, + address fallbackHandler, + address paymentToken, + uint256 payment, + address payable paymentReceiver + ) + external; +} diff --git a/accounts/safe7579/src/utils/SignatureValidatorConstants.sol b/accounts/safe7579/src/utils/SignatureValidatorConstants.sol new file mode 100644 index 00000000..06d5f1d2 --- /dev/null +++ b/accounts/safe7579/src/utils/SignatureValidatorConstants.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: LGPL-3.0-only +/* solhint-disable one-contract-per-file */ +pragma solidity >=0.7.0 <0.9.0; + +/** + * @title SignatureValidatorConstants + * @dev This contract defines the constants used for EIP-1271 signature validation. + */ +contract SignatureValidatorConstants { + // bytes4(keccak256("isValidSignature(bytes32,bytes)") + bytes4 internal constant EIP1271_MAGIC_VALUE = 0x1626ba7e; + + // bytes4(keccak256("isValidSignature(bytes,bytes)") + bytes4 internal constant LEGACY_EIP1271_MAGIC_VALUE = 0x20c13b0b; +} diff --git a/accounts/safe7579/src/utils/SignerFactory.sol b/accounts/safe7579/src/utils/SignerFactory.sol new file mode 100644 index 00000000..cbf3769d --- /dev/null +++ b/accounts/safe7579/src/utils/SignerFactory.sol @@ -0,0 +1,18 @@ +import "./SafeLaunchpad.sol"; + +contract SignerFactory is IUniqueSignerFactory { + function getSigner(bytes memory data) external view override returns (address signer) { } + + function createSigner(bytes memory data) external override returns (address signer) { } + + function isValidSignatureForSigner( + bytes32 message, + bytes calldata signature, + bytes calldata signerData + ) + external + view + override + returns (bytes4 magicValue) + { } +} diff --git a/accounts/safe7579/test/Launchpad.t.sol b/accounts/safe7579/test/Launchpad.t.sol new file mode 100644 index 00000000..e719cc8b --- /dev/null +++ b/accounts/safe7579/test/Launchpad.t.sol @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: LGPL-3.0-only + +pragma solidity ^0.8.0; + +import "forge-std/Test.sol"; + +import "src/SafeERC7579.sol"; +import "src/SafeERC7579.sol"; +import "src/utils/SafeLaunchpad.sol"; +import "@safe-global/safe-contracts/contracts/proxies/SafeProxyFactory.sol"; +import "@safe-global/safe-contracts/contracts/Safe.sol"; + +contract SafeLaunchPadTest is Test { + SafeSignerLaunchpad safeLaunchpad; + SafeERC7579 safe7579; + Safe singleton; + Safe safeAccount; + SafeProxyFactory safeProxyFactory; + + address entrypoint = address(this); + + Account signer1 = makeAccount("signer1"); + Account signer2 = makeAccount("signer2"); + + function setUp() public { + singleton = new Safe(); + safeProxyFactory = new SafeProxyFactory(); + safeLaunchpad = new SafeSignerLaunchpad(entrypoint); + + bytes memory safeLaunchPadSetup; + // Safe.setup, + // ( + // owners, + // 2, + // address(safeLaunchpad), + // safeLaunchPadSetup, + // address(safe7579), + // address(0), + // 0, + // payable(address(0)) + // ) + // ); + + address[] memory owners = new address[](2); + owners[0] = signer1.addr; + owners[1] = signer2.addr; + // SETUP SAFE + bytes memory initializer = abi.encodeCall( + Safe.setup, + ( + owners, + 2, + address(safeLaunchpad), + safeLaunchPadSetup, + address(safe7579), + address(0), + 0, + payable(address(0)) + ) + ); + uint256 salt = 0; + + SafeProxy safeProxy = + safeProxyFactory.createProxyWithNonce(address(singleton), initializer, salt); + } + + /** + * Genereates initcode that will be passed to safeProxyFactory + * @param safeLaunchPadSetup init code for safe launchpad setup() function + */ + function _safeProxyFactory_initcode(bytes memory safeLaunchPadSetup) + internal + returns (bytes memory initCode) + { + // initCode = abi.encodeCall( + // Safe.setup, + // ( + // owners, + // 2, + // address(safeLaunchpad), + // safeLaunchPadSetup, + // address(safe7579), + // address(0), + // 0, + // payable(address(0)) + // ) + // ); + } + + function test_foo() public { } +} From 8987bde03ced887ccd4a54caf08769c14dc6ed64 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Fri, 8 Mar 2024 12:53:53 +0700 Subject: [PATCH 03/64] userOp working. predicting address for userop.sender not working yet --- accounts/safe7579/src/SafeERC7579.sol | 29 +- accounts/safe7579/src/utils/Launchpad.sol | 8 + accounts/safe7579/src/utils/SafeLaunchpad.sol | 364 ------------------ accounts/safe7579/src/utils/SignerFactory.sol | 18 - accounts/safe7579/test/Launchpad.t.sol | 146 +++++-- 5 files changed, 137 insertions(+), 428 deletions(-) create mode 100644 accounts/safe7579/src/utils/Launchpad.sol delete mode 100644 accounts/safe7579/src/utils/SafeLaunchpad.sol delete mode 100644 accounts/safe7579/src/utils/SignerFactory.sol diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index 52f5bae7..b5f25a2e 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -29,12 +29,14 @@ import { } from "@ERC4337/account-abstraction/contracts/core/UserOperationLib.sol"; import { _packValidationData } from "@ERC4337/account-abstraction/contracts/core/Helpers.sol"; +import "forge-std/console2.sol"; /** * @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; @@ -42,6 +44,8 @@ contract SafeERC7579 is ISafeOp, IERC7579Account, AccessControl, IMSA, HookManag error Unsupported(); + event Safe7579Initialized(address indexed safe); + bytes32 private constant DOMAIN_SEPARATOR_TYPEHASH = 0x47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a79469218; @@ -151,6 +155,7 @@ contract SafeERC7579 is ISafeOp, IERC7579Account, AccessControl, IMSA, HookManag // pay prefund if (missingAccountFunds != 0) { + console2.log("missingAccountFunds", missingAccountFunds); _execute({ safe: userOp.getSender(), target: entryPoint(), @@ -368,12 +373,28 @@ contract SafeERC7579 is ISafeOp, IERC7579Account, AccessControl, IMSA, HookManag return keccak256(abi.encode(DOMAIN_SEPARATOR_TYPEHASH, block.chainid, this)); } - function initializeAccount(bytes calldata data) external payable { + function initializeAccount(bytes calldata initCode) external payable { _initModuleManager(); - (address bootstrap, bytes memory bootstrapCall) = abi.decode(data, (address, bytes)); + ( + address[] memory validator, + bytes[] memory validatorInitcode, + address[] memory executors, + bytes[] memory executorsInitcode + ) = abi.decode(initCode, (address[], bytes[], address[], bytes[])); + + uint256 length = validator.length; + if (length != validatorInitcode.length) revert("Invalid input"); + for (uint256 i; i < length; i++) { + _installValidator(validator[i], validatorInitcode[i]); + } + + length = executors.length; + if (length != executorsInitcode.length) revert("Invalid input"); + for (uint256 i; i < length; i++) { + _installExecutor(executors[i], executorsInitcode[i]); + } - (bool success,) = bootstrap.delegatecall(bootstrapCall); - if (!success) revert AccountInitializationFailed(); + emit Safe7579Initialized(msg.sender); } } diff --git a/accounts/safe7579/src/utils/Launchpad.sol b/accounts/safe7579/src/utils/Launchpad.sol new file mode 100644 index 00000000..9323fa82 --- /dev/null +++ b/accounts/safe7579/src/utils/Launchpad.sol @@ -0,0 +1,8 @@ +import "../SafeERC7579.sol"; + +contract Launchpad { + function initSafe7579(address safe7579, bytes calldata safe7579InitCode) public { + ISafe(address(this)).enableModule(safe7579); + SafeERC7579(payable(safe7579)).initializeAccount(safe7579InitCode); + } +} diff --git a/accounts/safe7579/src/utils/SafeLaunchpad.sol b/accounts/safe7579/src/utils/SafeLaunchpad.sol deleted file mode 100644 index 0f14a07a..00000000 --- a/accounts/safe7579/src/utils/SafeLaunchpad.sol +++ /dev/null @@ -1,364 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only -pragma solidity >=0.8.0 <0.9.0; - -import { IAccount } from "@ERC4337/account-abstraction/contracts/interfaces/IAccount.sol"; - -import { - PackedUserOperation, - UserOperationLib -} from "@ERC4337/account-abstraction/contracts/core/UserOperationLib.sol"; -import { _packValidationData } from "@ERC4337/account-abstraction/contracts/core/Helpers.sol"; -import { SafeStorage } from "@safe-global/safe-contracts/contracts/libraries/SafeStorage.sol"; -import { SignatureValidatorConstants } from "./SignatureValidatorConstants.sol"; - -interface IUniqueSignerFactory { - /** - * @notice Gets the unique signer address for the specified data. - * @dev The unique signer address must be unique for some given data. The signer is not - * guaranteed to be created yet. - * @param data The signer specific data. - * @return signer The signer address. - */ - function getSigner(bytes memory data) external view returns (address signer); - - /** - * @notice Create a new unique signer for the specified data. - * @dev The unique signer address must be unique for some given data. This must not revert if - * the unique owner already exists. - * @param data The signer specific data. - * @return signer The signer address. - */ - function createSigner(bytes memory data) external returns (address signer); - - /** - * @notice Verifies a signature for the specified address without deploying it. - * @dev This must be equivalent to first deploying the signer with the factory, and then - * verifying the signature - * with it directly: `factory.createSigner(signerData).isValidSignature(message, signature)` - * @param message The signed message. - * @param signature The signature bytes. - * @param signerData The signer data to verify signature for. - * @return magicValue Returns a legacy EIP-1271 magic value - * (`bytes4(keccak256(isValidSignature(bytes,bytes))`) when the signature is valid. Reverting or - * returning any other value implies an invalid signature. - */ - function isValidSignatureForSigner( - bytes32 message, - bytes calldata signature, - bytes calldata signerData - ) - external - view - returns (bytes4 magicValue); -} - -/** - * @title SafeOpLaunchpad - A contract for Safe initialization with custom unique signers that would - * violate ERC-4337 factory rules. - * @dev The is intended to be set as a Safe proxy's implementation for ERC-4337 user operation that - * deploys the account. - */ -contract SafeSignerLaunchpad is IAccount, SafeStorage, SignatureValidatorConstants { - bytes32 private constant DOMAIN_SEPARATOR_TYPEHASH = - keccak256("EIP712Domain(uint256 chainId,address verifyingContract)"); - - // keccak256("SafeSignerLaunchpad.initHash") - 1 - uint256 private constant INIT_HASH_SLOT = - 0x1d2f0b9dbb6ed3f829c9614e6c5d2ea2285238801394dc57e8500e0e306d8f80; - - /** - * @notice The keccak256 hash of the EIP-712 SafeInit struct, representing the structure of a - * ERC-4337 compatible deferred Safe initialization. - * {address} singleton - The singleton to evolve into during the setup. - * {address} signerFactory - The unique signer factory to use for creating an owner. - * {bytes} signerData - The signer data to use the owner. - * {address} setupTo - The contract to delegatecall during setup. - * {bytes} setupData - The calldata for the setup delegatecall. - * {address} fallbackHandler - The fallback handler to initialize the Safe with. - */ - bytes32 private constant SAFE_INIT_TYPEHASH = keccak256( - "SafeInit(address singleton,address signerFactory,bytes signerData,address setupTo,bytes setupData,address fallbackHandler)" - ); - - /** - * @notice The keccak256 hash of the EIP-712 SafeInitOp struct, representing the user operation - * to execute alongside initialization. - * {bytes32} userOpHash - The user operation hash being executed. - * {uint48} validAfter - A timestamp representing from when the user operation is valid. - * {uint48} validUntil - A timestamp representing until when the user operation is valid, or 0 - * to indicated "forever". - * {address} entryPoint - The address of the entry point that will execute the user operation. - */ - bytes32 private constant SAFE_INIT_OP_TYPEHASH = keccak256( - "SafeInitOp(bytes32 userOpHash,uint48 validAfter,uint48 validUntil,address entryPoint)" - ); - - address private immutable SELF; - address public immutable SUPPORTED_ENTRYPOINT; - - constructor(address entryPoint) { - require(entryPoint != address(0), "Invalid entry point"); - - SELF = address(this); - SUPPORTED_ENTRYPOINT = entryPoint; - } - - modifier onlyProxy() { - require(singleton == SELF, "Not called from proxy"); - _; - } - - modifier onlySupportedEntryPoint() { - require(msg.sender == SUPPORTED_ENTRYPOINT, "Unsupported entry point"); - _; - } - - receive() external payable { } - - function preValidationSetup( - bytes32 initHash, - address to, - bytes calldata preInit - ) - external - onlyProxy - { - _setInitHash(initHash); - if (to != address(0)) { - (bool success,) = to.delegatecall(preInit); - require(success, "Pre-initialization failed"); - } - } - - function getInitHash( - address singleton, - address signerFactory, - bytes memory signerData, - address setupTo, - bytes memory setupData, - address fallbackHandler - ) - public - view - returns (bytes32 initHash) - { - initHash = keccak256( - abi.encodePacked( - bytes1(0x19), - bytes1(0x01), - _domainSeparator(), - keccak256( - abi.encode( - SAFE_INIT_TYPEHASH, - singleton, - signerFactory, - keccak256(signerData), - setupTo, - keccak256(setupData), - fallbackHandler - ) - ) - ) - ); - } - - function getOperationHash( - bytes32 userOpHash, - uint48 validAfter, - uint48 validUntil - ) - public - view - returns (bytes32 operationHash) - { - operationHash = keccak256(_getOperationData(userOpHash, validAfter, validUntil)); - } - - function validateUserOp( - PackedUserOperation calldata userOp, - bytes32 userOpHash, - uint256 missingAccountFunds - ) - external - override - onlyProxy - onlySupportedEntryPoint - returns (uint256 validationData) - { - address signerFactory; - bytes memory signerData; - { - require( - this.initializeThenUserOp.selector == bytes4(userOp.callData[:4]), - "invalid user operation data" - ); - - address singleton; - address setupTo; - bytes memory setupData; - address fallbackHandler; - (singleton, signerFactory, signerData, setupTo, setupData, fallbackHandler,) = abi - .decode(userOp.callData[4:], (address, address, bytes, address, bytes, address, bytes)); - bytes32 initHash = getInitHash( - singleton, signerFactory, signerData, setupTo, setupData, fallbackHandler - ); - - require(initHash == _initHash(), "invalid init hash"); - } - - validationData = _validateSignatures(userOp, userOpHash, signerFactory, signerData); - if (missingAccountFunds > 0) { - // solhint-disable-next-line no-inline-assembly - assembly ("memory-safe") { - // The `pop` is necessary here because solidity 0.5.0 - // enforces "strict" assembly blocks and "statements (elements of a block) are - // disallowed if they return something onto the stack at the end." - // This is not well documented, the quote is taken from here: - // https://github.com/ethereum/solidity/issues/1820 - // The compiler will throw an error if we keep the success value on the stack - pop(call(gas(), caller(), missingAccountFunds, 0, 0, 0, 0)) - } - } - } - - /** - * @dev Validates that the user operation is correctly signed and returns an ERC-4337 packed - * validation data - * of `validAfter || validUntil || authorizer`: - * - `authorizer`: 20-byte address, 0 for valid signature or 1 to mark signature failure (this - * module does not make use of signature aggregators). - * - `validUntil`: 6-byte timestamp value, or zero for "infinite". The user operation is valid - * only up to this time. - * - `validAfter`: 6-byte timestamp. The user operation is valid only after this time. - * @param userOp User operation struct. - * @return validationData An integer indicating the result of the validation. - */ - function _validateSignatures( - PackedUserOperation calldata userOp, - bytes32 userOpHash, - address signerFactory, - bytes memory signerData - ) - internal - view - returns (uint256 validationData) - { - uint48 validAfter; - uint48 validUntil; - bytes calldata signature; - { - bytes calldata sig = userOp.signature; - validAfter = uint48(bytes6(sig[0:6])); - validUntil = uint48(bytes6(sig[6:12])); - signature = sig[12:]; - } - - bytes memory operationData = _getOperationData(userOpHash, validAfter, validUntil); - bytes32 operationHash = keccak256(operationData); - try IUniqueSignerFactory(signerFactory).isValidSignatureForSigner( - operationHash, signature, signerData - ) returns (bytes4 magicValue) { - // The timestamps are validated by the entry point, therefore we will not check them - // again - validationData = - _packValidationData(magicValue != EIP1271_MAGIC_VALUE, validUntil, validAfter); - } catch { - validationData = _packValidationData(true, validUntil, validAfter); - } - } - - function initializeThenUserOp( - address singleton, - address signerFactory, - bytes calldata signerData, - address setupTo, - bytes calldata setupData, - address fallbackHandler, - bytes memory callData - ) - external - onlySupportedEntryPoint - { - SafeStorage.singleton = singleton; - { - address[] memory owners = new address[](1); - owners[0] = IUniqueSignerFactory(signerFactory).createSigner(signerData); - - SafeSetup(address(this)).setup( - owners, 1, setupTo, setupData, fallbackHandler, address(0), 0, payable(address(0)) - ); - } - - (bool success, bytes memory returnData) = address(this).delegatecall(callData); - if (!success) { - // solhint-disable-next-line no-inline-assembly - assembly ("memory-safe") { - revert(add(returnData, 0x20), mload(returnData)) - } - } - - _setInitHash(0); - } - - function _domainSeparator() internal view returns (bytes32) { - return keccak256(abi.encode(DOMAIN_SEPARATOR_TYPEHASH, block.chainid, SELF)); - } - - function _getOperationData( - bytes32 userOpHash, - uint48 validAfter, - uint48 validUntil - ) - internal - view - returns (bytes memory operationData) - { - operationData = abi.encodePacked( - bytes1(0x19), - bytes1(0x01), - _domainSeparator(), - keccak256( - abi.encode( - SAFE_INIT_OP_TYPEHASH, userOpHash, validAfter, validUntil, SUPPORTED_ENTRYPOINT - ) - ) - ); - } - - function _initHash() public view returns (bytes32 value) { - // solhint-disable-next-line no-inline-assembly - assembly ("memory-safe") { - value := sload(INIT_HASH_SLOT) - } - } - - function _setInitHash(bytes32 value) internal { - // solhint-disable-next-line no-inline-assembly - assembly ("memory-safe") { - sstore(INIT_HASH_SLOT, value) - } - } - - function _isContract(address account) internal view returns (bool) { - uint256 size; - // solhint-disable-next-line no-inline-assembly - assembly ("memory-safe") { - size := extcodesize(account) - } - return size > 0; - } -} - -interface SafeSetup { - function setup( - address[] calldata _owners, - uint256 _threshold, - address to, - bytes calldata data, - address fallbackHandler, - address paymentToken, - uint256 payment, - address payable paymentReceiver - ) - external; -} diff --git a/accounts/safe7579/src/utils/SignerFactory.sol b/accounts/safe7579/src/utils/SignerFactory.sol deleted file mode 100644 index cbf3769d..00000000 --- a/accounts/safe7579/src/utils/SignerFactory.sol +++ /dev/null @@ -1,18 +0,0 @@ -import "./SafeLaunchpad.sol"; - -contract SignerFactory is IUniqueSignerFactory { - function getSigner(bytes memory data) external view override returns (address signer) { } - - function createSigner(bytes memory data) external override returns (address signer) { } - - function isValidSignatureForSigner( - bytes32 message, - bytes calldata signature, - bytes calldata signerData - ) - external - view - override - returns (bytes4 magicValue) - { } -} diff --git a/accounts/safe7579/test/Launchpad.t.sol b/accounts/safe7579/test/Launchpad.t.sol index e719cc8b..a595108e 100644 --- a/accounts/safe7579/test/Launchpad.t.sol +++ b/accounts/safe7579/test/Launchpad.t.sol @@ -6,40 +6,51 @@ import "forge-std/Test.sol"; import "src/SafeERC7579.sol"; import "src/SafeERC7579.sol"; -import "src/utils/SafeLaunchpad.sol"; +import "src/utils/Launchpad.sol"; import "@safe-global/safe-contracts/contracts/proxies/SafeProxyFactory.sol"; import "@safe-global/safe-contracts/contracts/Safe.sol"; +import "@rhinestone/modulekit/src/Mocks.sol"; +import "@rhinestone/modulekit/src/test/predeploy/EntryPoint.sol"; + +import { EntryPoint } from "@ERC4337/account-abstraction/contracts/core/EntryPoint.sol"; + +import { LibClone } from "solady/src/utils/LibClone.sol"; contract SafeLaunchPadTest is Test { - SafeSignerLaunchpad safeLaunchpad; SafeERC7579 safe7579; Safe singleton; Safe safeAccount; SafeProxyFactory safeProxyFactory; + Launchpad launchpad; - address entrypoint = address(this); + MockValidator defaultValidator; Account signer1 = makeAccount("signer1"); Account signer2 = makeAccount("signer2"); + IEntryPoint entrypoint; + function setUp() public { singleton = new Safe(); safeProxyFactory = new SafeProxyFactory(); - safeLaunchpad = new SafeSignerLaunchpad(entrypoint); - - bytes memory safeLaunchPadSetup; - // Safe.setup, - // ( - // owners, - // 2, - // address(safeLaunchpad), - // safeLaunchPadSetup, - // address(safe7579), - // address(0), - // 0, - // payable(address(0)) - // ) - // ); + launchpad = new Launchpad(); + safe7579 = new SafeERC7579(); + + entrypoint = etchEntrypoint(); + + defaultValidator = new MockValidator(); + + address[] memory validators = new address[](1); + validators[0] = address(defaultValidator); + bytes[] memory validatorsInitCode = new bytes[](1); + + bytes memory safeLaunchPadSetup = abi.encodeCall( + Launchpad.initSafe7579, + ( + address(safe7579), + abi.encode(validators, validatorsInitCode, new address[](0), new bytes[](0)) + ) + ); address[] memory owners = new address[](2); owners[0] = signer1.addr; @@ -50,7 +61,7 @@ contract SafeLaunchPadTest is Test { ( owners, 2, - address(safeLaunchpad), + address(launchpad), safeLaunchPadSetup, address(safe7579), address(0), @@ -60,31 +71,82 @@ contract SafeLaunchPadTest is Test { ); uint256 salt = 0; - SafeProxy safeProxy = - safeProxyFactory.createProxyWithNonce(address(singleton), initializer, salt); + // SafeProxy safeProxy = + // safeProxyFactory.createProxyWithNonce(address(singleton), initializer, salt); } - /** - * Genereates initcode that will be passed to safeProxyFactory - * @param safeLaunchPadSetup init code for safe launchpad setup() function - */ - function _safeProxyFactory_initcode(bytes memory safeLaunchPadSetup) - internal - returns (bytes memory initCode) - { - // initCode = abi.encodeCall( - // Safe.setup, - // ( - // owners, - // 2, - // address(safeLaunchpad), - // safeLaunchPadSetup, - // address(safe7579), - // address(0), - // 0, - // payable(address(0)) - // ) - // ); + function test_createAccount() public { + address[] memory validators = new address[](1); + validators[0] = address(defaultValidator); + bytes[] memory validatorsInitCode = new bytes[](1); + + bytes memory safeLaunchPadSetup = abi.encodeCall( + Launchpad.initSafe7579, + ( + address(safe7579), + abi.encode(validators, validatorsInitCode, new address[](0), new bytes[](0)) + ) + ); + + address[] memory owners = new address[](2); + owners[0] = signer1.addr; + owners[1] = signer2.addr; + // SETUP SAFE + bytes memory initializer = abi.encodeCall( + Safe.setup, + ( + owners, + 2, + address(launchpad), + safeLaunchPadSetup, + address(safe7579), + address(0), + 0, + payable(address(0)) + ) + ); + uint256 salt = 0; + + PackedUserOperation memory userOp = getDefaultUserOp(); + userOp.initCode = abi.encodePacked( + address(safeProxyFactory), + abi.encodeCall( + SafeProxyFactory.createProxyWithNonce, (address(singleton), initializer, salt) + ) + ); + + PackedUserOperation[] memory userOps = new PackedUserOperation[](1); + userOps[0] = userOp; + + entrypoint.handleOps(userOps, payable(address(0x69))); + } + + function getDefaultUserOp() internal returns (PackedUserOperation memory userOp) { + address account = address(0x8bDB7B3070D3cefA1586427ebAfd5FDD56aE96A7); + + console.log("accountPredict", _predictAddress(bytes32(0))); + vm.deal(account, 1 ether); + uint192 key = uint192(bytes24(bytes20(address(defaultValidator)))); + uint256 nonce = entrypoint.getNonce(address(account), key); + userOp = PackedUserOperation({ + sender: account, + nonce: nonce, + 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") + }); + } + + function _predictAddress(bytes32 salt) internal returns (address safeProxy) { + bytes memory deploymentData = abi.encodePacked( + safeProxyFactory.proxyCreationCode(), uint256(uint160(address(singleton))) + ); + bytes32 hash = LibClone.initCodeHash(address(singleton)); + safeProxy = LibClone.predictDeterministicAddress(hash, salt, address(safeProxyFactory)); } function test_foo() public { } From ccaa93c63704bcd0f47566fe3bb76d105b526932 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Fri, 8 Mar 2024 13:40:09 +0700 Subject: [PATCH 04/64] feat: predicting address for safe factory now works --- accounts/safe7579/test/Launchpad.t.sol | 43 ++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/accounts/safe7579/test/Launchpad.t.sol b/accounts/safe7579/test/Launchpad.t.sol index a595108e..60f65a30 100644 --- a/accounts/safe7579/test/Launchpad.t.sol +++ b/accounts/safe7579/test/Launchpad.t.sol @@ -107,7 +107,8 @@ contract SafeLaunchPadTest is Test { ); uint256 salt = 0; - PackedUserOperation memory userOp = getDefaultUserOp(); + address account = _predictAddress(bytes32(salt), initializer); + PackedUserOperation memory userOp = getDefaultUserOp(account); userOp.initCode = abi.encodePacked( address(safeProxyFactory), abi.encodeCall( @@ -115,16 +116,19 @@ contract SafeLaunchPadTest is Test { ) ); + console.log("accountPredict", _predictAddress(bytes32(0), initializer)); + PackedUserOperation[] memory userOps = new PackedUserOperation[](1); userOps[0] = userOp; entrypoint.handleOps(userOps, payable(address(0x69))); } - function getDefaultUserOp() internal returns (PackedUserOperation memory userOp) { - address account = address(0x8bDB7B3070D3cefA1586427ebAfd5FDD56aE96A7); - - console.log("accountPredict", _predictAddress(bytes32(0))); + function getDefaultUserOp(address account) + internal + returns (PackedUserOperation memory userOp) + { + // console.log("accountPredict", _predictAddress(bytes32(0))); vm.deal(account, 1 ether); uint192 key = uint192(bytes24(bytes20(address(defaultValidator)))); uint256 nonce = entrypoint.getNonce(address(account), key); @@ -141,12 +145,39 @@ contract SafeLaunchPadTest is Test { }); } - function _predictAddress(bytes32 salt) internal returns (address safeProxy) { + function _predictAddress( + bytes32 salt, + bytes memory initializer + ) + internal + returns (address safeProxy) + { bytes memory deploymentData = abi.encodePacked( safeProxyFactory.proxyCreationCode(), uint256(uint160(address(singleton))) ); bytes32 hash = LibClone.initCodeHash(address(singleton)); safeProxy = LibClone.predictDeterministicAddress(hash, salt, address(safeProxyFactory)); + salt = keccak256(abi.encodePacked(keccak256(initializer), salt)); + + safeProxy = address( + uint160( + uint256( + keccak256( + abi.encodePacked( + bytes1(0xff), + address(safeProxyFactory), + salt, + keccak256( + abi.encodePacked( + safeProxyFactory.proxyCreationCode(), + uint256(uint160(address(singleton))) + ) + ) + ) + ) + ) + ) + ); } function test_foo() public { } From 3e5f10c128508e303d327e44b5367f412edbbc1d Mon Sep 17 00:00:00 2001 From: zeroknots Date: Fri, 8 Mar 2024 14:16:01 +0700 Subject: [PATCH 05/64] refine setup --- accounts/safe7579/src/SafeERC7579.sol | 11 +++++++---- accounts/safe7579/test/Launchpad.t.sol | 10 +++------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index b5f25a2e..89e6769c 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -28,15 +28,14 @@ import { UserOperationLib } from "@ERC4337/account-abstraction/contracts/core/UserOperationLib.sol"; import { _packValidationData } from "@ERC4337/account-abstraction/contracts/core/Helpers.sol"; +import { IEntryPoint } from "@ERC4337/account-abstraction/contracts/interfaces/IEntryPoint.sol"; -import "forge-std/console2.sol"; /** * @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; @@ -155,7 +154,6 @@ contract SafeERC7579 is ISafeOp, IERC7579Account, AccessControl, IMSA, HookManag // pay prefund if (missingAccountFunds != 0) { - console2.log("missingAccountFunds", missingAccountFunds); _execute({ safe: userOp.getSender(), target: entryPoint(), @@ -245,6 +243,7 @@ contract SafeERC7579 is ISafeOp, IERC7579Account, AccessControl, IMSA, HookManag CallType callType = encodedMode.getCallType(); if (callType == CALLTYPE_BATCH) return true; else if (callType == CALLTYPE_SINGLE) return true; + else if (callType == CALLTYPE_DELEGATECALL) return true; else return false; } @@ -283,7 +282,6 @@ contract SafeERC7579 is ISafeOp, IERC7579Account, AccessControl, IMSA, HookManag * @inheritdoc IERC7579Account */ function accountId() external view override returns (string memory accountImplementationId) { - // TODO: concat safe version string memory safeVersion = ISafe(_msgSender()).VERSION(); return string(abi.encodePacked(safeVersion, "erc7579.v0.0.0")); } @@ -397,4 +395,9 @@ contract SafeERC7579 is ISafeOp, IERC7579Account, AccessControl, IMSA, HookManag emit Safe7579Initialized(msg.sender); } + + function getNonce(address safe, address validator) external view returns (uint256 nonce) { + uint192 key = uint192(bytes24(bytes20(address(validator)))); + nonce = IEntryPoint(entryPoint()).getNonce(safe, key); + } } diff --git a/accounts/safe7579/test/Launchpad.t.sol b/accounts/safe7579/test/Launchpad.t.sol index 60f65a30..c3e13e4b 100644 --- a/accounts/safe7579/test/Launchpad.t.sol +++ b/accounts/safe7579/test/Launchpad.t.sol @@ -108,6 +108,7 @@ contract SafeLaunchPadTest is Test { uint256 salt = 0; address account = _predictAddress(bytes32(salt), initializer); + vm.deal(account, 1 ether); PackedUserOperation memory userOp = getDefaultUserOp(account); userOp.initCode = abi.encodePacked( address(safeProxyFactory), @@ -116,8 +117,6 @@ contract SafeLaunchPadTest is Test { ) ); - console.log("accountPredict", _predictAddress(bytes32(0), initializer)); - PackedUserOperation[] memory userOps = new PackedUserOperation[](1); userOps[0] = userOp; @@ -126,15 +125,12 @@ contract SafeLaunchPadTest is Test { function getDefaultUserOp(address account) internal + view returns (PackedUserOperation memory userOp) { - // console.log("accountPredict", _predictAddress(bytes32(0))); - vm.deal(account, 1 ether); - uint192 key = uint192(bytes24(bytes20(address(defaultValidator)))); - uint256 nonce = entrypoint.getNonce(address(account), key); userOp = PackedUserOperation({ sender: account, - nonce: nonce, + nonce: safe7579.getNonce(address(account), address(defaultValidator)), initCode: "", callData: "", accountGasLimits: bytes32(abi.encodePacked(uint128(2e6), uint128(2e6))), From 0e534ffa7fd80017654f13c8f6f6cf65a6572b83 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Fri, 8 Mar 2024 15:03:49 +0700 Subject: [PATCH 06/64] =?UTF-8?q?=F0=9F=94=A5=20Tests=20passing=20again?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- accounts/safe7579/src/SafeERC7579.sol | 5 + accounts/safe7579/src/interfaces/ISafe.sol | 12 ++ accounts/safe7579/src/utils/Boostrap.sol | 69 --------- accounts/safe7579/src/utils/Launchpad.sol | 84 +++++++++- .../src/utils/SignatureValidatorConstants.sol | 15 -- accounts/safe7579/test/Base.t.sol | 143 ++++++++---------- accounts/safe7579/test/Base.t.sol.bak | 122 +++++++++++++++ .../{Launchpad.t.sol => Launchpad.t.sol.bak} | 0 accounts/safe7579/test/SafeERC7579.t.sol | 78 +++++++--- 9 files changed, 347 insertions(+), 181 deletions(-) delete mode 100644 accounts/safe7579/src/utils/Boostrap.sol delete mode 100644 accounts/safe7579/src/utils/SignatureValidatorConstants.sol create mode 100644 accounts/safe7579/test/Base.t.sol.bak rename accounts/safe7579/test/{Launchpad.t.sol => Launchpad.t.sol.bak} (100%) diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index 89e6769c..797d7650 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -396,6 +396,11 @@ contract SafeERC7579 is ISafeOp, IERC7579Account, AccessControl, IMSA, HookManag emit Safe7579Initialized(msg.sender); } + /** + * Safe7579 is using validator selection encoding in the userop nonce. + * to make it easier for SDKs / devs to integrate, this function can be + * called to get the next nonce for a specific validator + */ function getNonce(address safe, address validator) external view returns (uint256 nonce) { uint192 key = uint192(bytes24(bytes20(address(validator)))); nonce = IEntryPoint(entryPoint()).getNonce(safe, key); diff --git a/accounts/safe7579/src/interfaces/ISafe.sol b/accounts/safe7579/src/interfaces/ISafe.sol index 25ee4efb..be60fa30 100644 --- a/accounts/safe7579/src/interfaces/ISafe.sol +++ b/accounts/safe7579/src/interfaces/ISafe.sol @@ -2,6 +2,18 @@ pragma solidity ^0.8.0; interface ISafe { + function setup( + address[] calldata _owners, + uint256 _threshold, + address to, + bytes calldata data, + address fallbackHandler, + address paymentToken, + uint256 payment, + address payable paymentReceiver + ) + external; + /** * @dev Allows a Module to execute a Safe transaction without any further confirmations. * @param to Destination address of module transaction. diff --git a/accounts/safe7579/src/utils/Boostrap.sol b/accounts/safe7579/src/utils/Boostrap.sol deleted file mode 100644 index 46981a1b..00000000 --- a/accounts/safe7579/src/utils/Boostrap.sol +++ /dev/null @@ -1,69 +0,0 @@ -// 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/src/utils/Launchpad.sol b/accounts/safe7579/src/utils/Launchpad.sol index 9323fa82..b272d990 100644 --- a/accounts/safe7579/src/utils/Launchpad.sol +++ b/accounts/safe7579/src/utils/Launchpad.sol @@ -1,8 +1,88 @@ -import "../SafeERC7579.sol"; +// SPDX-License-Identifier: LGPL-3.0-only +pragma solidity ^0.8.0; + +import { ISafe, SafeERC7579 } from "../SafeERC7579.sol"; + +/** + * Helper contract that gets delegatecalled byt SafeProxy.setup() to setup safe7579 as a module + * (safe module) + * as well as initializing Safe7579 for the SafeProxy + */ +contract Safe7579Launchpad { + address immutable safe7579Singleton; + + constructor(address _safe7579Singleton) { + safe7579Singleton = _safe7579Singleton; + } -contract Launchpad { function initSafe7579(address safe7579, bytes calldata safe7579InitCode) public { ISafe(address(this)).enableModule(safe7579); SafeERC7579(payable(safe7579)).initializeAccount(safe7579InitCode); } + + function predictSafeAddress( + address singleton, + address safeProxyFactory, + bytes memory creationCode, + bytes32 salt, + bytes memory initializer + ) + external + pure + returns (address safeProxy) + { + salt = keccak256(abi.encodePacked(keccak256(initializer), salt)); + + safeProxy = address( + uint160( + uint256( + keccak256( + abi.encodePacked( + bytes1(0xff), + address(safeProxyFactory), + salt, + keccak256( + abi.encodePacked(creationCode, uint256(uint160(address(singleton)))) + ) + ) + ) + ) + ) + ); + } + + function getInitCode( + address[] memory signers, + uint256 threshold, + address[] calldata validators, + bytes[] calldata validatorsInitCode, + address[] calldata executors, + bytes[] calldata executorsInitCode + ) + external + view + returns (bytes memory initCode) + { + bytes memory safeLaunchPadSetup = abi.encodeCall( + this.initSafe7579, + ( + address(safe7579Singleton), + abi.encode(validators, validatorsInitCode, executors, executorsInitCode) + ) + ); + // SETUP SAFE + initCode = abi.encodeCall( + ISafe.setup, + ( + signers, + threshold, + address(this), + safeLaunchPadSetup, + safe7579Singleton, + address(0), + 0, + payable(address(0)) + ) + ); + } } diff --git a/accounts/safe7579/src/utils/SignatureValidatorConstants.sol b/accounts/safe7579/src/utils/SignatureValidatorConstants.sol deleted file mode 100644 index 06d5f1d2..00000000 --- a/accounts/safe7579/src/utils/SignatureValidatorConstants.sol +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only -/* solhint-disable one-contract-per-file */ -pragma solidity >=0.7.0 <0.9.0; - -/** - * @title SignatureValidatorConstants - * @dev This contract defines the constants used for EIP-1271 signature validation. - */ -contract SignatureValidatorConstants { - // bytes4(keccak256("isValidSignature(bytes32,bytes)") - bytes4 internal constant EIP1271_MAGIC_VALUE = 0x1626ba7e; - - // bytes4(keccak256("isValidSignature(bytes,bytes)") - bytes4 internal constant LEGACY_EIP1271_MAGIC_VALUE = 0x20c13b0b; -} diff --git a/accounts/safe7579/test/Base.t.sol b/accounts/safe7579/test/Base.t.sol index 82cd0099..7e886b48 100644 --- a/accounts/safe7579/test/Base.t.sol +++ b/accounts/safe7579/test/Base.t.sol @@ -10,106 +10,95 @@ 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 { SafeProxyFactory } from + "@safe-global/safe-contracts/contracts/proxies/SafeProxyFactory.sol"; import { LibClone } from "solady/src/utils/LibClone.sol"; +import "src/utils/Launchpad.sol"; +import { Solarray } from "solarray/Solarray.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); + SafeERC7579 safe7579; + Safe singleton; + Safe safe; + SafeProxyFactory safeProxyFactory; + Safe7579Launchpad launchpad; - MockValidator internal defaultValidator; - MockExecutor internal defaultExecutor; - Bootstrap internal bootstrap; + MockValidator defaultValidator; + MockExecutor defaultExecutor; - MockTarget internal target; + Account signer1 = makeAccount("signer1"); + Account signer2 = makeAccount("signer2"); - Account internal signer1; - Account internal signer2; + IEntryPoint entrypoint; + bytes userOpInitCode; 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"); + entrypoint = etchEntrypoint(); + singleton = new Safe(); + safeProxyFactory = new SafeProxyFactory(); + safe7579 = new SafeERC7579(); + launchpad = new Safe7579Launchpad(address(safe7579)); // Set up Modules - defaultExecutor = new MockExecutor(); defaultValidator = new MockValidator(); + defaultExecutor = new MockExecutor(); - // 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; - - // TODO: think about launchpad impl see: passkey for safe. - 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 - }); + bytes32 salt; - vm.startPrank(address(clone)); - clone.enableModule(address(erc7579Mod)); - erc7579Mod.initializeAccount( - abi.encode( - address(bootstrap), - abi.encodeCall( - Bootstrap.singleInitMSA, (_defaultValidator, "", address(defaultExecutor), "") - ) + bytes memory initializer = launchpad.getInitCode({ + signers: Solarray.addresses(signer1.addr, signer2.addr), + threshold: 2, + validators: Solarray.addresses(address(defaultValidator)), + validatorsInitCode: Solarray.bytess(""), + executors: Solarray.addresses(address(defaultExecutor)), + executorsInitCode: Solarray.bytess("") + }); + // computer counterfactual address for SafeProxy + safe = Safe( + payable( + launchpad.predictSafeAddress({ + singleton: address(singleton), + safeProxyFactory: address(safeProxyFactory), + creationCode: safeProxyFactory.proxyCreationCode(), + salt: salt, + initializer: initializer + }) ) ); - vm.stopPrank(); + userOpInitCode = initCode(initializer, salt); } - 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 initCode( + bytes memory initializer, + bytes32 salt + ) + internal + view + returns (bytes memory _initCode) + { + _initCode = abi.encodePacked( + address(safeProxyFactory), + abi.encodeCall( + SafeProxyFactory.createProxyWithNonce, + (address(singleton), initializer, uint256(salt)) + ) + ); } - function getDefaultUserOp() internal pure returns (PackedUserOperation memory userOp) { + function getDefaultUserOp( + address account, + address validator + ) + internal + view + returns (PackedUserOperation memory userOp) + { userOp = PackedUserOperation({ - sender: address(0), - nonce: 0, + sender: account, + nonce: safe7579.getNonce(account, validator), initCode: "", callData: "", accountGasLimits: bytes32(abi.encodePacked(uint128(2e6), uint128(2e6))), diff --git a/accounts/safe7579/test/Base.t.sol.bak b/accounts/safe7579/test/Base.t.sol.bak new file mode 100644 index 00000000..82cd0099 --- /dev/null +++ b/accounts/safe7579/test/Base.t.sol.bak @@ -0,0 +1,122 @@ +// 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; + + // TODO: think about launchpad impl see: passkey for safe. + 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/Launchpad.t.sol b/accounts/safe7579/test/Launchpad.t.sol.bak similarity index 100% rename from accounts/safe7579/test/Launchpad.t.sol rename to accounts/safe7579/test/Launchpad.t.sol.bak diff --git a/accounts/safe7579/test/SafeERC7579.t.sol b/accounts/safe7579/test/SafeERC7579.t.sol index fe8c6baa..335f8ecf 100644 --- a/accounts/safe7579/test/SafeERC7579.t.sol +++ b/accounts/safe7579/test/SafeERC7579.t.sol @@ -6,14 +6,30 @@ import "erc7579/lib/ModeLib.sol"; import "erc7579/lib/ExecutionLib.sol"; import { TestBaseUtil, MockTarget, MockFallback } from "./Base.t.sol"; -contract MSATest is TestBaseUtil { +import "forge-std/console2.sol"; + +contract Safe7579Test is TestBaseUtil { + MockTarget target; + function setUp() public override { super.setUp(); + target = new MockTarget(); + deal(address(safe), 1 ether); + } + + modifier alreadyInitialized(bool initNow) { + if (initNow) { + test_initializeAccount(); + } + _; } - function test_execSingle() public { + function test_initializeAccount() public { + PackedUserOperation memory userOp = + getDefaultUserOp(address(safe), address(defaultValidator)); + // Create calldata for the account to execute - bytes memory setValueOnTarget = abi.encodeCall(MockTarget.set, 1337); + bytes memory setValueOnTarget = abi.encodeCall(MockTarget.set, 777); // Encode the call into the calldata for the userOp bytes memory userOpCalldata = abi.encodeCall( @@ -23,15 +39,39 @@ contract MSATest is TestBaseUtil { ExecutionLib.encodeSingle(address(target), uint256(0), setValueOnTarget) ) ); + userOp.initCode = userOpInitCode; + userOp.callData = userOpCalldata; + // Create userOps array + PackedUserOperation[] memory userOps = new PackedUserOperation[](1); + userOps[0] = userOp; - // Get the account, initcode and nonce - uint256 nonce = getNonce(address(safe), address(defaultValidator)); + // Send the userOp to the entrypoint + entrypoint.handleOps(userOps, payable(address(0x69))); - // Create the userOp and add the data - PackedUserOperation memory userOp = getDefaultUserOp(); - userOp.sender = address(safe); - userOp.nonce = nonce; - userOp.initCode = ""; + // Assert that the value was set ie that execution was successful + assertTrue(target.value() == 777); + userOpInitCode = ""; + } + + function test_execSingle(bool withInitializedAccount) + public + alreadyInitialized(withInitializedAccount) + { + // 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) + ) + ); + + PackedUserOperation memory userOp = + getDefaultUserOp(address(safe), address(defaultValidator)); + userOp.initCode = userOpInitCode; userOp.callData = userOpCalldata; // Create userOps array @@ -45,7 +85,10 @@ contract MSATest is TestBaseUtil { assertTrue(target.value() == 1337); } - function test_execBatch() public { + function test_execBatch(bool withInitializedAccount) + public + alreadyInitialized(withInitializedAccount) + { // Create calldata for the account to execute bytes memory setValueOnTarget = abi.encodeCall(MockTarget.set, 1337); address target2 = address(0x420); @@ -62,14 +105,10 @@ contract MSATest is TestBaseUtil { (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 = ""; + PackedUserOperation memory userOp = + getDefaultUserOp(address(safe), address(defaultValidator)); + userOp.initCode = userOpInitCode; userOp.callData = userOpCalldata; // Create userOps array @@ -84,6 +123,7 @@ contract MSATest is TestBaseUtil { } function test_execViaExecutor() public { + test_initializeAccount(); defaultExecutor.executeViaAccount( IERC7579Account(address(safe)), address(target), @@ -93,6 +133,7 @@ contract MSATest is TestBaseUtil { } function test_execBatchFromExecutor() public { + test_initializeAccount(); bytes memory setValueOnTarget = abi.encodeCall(MockTarget.set, 1338); Execution[] memory executions = new Execution[](2); executions[0] = Execution({ target: address(target), value: 0, callData: setValueOnTarget }); @@ -107,6 +148,7 @@ contract MSATest is TestBaseUtil { } function test_fallback() public { + test_initializeAccount(); MockFallback _fallback = new MockFallback(); vm.prank(address(safe)); IERC7579Account(address(safe)).installModule(3, address(_fallback), ""); From 36bd03e2fa2237aad4575fafa457940b0be8dcc3 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Fri, 8 Mar 2024 15:14:55 +0700 Subject: [PATCH 07/64] adding ERC1271 --- accounts/safe7579/script/Deploy.s.sol | 1 + accounts/safe7579/src/SafeERC7579.sol | 15 +- accounts/safe7579/src/utils/Launchpad.sol | 8 +- accounts/safe7579/test/Base.t.sol.bak | 122 -------------- accounts/safe7579/test/Launchpad.t.sol.bak | 180 --------------------- 5 files changed, 19 insertions(+), 307 deletions(-) create mode 100644 accounts/safe7579/script/Deploy.s.sol delete mode 100644 accounts/safe7579/test/Base.t.sol.bak delete mode 100644 accounts/safe7579/test/Launchpad.t.sol.bak diff --git a/accounts/safe7579/script/Deploy.s.sol b/accounts/safe7579/script/Deploy.s.sol new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/accounts/safe7579/script/Deploy.s.sol @@ -0,0 +1 @@ + diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index 797d7650..1405d572 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -192,7 +192,20 @@ contract SafeERC7579 is ISafeOp, IERC7579Account, AccessControl, IMSA, HookManag /** * @inheritdoc IERC7579Account */ - function isValidSignature(bytes32 hash, bytes calldata data) external view returns (bytes4) { } + function isValidSignature( + bytes32 hash, + bytes calldata data + ) + external + view + returns (bytes4 magicValue) + { + address validationModule = address(bytes20(data[:20])); + + if (!_isValidatorInstalled(validationModule)) return 0xFFFFFFFF; + magicValue = + IValidator(validationModule).isValidSignatureWithSender(msg.sender, hash, data[20:]); + } /** * @inheritdoc IERC7579Account diff --git a/accounts/safe7579/src/utils/Launchpad.sol b/accounts/safe7579/src/utils/Launchpad.sol index b272d990..1abc5030 100644 --- a/accounts/safe7579/src/utils/Launchpad.sol +++ b/accounts/safe7579/src/utils/Launchpad.sol @@ -9,10 +9,10 @@ import { ISafe, SafeERC7579 } from "../SafeERC7579.sol"; * as well as initializing Safe7579 for the SafeProxy */ contract Safe7579Launchpad { - address immutable safe7579Singleton; + address immutable SAFE7579Singleton; constructor(address _safe7579Singleton) { - safe7579Singleton = _safe7579Singleton; + SAFE7579Singleton = _safe7579Singleton; } function initSafe7579(address safe7579, bytes calldata safe7579InitCode) public { @@ -66,7 +66,7 @@ contract Safe7579Launchpad { bytes memory safeLaunchPadSetup = abi.encodeCall( this.initSafe7579, ( - address(safe7579Singleton), + address(SAFE7579Singleton), abi.encode(validators, validatorsInitCode, executors, executorsInitCode) ) ); @@ -78,7 +78,7 @@ contract Safe7579Launchpad { threshold, address(this), safeLaunchPadSetup, - safe7579Singleton, + SAFE7579Singleton, address(0), 0, payable(address(0)) diff --git a/accounts/safe7579/test/Base.t.sol.bak b/accounts/safe7579/test/Base.t.sol.bak deleted file mode 100644 index 82cd0099..00000000 --- a/accounts/safe7579/test/Base.t.sol.bak +++ /dev/null @@ -1,122 +0,0 @@ -// 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; - - // TODO: think about launchpad impl see: passkey for safe. - 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/Launchpad.t.sol.bak b/accounts/safe7579/test/Launchpad.t.sol.bak deleted file mode 100644 index c3e13e4b..00000000 --- a/accounts/safe7579/test/Launchpad.t.sol.bak +++ /dev/null @@ -1,180 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only - -pragma solidity ^0.8.0; - -import "forge-std/Test.sol"; - -import "src/SafeERC7579.sol"; -import "src/SafeERC7579.sol"; -import "src/utils/Launchpad.sol"; -import "@safe-global/safe-contracts/contracts/proxies/SafeProxyFactory.sol"; -import "@safe-global/safe-contracts/contracts/Safe.sol"; -import "@rhinestone/modulekit/src/Mocks.sol"; -import "@rhinestone/modulekit/src/test/predeploy/EntryPoint.sol"; - -import { EntryPoint } from "@ERC4337/account-abstraction/contracts/core/EntryPoint.sol"; - -import { LibClone } from "solady/src/utils/LibClone.sol"; - -contract SafeLaunchPadTest is Test { - SafeERC7579 safe7579; - Safe singleton; - Safe safeAccount; - SafeProxyFactory safeProxyFactory; - Launchpad launchpad; - - MockValidator defaultValidator; - - Account signer1 = makeAccount("signer1"); - Account signer2 = makeAccount("signer2"); - - IEntryPoint entrypoint; - - function setUp() public { - singleton = new Safe(); - safeProxyFactory = new SafeProxyFactory(); - launchpad = new Launchpad(); - safe7579 = new SafeERC7579(); - - entrypoint = etchEntrypoint(); - - defaultValidator = new MockValidator(); - - address[] memory validators = new address[](1); - validators[0] = address(defaultValidator); - bytes[] memory validatorsInitCode = new bytes[](1); - - bytes memory safeLaunchPadSetup = abi.encodeCall( - Launchpad.initSafe7579, - ( - address(safe7579), - abi.encode(validators, validatorsInitCode, new address[](0), new bytes[](0)) - ) - ); - - address[] memory owners = new address[](2); - owners[0] = signer1.addr; - owners[1] = signer2.addr; - // SETUP SAFE - bytes memory initializer = abi.encodeCall( - Safe.setup, - ( - owners, - 2, - address(launchpad), - safeLaunchPadSetup, - address(safe7579), - address(0), - 0, - payable(address(0)) - ) - ); - uint256 salt = 0; - - // SafeProxy safeProxy = - // safeProxyFactory.createProxyWithNonce(address(singleton), initializer, salt); - } - - function test_createAccount() public { - address[] memory validators = new address[](1); - validators[0] = address(defaultValidator); - bytes[] memory validatorsInitCode = new bytes[](1); - - bytes memory safeLaunchPadSetup = abi.encodeCall( - Launchpad.initSafe7579, - ( - address(safe7579), - abi.encode(validators, validatorsInitCode, new address[](0), new bytes[](0)) - ) - ); - - address[] memory owners = new address[](2); - owners[0] = signer1.addr; - owners[1] = signer2.addr; - // SETUP SAFE - bytes memory initializer = abi.encodeCall( - Safe.setup, - ( - owners, - 2, - address(launchpad), - safeLaunchPadSetup, - address(safe7579), - address(0), - 0, - payable(address(0)) - ) - ); - uint256 salt = 0; - - address account = _predictAddress(bytes32(salt), initializer); - vm.deal(account, 1 ether); - PackedUserOperation memory userOp = getDefaultUserOp(account); - userOp.initCode = abi.encodePacked( - address(safeProxyFactory), - abi.encodeCall( - SafeProxyFactory.createProxyWithNonce, (address(singleton), initializer, salt) - ) - ); - - PackedUserOperation[] memory userOps = new PackedUserOperation[](1); - userOps[0] = userOp; - - entrypoint.handleOps(userOps, payable(address(0x69))); - } - - function getDefaultUserOp(address account) - internal - view - returns (PackedUserOperation memory userOp) - { - userOp = PackedUserOperation({ - sender: account, - nonce: safe7579.getNonce(address(account), address(defaultValidator)), - 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") - }); - } - - function _predictAddress( - bytes32 salt, - bytes memory initializer - ) - internal - returns (address safeProxy) - { - bytes memory deploymentData = abi.encodePacked( - safeProxyFactory.proxyCreationCode(), uint256(uint160(address(singleton))) - ); - bytes32 hash = LibClone.initCodeHash(address(singleton)); - safeProxy = LibClone.predictDeterministicAddress(hash, salt, address(safeProxyFactory)); - salt = keccak256(abi.encodePacked(keccak256(initializer), salt)); - - safeProxy = address( - uint160( - uint256( - keccak256( - abi.encodePacked( - bytes1(0xff), - address(safeProxyFactory), - salt, - keccak256( - abi.encodePacked( - safeProxyFactory.proxyCreationCode(), - uint256(uint160(address(singleton))) - ) - ) - ) - ) - ) - ) - ); - } - - function test_foo() public { } -} From f1ad2731fbf7a9e59795732c1b862332acc79724 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Fri, 8 Mar 2024 16:01:43 +0700 Subject: [PATCH 08/64] =?UTF-8?q?=E2=9C=A8=20Safe7579=20now=20supports=20m?= =?UTF-8?q?sg.sig=20specific=20fallbacks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- accounts/safe7579/src/SafeERC7579.sol | 18 ++- accounts/safe7579/src/core/ModuleManager.sol | 134 +++++++++++++++---- 2 files changed, 117 insertions(+), 35 deletions(-) diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index 1405d572..fc9742e0 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -277,18 +277,24 @@ contract SafeERC7579 is ISafeOp, IERC7579Account, AccessControl, IMSA, HookManag function isModuleInstalled( uint256 moduleType, address module, - bytes calldata /*additionalContext*/ + bytes calldata additionalContext ) external view override returns (bool) { - if (moduleType == MODULE_TYPE_VALIDATOR) return _isValidatorInstalled(module); - else if (moduleType == MODULE_TYPE_EXECUTOR) return _isExecutorInstalled(module); - else if (moduleType == MODULE_TYPE_FALLBACK) return _isFallbackHandlerInstalled(module); - else if (moduleType == MODULE_TYPE_HOOK) return _isHookInstalled(module); - else return false; + if (moduleType == MODULE_TYPE_VALIDATOR) { + return _isValidatorInstalled(module); + } else if (moduleType == MODULE_TYPE_EXECUTOR) { + return _isExecutorInstalled(module); + } else if (moduleType == MODULE_TYPE_FALLBACK) { + return _isFallbackHandlerInstalled(module, additionalContext); + } else if (moduleType == MODULE_TYPE_HOOK) { + return _isHookInstalled(module); + } else { + return false; + } } /** diff --git a/accounts/safe7579/src/core/ModuleManager.sol b/accounts/safe7579/src/core/ModuleManager.sol index 1d242bc4..4456847c 100644 --- a/accounts/safe7579/src/core/ModuleManager.sol +++ b/accounts/safe7579/src/core/ModuleManager.sol @@ -7,12 +7,19 @@ import { IModule } from "erc7579/interfaces/IERC7579Module.sol"; import { ExecutionHelper } from "./ExecutionHelper.sol"; import { Receiver } from "erc7579/core/Receiver.sol"; import { AccessControl } from "./AccessControl.sol"; +import { CallType, CALLTYPE_SINGLE, CALLTYPE_DELEGATECALL } from "erc7579/lib/ModeLib.sol"; + +CallType constant CALLTYPE_STATIC = CallType.wrap(0xFE); + +struct FallbackHandler { + address handler; + CallType calltype; +} struct ModuleManagerStorage { // linked list of executors. List is initialized by initializeAccount() SentinelListLib.SentinelList _executors; - // single fallback handler for all fallbacks - address fallbackHandler; + mapping(bytes4 selector => FallbackHandler fallbackHandler) _fallbacks; } /** @@ -29,7 +36,7 @@ abstract contract ModuleManager is AccessControl, Receiver, ExecutionHelper { error CannotRemoveLastValidator(); error InitializerError(); error ValidatorStorageHelperError(); - error NoFallbackHandler(); + error NoFallbackHandler(bytes4 msgSig); mapping(address smartAccount => ModuleManagerStorage moduleManagerStorage) internal $moduleManager; @@ -166,10 +173,19 @@ abstract contract ModuleManager is AccessControl, Receiver, ExecutionHelper { ///////////////////////////////////////////////////// // 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 + function _installFallbackHandler(address handler, bytes calldata params) internal virtual { + (bytes4 functionSig, CallType calltype, bytes memory initData) = + abi.decode(params, (bytes4, CallType, bytes)); + if (_isFallbackHandlerInstalled(functionSig)) revert(); + + FallbackHandler storage $fallbacks = $moduleManager[msg.sender]._fallbacks[functionSig]; + $fallbacks.calltype = calltype; + $fallbacks.handler = handler; + + // + // ModuleManagerStorage storage $mms = $moduleManager[msg.sender]; + // $mms.fallbackHandler = handler; + // // Initialize Fallback Module via Safe _execute({ safe: msg.sender, target: handler, @@ -178,9 +194,16 @@ abstract contract ModuleManager is AccessControl, Receiver, ExecutionHelper { }); } + function _isFallbackHandlerInstalled(bytes4 functionSig) internal view virtual returns (bool) { + FallbackHandler storage $fallback = $moduleManager[msg.sender]._fallbacks[functionSig]; + return $fallback.handler != address(0); + } + function _uninstallFallbackHandler(address handler, bytes calldata initData) internal virtual { + (bytes4 functionSig) = abi.decode(initData, (bytes4)); + ModuleManagerStorage storage $mms = $moduleManager[msg.sender]; - $mms.fallbackHandler = address(0); + $mms._fallbacks[functionSig].handler = address(0); // De-Initialize Fallback Module via Safe _execute({ safe: msg.sender, @@ -190,35 +213,88 @@ abstract contract ModuleManager is AccessControl, Receiver, ExecutionHelper { }); } - 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 _isFallbackHandlerInstalled( + address _handler, + bytes calldata additionalContext + ) + internal + view + virtual + returns (bool) + { + bytes4 functionSig = abi.decode(additionalContext, (bytes4)); - function getActiveFallbackHandler() external view virtual returns (address) { - return _getFallbackHandler(); + FallbackHandler storage $fallback = $moduleManager[msg.sender]._fallbacks[functionSig]; + return $fallback.handler == _handler; } // FALLBACK // solhint-disable-next-line no-complex-fallback fallback() external payable override(Receiver) receiverFallback { - address handler = _getFallbackHandler(); - if (handler == address(0)) revert NoFallbackHandler(); + FallbackHandler storage $fallbackHandler = $moduleManager[msg.sender]._fallbacks[msg.sig]; + address handler = $fallbackHandler.handler; + CallType calltype = $fallbackHandler.calltype; + if (handler == address(0)) revert NoFallbackHandler(msg.sig); - bytes memory retData = _executeReturnData({ - safe: msg.sender, - target: handler, - value: msg.value, - callData: abi.encodePacked(msg.data, _msgSender()) // ERC2771 - }); + if (calltype == CALLTYPE_STATIC) { + assembly { + 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 := + staticcall(gas(), handler, calldataPtr, add(calldatasize(), 20), 0, 0) + + let returnDataPtr := allocate(returndatasize()) + returndatacopy(returnDataPtr, 0, returndatasize()) + if iszero(success) { revert(returnDataPtr, returndatasize()) } + return(returnDataPtr, returndatasize()) + } + } + if (calltype == CALLTYPE_SINGLE) { + assembly { + 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-disable-next-line no-inline-assembly - assembly { - return(add(retData, 0x20), mload(retData)) + if (calltype == CALLTYPE_DELEGATECALL) { + assembly { + calldatacopy(0, 0, calldatasize()) + let result := delegatecall(gas(), handler, 0, calldatasize(), 0, 0) + returndatacopy(0, 0, returndatasize()) + switch result + case 0 { revert(0, returndatasize()) } + default { return(0, returndatasize()) } + } } } } From 0774d2bf46e0094a7056dd0e2f2777616269f7c0 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Thu, 14 Mar 2024 10:42:05 +0700 Subject: [PATCH 09/64] =?UTF-8?q?=E2=9C=A8=20Safe7579=20now=20supports=20c?= =?UTF-8?q?omplex=20fallbacks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../safe7579/src/core/ExecutionHelper.sol | 26 +++++++ accounts/safe7579/src/core/ModuleManager.sol | 71 ++++--------------- accounts/safe7579/test/SafeERC7579.t.sol | 20 ++++-- accounts/safe7579/test/mocks/MockFallback.sol | 11 ++- 4 files changed, 62 insertions(+), 66 deletions(-) diff --git a/accounts/safe7579/src/core/ExecutionHelper.sol b/accounts/safe7579/src/core/ExecutionHelper.sol index 298d4d80..cc50f31d 100644 --- a/accounts/safe7579/src/core/ExecutionHelper.sol +++ b/accounts/safe7579/src/core/ExecutionHelper.sol @@ -112,4 +112,30 @@ abstract contract ExecutionHelper { _executeReturnData(safe, execution.target, execution.value, execution.callData); } } + + /** + * Execute staticcall 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 _executeStaticReturnData( + address safe, + address target, + uint256 value, + bytes memory callData + ) + internal + view + returns (bytes memory returnData) + { + bool success; + (success, returnData) = safe.staticcall( + abi.encodeCall(ISafe.execTransactionFromModuleReturnData, (target, value, callData, 0)) + ); + if (!success) revert ExecutionFailed(); + } } diff --git a/accounts/safe7579/src/core/ModuleManager.sol b/accounts/safe7579/src/core/ModuleManager.sol index 4456847c..1ea3f200 100644 --- a/accounts/safe7579/src/core/ModuleManager.sol +++ b/accounts/safe7579/src/core/ModuleManager.sol @@ -37,6 +37,7 @@ abstract contract ModuleManager is AccessControl, Receiver, ExecutionHelper { error InitializerError(); error ValidatorStorageHelperError(); error NoFallbackHandler(bytes4 msgSig); + error FallbackInstalled(bytes4 msgSig); mapping(address smartAccount => ModuleManagerStorage moduleManagerStorage) internal $moduleManager; @@ -176,16 +177,12 @@ abstract contract ModuleManager is AccessControl, Receiver, ExecutionHelper { function _installFallbackHandler(address handler, bytes calldata params) internal virtual { (bytes4 functionSig, CallType calltype, bytes memory initData) = abi.decode(params, (bytes4, CallType, bytes)); - if (_isFallbackHandlerInstalled(functionSig)) revert(); + if (_isFallbackHandlerInstalled(functionSig)) revert FallbackInstalled(functionSig); FallbackHandler storage $fallbacks = $moduleManager[msg.sender]._fallbacks[functionSig]; $fallbacks.calltype = calltype; $fallbacks.handler = handler; - // - // ModuleManagerStorage storage $mms = $moduleManager[msg.sender]; - // $mms.fallbackHandler = handler; - // // Initialize Fallback Module via Safe _execute({ safe: msg.sender, target: handler, @@ -230,71 +227,27 @@ abstract contract ModuleManager is AccessControl, Receiver, ExecutionHelper { // FALLBACK // solhint-disable-next-line no-complex-fallback - fallback() external payable override(Receiver) receiverFallback { + fallback(bytes calldata callData) + external + payable + override(Receiver) + receiverFallback + returns (bytes memory fallbackRet) + { FallbackHandler storage $fallbackHandler = $moduleManager[msg.sender]._fallbacks[msg.sig]; address handler = $fallbackHandler.handler; CallType calltype = $fallbackHandler.calltype; if (handler == address(0)) revert NoFallbackHandler(msg.sig); if (calltype == CALLTYPE_STATIC) { - assembly { - 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 := - staticcall(gas(), handler, calldataPtr, add(calldatasize(), 20), 0, 0) - - let returnDataPtr := allocate(returndatasize()) - returndatacopy(returnDataPtr, 0, returndatasize()) - if iszero(success) { revert(returnDataPtr, returndatasize()) } - return(returnDataPtr, returndatasize()) - } + return _executeStaticReturnData(msg.sender, handler, 0, callData); } if (calltype == CALLTYPE_SINGLE) { - assembly { - 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()) - } + return _executeReturnData(msg.sender, handler, 0, callData); } if (calltype == CALLTYPE_DELEGATECALL) { - assembly { - calldatacopy(0, 0, calldatasize()) - let result := delegatecall(gas(), handler, 0, calldatasize(), 0, 0) - returndatacopy(0, 0, returndatasize()) - switch result - case 0 { revert(0, returndatasize()) } - default { return(0, returndatasize()) } - } + return _executeDelegateCallReturnData(msg.sender, handler, callData); } } } diff --git a/accounts/safe7579/test/SafeERC7579.t.sol b/accounts/safe7579/test/SafeERC7579.t.sol index 335f8ecf..21d1e2a4 100644 --- a/accounts/safe7579/test/SafeERC7579.t.sol +++ b/accounts/safe7579/test/SafeERC7579.t.sol @@ -151,12 +151,24 @@ contract Safe7579Test is TestBaseUtil { test_initializeAccount(); 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); + IERC7579Account(address(safe)).installModule( + 3, address(_fallback), abi.encode(MockFallback.target.selector, CALLTYPE_SINGLE, "") + ); + (uint256 ret, address msgSender) = MockFallback(address(safe)).target(1337); assertEq(ret, 1337); - assertEq(erc2771Sender, address(this)); assertEq(msgSender, address(safe)); + + vm.prank(address(safe)); + IERC7579Account(address(safe)).installModule( + 3, + address(_fallback), + abi.encode(MockFallback.target2.selector, CALLTYPE_DELEGATECALL, "") + ); + (uint256 _ret, address _this, address _msgSender) = + MockFallback(address(safe)).target2(1337); + + assertEq(_ret, 1337); + assertEq(_this, address(safe)); } } diff --git a/accounts/safe7579/test/mocks/MockFallback.sol b/accounts/safe7579/test/mocks/MockFallback.sol index acb84d76..20e4c29f 100644 --- a/accounts/safe7579/test/mocks/MockFallback.sol +++ b/accounts/safe7579/test/mocks/MockFallback.sol @@ -5,12 +5,17 @@ import { HandlerContext } from "@safe-global/safe-contracts/contracts/handler/Ha import { MockFallback as MockFallbackBase } from "@rhinestone/modulekit/src/mocks/MockFallback.sol"; contract MockFallback is MockFallbackBase, HandlerContext { - function target(uint256 value) + function target(uint256 value) external returns (uint256 _value, address msgSender) { + _value = value; + msgSender = msg.sender; + } + + function target2(uint256 value) external - returns (uint256 _value, address erc2771Sender, address msgSender) + returns (uint256 _value, address _this, address msgSender) { _value = value; - erc2771Sender = _msgSender(); msgSender = msg.sender; + _this = address(this); } } From 5c10bc70b6a174268149206633f046feedfc0d2f Mon Sep 17 00:00:00 2001 From: zeroknots Date: Thu, 14 Mar 2024 12:39:19 +0700 Subject: [PATCH 10/64] =?UTF-8?q?=F0=9F=94=A5=20Changed=20static/call=20in?= =?UTF-8?q?=20safe7579=20to=20use=20direct=20call=20to=20handler?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- accounts/safe7579/README.md | 66 ------------------ accounts/safe7579/notes.txt | 0 accounts/safe7579/src/core/ModuleManager.sol | 68 ++++++++++++++++++- accounts/safe7579/test/SafeERC7579.t.sol | 21 +++++- accounts/safe7579/test/mocks/MockFallback.sol | 8 ++- 5 files changed, 92 insertions(+), 71 deletions(-) delete mode 100644 accounts/safe7579/README.md create mode 100644 accounts/safe7579/notes.txt diff --git a/accounts/safe7579/README.md b/accounts/safe7579/README.md deleted file mode 100644 index 9265b455..00000000 --- a/accounts/safe7579/README.md +++ /dev/null @@ -1,66 +0,0 @@ -## Foundry - -**Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.** - -Foundry consists of: - -- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools). -- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data. -- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network. -- **Chisel**: Fast, utilitarian, and verbose solidity REPL. - -## Documentation - -https://book.getfoundry.sh/ - -## Usage - -### Build - -```shell -$ forge build -``` - -### Test - -```shell -$ forge test -``` - -### Format - -```shell -$ forge fmt -``` - -### Gas Snapshots - -```shell -$ forge snapshot -``` - -### Anvil - -```shell -$ anvil -``` - -### Deploy - -```shell -$ forge script script/Counter.s.sol:CounterScript --rpc-url --private-key -``` - -### Cast - -```shell -$ cast -``` - -### Help - -```shell -$ forge --help -$ anvil --help -$ cast --help -``` diff --git a/accounts/safe7579/notes.txt b/accounts/safe7579/notes.txt new file mode 100644 index 00000000..e69de29b diff --git a/accounts/safe7579/src/core/ModuleManager.sol b/accounts/safe7579/src/core/ModuleManager.sol index 1ea3f200..de6a1b73 100644 --- a/accounts/safe7579/src/core/ModuleManager.sol +++ b/accounts/safe7579/src/core/ModuleManager.sol @@ -107,6 +107,9 @@ abstract contract ModuleManager is AccessControl, Receiver, ExecutionHelper { isInstalled = $validators.contains({ account: msg.sender, entry: validator }); } + /** + * Get paginated list of installed validators + */ function getValidatorPaginated( address start, uint256 pageSize @@ -240,10 +243,71 @@ abstract contract ModuleManager is AccessControl, Receiver, ExecutionHelper { if (handler == address(0)) revert NoFallbackHandler(msg.sig); if (calltype == CALLTYPE_STATIC) { - return _executeStaticReturnData(msg.sender, handler, 0, callData); + 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 := + staticcall(gas(), handler, calldataPtr, add(calldatasize(), 20), 0, 0) + + let returnDataPtr := allocate(returndatasize()) + returndatacopy(returnDataPtr, 0, returndatasize()) + if iszero(success) { revert(returnDataPtr, returndatasize()) } + return(returnDataPtr, returndatasize()) + } } if (calltype == CALLTYPE_SINGLE) { - return _executeReturnData(msg.sender, handler, 0, callData); + 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()) + } } if (calltype == CALLTYPE_DELEGATECALL) { diff --git a/accounts/safe7579/test/SafeERC7579.t.sol b/accounts/safe7579/test/SafeERC7579.t.sol index 21d1e2a4..e1304392 100644 --- a/accounts/safe7579/test/SafeERC7579.t.sol +++ b/accounts/safe7579/test/SafeERC7579.t.sol @@ -7,6 +7,7 @@ import "erc7579/lib/ExecutionLib.sol"; import { TestBaseUtil, MockTarget, MockFallback } from "./Base.t.sol"; import "forge-std/console2.sol"; +CallType constant CALLTYPE_STATIC = CallType.wrap(0xFE); contract Safe7579Test is TestBaseUtil { MockTarget target; @@ -154,10 +155,26 @@ contract Safe7579Test is TestBaseUtil { IERC7579Account(address(safe)).installModule( 3, address(_fallback), abi.encode(MockFallback.target.selector, CALLTYPE_SINGLE, "") ); - (uint256 ret, address msgSender) = MockFallback(address(safe)).target(1337); + (uint256 ret, address msgSender, address context) = MockFallback(address(safe)).target(1337); assertEq(ret, 1337); - assertEq(msgSender, address(safe)); + assertEq(msgSender, address(safe7579)); + assertEq(context, address(safe)); + + vm.prank(address(safe)); + IERC7579Account(address(safe)).uninstallModule( + 3, address(_fallback), abi.encode(MockFallback.target.selector, CALLTYPE_SINGLE, "") + ); + vm.prank(address(safe)); + IERC7579Account(address(safe)).installModule( + 3, address(_fallback), abi.encode(MockFallback.target.selector, CALLTYPE_STATIC, "") + ); + ( ret, msgSender, context) = MockFallback(address(safe)).target(1337); + assertEq(ret, 1337); + assertEq(msgSender, address(safe7579)); + assertEq(context, address(safe)); + + vm.prank(address(safe)); IERC7579Account(address(safe)).installModule( diff --git a/accounts/safe7579/test/mocks/MockFallback.sol b/accounts/safe7579/test/mocks/MockFallback.sol index 20e4c29f..c5cdf51d 100644 --- a/accounts/safe7579/test/mocks/MockFallback.sol +++ b/accounts/safe7579/test/mocks/MockFallback.sol @@ -4,10 +4,16 @@ 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"; +import "forge-std/console2.sol"; + contract MockFallback is MockFallbackBase, HandlerContext { - function target(uint256 value) external returns (uint256 _value, address msgSender) { + function target(uint256 value) + external + returns (uint256 _value, address msgSender, address msgSenderContext) + { _value = value; msgSender = msg.sender; + msgSenderContext = _msgSender(); } function target2(uint256 value) From c0271d7f08a1c4a0cedfa638c370874f0dec1c85 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Thu, 14 Mar 2024 13:19:11 +0700 Subject: [PATCH 11/64] =?UTF-8?q?=E2=9C=A8=20Installation=20and=20deinstal?= =?UTF-8?q?lation=20now=20works=20with=20calldata?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- accounts/safe7579/src/SafeERC7579.sol | 56 ++++++++++++++----- accounts/safe7579/src/core/ModuleManager.sol | 8 +-- .../safe7579/src/interfaces/ISafe7579Init.sol | 20 +++++++ accounts/safe7579/src/utils/Launchpad.sol | 32 +++++++---- accounts/safe7579/test/Base.t.sol | 17 ++++-- accounts/safe7579/test/SafeERC7579.t.sol | 5 +- 6 files changed, 102 insertions(+), 36 deletions(-) create mode 100644 accounts/safe7579/src/interfaces/ISafe7579Init.sol diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index fc9742e0..2d9f1d71 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -29,6 +29,7 @@ import { } from "@ERC4337/account-abstraction/contracts/core/UserOperationLib.sol"; import { _packValidationData } from "@ERC4337/account-abstraction/contracts/core/Helpers.sol"; import { IEntryPoint } from "@ERC4337/account-abstraction/contracts/interfaces/IEntryPoint.sol"; +import { ISafe7579Init } from "./interfaces/ISafe7579Init.sol"; /** * @title ERC7579 Adapter for Safe accounts. @@ -36,7 +37,14 @@ import { IEntryPoint } from "@ERC4337/account-abstraction/contracts/interfaces/I * this contract creates full ERC7579 compliance to Safe accounts * @author zeroknots.eth | rhinestone.wtf */ -contract SafeERC7579 is ISafeOp, IERC7579Account, AccessControl, IMSA, HookManager { +contract SafeERC7579 is + ISafeOp, + IERC7579Account, + ISafe7579Init, + AccessControl, + IMSA, + HookManager +{ using UserOperationLib for PackedUserOperation; using ModeLib for ModeCode; using ExecutionLib for bytes; @@ -390,26 +398,46 @@ contract SafeERC7579 is ISafeOp, IERC7579Account, AccessControl, IMSA, HookManag return keccak256(abi.encode(DOMAIN_SEPARATOR_TYPEHASH, block.chainid, this)); } - function initializeAccount(bytes calldata initCode) external payable { + function initializeAccount(bytes calldata callData) external payable override { + // TODO: destructuring callData + } + + function initializeAccount( + ModuleInit[] calldata validators, + ModuleInit[] calldata executors, + ModuleInit[] calldata fallbacks, + ModuleInit[] calldata hooks + ) + public + payable + override + { _initModuleManager(); - ( - address[] memory validator, - bytes[] memory validatorInitcode, - address[] memory executors, - bytes[] memory executorsInitcode - ) = abi.decode(initCode, (address[], bytes[], address[], bytes[])); - - uint256 length = validator.length; - if (length != validatorInitcode.length) revert("Invalid input"); + // InitData memory initDatas = abi.decode(initCode, (InitData)); + + uint256 length = validators.length; for (uint256 i; i < length; i++) { - _installValidator(validator[i], validatorInitcode[i]); + ModuleInit calldata validator = validators[i]; + _installValidator(validator.module, validator.initData); } length = executors.length; - if (length != executorsInitcode.length) revert("Invalid input"); for (uint256 i; i < length; i++) { - _installExecutor(executors[i], executorsInitcode[i]); + ModuleInit calldata executor = executors[i]; + _installExecutor(executor.module, executor.initData); + } + + length = fallbacks.length; + for (uint256 i; i < length; i++) { + ModuleInit calldata fallBack = fallbacks[i]; + _installFallbackHandler(fallBack.module, fallBack.initData); + } + + length = hooks.length; + for (uint256 i; i < length; i++) { + ModuleInit calldata hook = hooks[i]; + _installFallbackHandler(hook.module, hook.initData); } emit Safe7579Initialized(msg.sender); diff --git a/accounts/safe7579/src/core/ModuleManager.sol b/accounts/safe7579/src/core/ModuleManager.sol index de6a1b73..6fa710cd 100644 --- a/accounts/safe7579/src/core/ModuleManager.sol +++ b/accounts/safe7579/src/core/ModuleManager.sol @@ -65,7 +65,7 @@ abstract contract ModuleManager is AccessControl, Receiver, ExecutionHelper { /** * install and initialize validator module */ - function _installValidator(address validator, bytes memory data) internal virtual { + function _installValidator(address validator, bytes calldata data) internal virtual { $validators.push({ account: msg.sender, newEntry: validator }); // Initialize Validator Module via Safe @@ -80,7 +80,7 @@ abstract contract ModuleManager is AccessControl, Receiver, ExecutionHelper { /** * Uninstall and de-initialize validator module */ - function _uninstallValidator(address validator, bytes memory data) internal { + function _uninstallValidator(address validator, bytes calldata data) internal { (address prev, bytes memory disableModuleData) = abi.decode(data, (address, bytes)); $validators.pop({ account: msg.sender, prevEntry: prev, popEntry: validator }); @@ -130,7 +130,7 @@ abstract contract ModuleManager is AccessControl, Receiver, ExecutionHelper { // Manage Executors //////////////////////////////////////////////////// - function _installExecutor(address executor, bytes memory data) internal { + function _installExecutor(address executor, bytes calldata data) internal { SentinelListLib.SentinelList storage $executors = $moduleManager[msg.sender]._executors; $executors.push(executor); // Initialize Executor Module via Safe @@ -268,7 +268,7 @@ abstract contract ModuleManager is AccessControl, Receiver, ExecutionHelper { // Add 20 bytes for the address appended add the end let success := - staticcall(gas(), handler, calldataPtr, add(calldatasize(), 20), 0, 0) + staticcall(gas(), handler, calldataPtr, add(calldatasize(), 20), 0, 0) let returnDataPtr := allocate(returndatasize()) returndatacopy(returnDataPtr, 0, returndatasize()) diff --git a/accounts/safe7579/src/interfaces/ISafe7579Init.sol b/accounts/safe7579/src/interfaces/ISafe7579Init.sol new file mode 100644 index 00000000..eb86459a --- /dev/null +++ b/accounts/safe7579/src/interfaces/ISafe7579Init.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import { CallType } from "erc7579/lib/ModeLib.sol"; + +interface ISafe7579Init { + struct ModuleInit { + address module; + bytes initData; + } + + function initializeAccount( + ModuleInit[] calldata validators, + ModuleInit[] calldata executors, + ModuleInit[] calldata fallbacks, + ModuleInit[] calldata hooks + ) + external + payable; +} diff --git a/accounts/safe7579/src/utils/Launchpad.sol b/accounts/safe7579/src/utils/Launchpad.sol index 1abc5030..b53725e0 100644 --- a/accounts/safe7579/src/utils/Launchpad.sol +++ b/accounts/safe7579/src/utils/Launchpad.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.0; import { ISafe, SafeERC7579 } from "../SafeERC7579.sol"; +import { ISafe7579Init } from "../interfaces/ISafe7579Init.sol"; /** * Helper contract that gets delegatecalled byt SafeProxy.setup() to setup safe7579 as a module @@ -15,9 +16,22 @@ contract Safe7579Launchpad { SAFE7579Singleton = _safe7579Singleton; } - function initSafe7579(address safe7579, bytes calldata safe7579InitCode) public { + // function initSafe7579(address safe7579, bytes calldata safe7579InitCode) public { + // ISafe(address(this)).enableModule(safe7579); + // SafeERC7579(payable(safe7579)).initializeAccount(safe7579InitCode); + // } + + function initSafe7579( + address safe7579, + ISafe7579Init.ModuleInit[] calldata validators, + ISafe7579Init.ModuleInit[] calldata executors, + ISafe7579Init.ModuleInit[] calldata fallbacks, + ISafe7579Init.ModuleInit[] calldata hooks + ) + public + { ISafe(address(this)).enableModule(safe7579); - SafeERC7579(payable(safe7579)).initializeAccount(safe7579InitCode); + SafeERC7579(payable(safe7579)).initializeAccount(validators, executors, fallbacks, hooks); } function predictSafeAddress( @@ -54,21 +68,17 @@ contract Safe7579Launchpad { function getInitCode( address[] memory signers, uint256 threshold, - address[] calldata validators, - bytes[] calldata validatorsInitCode, - address[] calldata executors, - bytes[] calldata executorsInitCode + ISafe7579Init.ModuleInit[] calldata validators, + ISafe7579Init.ModuleInit[] calldata executors, + ISafe7579Init.ModuleInit[] calldata fallbacks, + ISafe7579Init.ModuleInit[] calldata hooks ) external view returns (bytes memory initCode) { bytes memory safeLaunchPadSetup = abi.encodeCall( - this.initSafe7579, - ( - address(SAFE7579Singleton), - abi.encode(validators, validatorsInitCode, executors, executorsInitCode) - ) + this.initSafe7579, (address(SAFE7579Singleton), validators, executors, fallbacks, hooks) ); // SETUP SAFE initCode = abi.encodeCall( diff --git a/accounts/safe7579/test/Base.t.sol b/accounts/safe7579/test/Base.t.sol index 7e886b48..d1f18061 100644 --- a/accounts/safe7579/test/Base.t.sol +++ b/accounts/safe7579/test/Base.t.sol @@ -48,13 +48,22 @@ contract TestBaseUtil is Test { bytes32 salt; + ISafe7579Init.ModuleInit[] memory validators = new ISafe7579Init.ModuleInit[](1); + validators[0] = + ISafe7579Init.ModuleInit({ module: address(defaultValidator), initData: bytes("") }); + ISafe7579Init.ModuleInit[] memory executors = new ISafe7579Init.ModuleInit[](1); + executors[0] = + ISafe7579Init.ModuleInit({ module: address(defaultExecutor), initData: bytes("") }); + ISafe7579Init.ModuleInit[] memory fallbacks = new ISafe7579Init.ModuleInit[](0); + ISafe7579Init.ModuleInit[] memory hooks = new ISafe7579Init.ModuleInit[](0); + bytes memory initializer = launchpad.getInitCode({ signers: Solarray.addresses(signer1.addr, signer2.addr), threshold: 2, - validators: Solarray.addresses(address(defaultValidator)), - validatorsInitCode: Solarray.bytess(""), - executors: Solarray.addresses(address(defaultExecutor)), - executorsInitCode: Solarray.bytess("") + validators: validators, + executors: executors, + fallbacks: fallbacks, + hooks: hooks }); // computer counterfactual address for SafeProxy safe = Safe( diff --git a/accounts/safe7579/test/SafeERC7579.t.sol b/accounts/safe7579/test/SafeERC7579.t.sol index e1304392..95bdedc2 100644 --- a/accounts/safe7579/test/SafeERC7579.t.sol +++ b/accounts/safe7579/test/SafeERC7579.t.sol @@ -7,6 +7,7 @@ import "erc7579/lib/ExecutionLib.sol"; import { TestBaseUtil, MockTarget, MockFallback } from "./Base.t.sol"; import "forge-std/console2.sol"; + CallType constant CALLTYPE_STATIC = CallType.wrap(0xFE); contract Safe7579Test is TestBaseUtil { @@ -169,13 +170,11 @@ contract Safe7579Test is TestBaseUtil { IERC7579Account(address(safe)).installModule( 3, address(_fallback), abi.encode(MockFallback.target.selector, CALLTYPE_STATIC, "") ); - ( ret, msgSender, context) = MockFallback(address(safe)).target(1337); + (ret, msgSender, context) = MockFallback(address(safe)).target(1337); assertEq(ret, 1337); assertEq(msgSender, address(safe7579)); assertEq(context, address(safe)); - - vm.prank(address(safe)); IERC7579Account(address(safe)).installModule( 3, From d70c3a503df44fd244783d95234aa5643b8bb6f2 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Thu, 14 Mar 2024 13:19:30 +0700 Subject: [PATCH 12/64] rm: comment --- accounts/safe7579/src/SafeERC7579.sol | 2 -- 1 file changed, 2 deletions(-) diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index 2d9f1d71..88b615bf 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -414,8 +414,6 @@ contract SafeERC7579 is { _initModuleManager(); - // InitData memory initDatas = abi.decode(initCode, (InitData)); - uint256 length = validators.length; for (uint256 i; i < length; i++) { ModuleInit calldata validator = validators[i]; From c9997c7bf21cb919b119af9946c82e612ac8ee8c Mon Sep 17 00:00:00 2001 From: zeroknots Date: Thu, 14 Mar 2024 15:05:03 +0700 Subject: [PATCH 13/64] feat: adding default case for safe signature --- accounts/safe7579/src/SafeERC7579.sol | 11 +++++++---- accounts/safe7579/src/core/ModuleManager.sol | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index 88b615bf..81ba53b2 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -149,16 +149,19 @@ 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 not, use Safe's checkSignatures() - if (!_isValidatorInstalled(validator)) return _validateSignatures(userOp); - - // bubble up the return value of the validator module - validSignature = IValidator(validator).validateUserOp(userOp, userOpHash); + if (validator == address(0) || !_isValidatorInstalled(validator)) { + return _validateSignatures(userOp); + } else { + // bubble up the return value of the validator module + validSignature = IValidator(validator).validateUserOp(userOp, userOpHash); + } // pay prefund if (missingAccountFunds != 0) { diff --git a/accounts/safe7579/src/core/ModuleManager.sol b/accounts/safe7579/src/core/ModuleManager.sol index 6fa710cd..c443881a 100644 --- a/accounts/safe7579/src/core/ModuleManager.sol +++ b/accounts/safe7579/src/core/ModuleManager.sol @@ -310,6 +310,7 @@ abstract contract ModuleManager is AccessControl, Receiver, ExecutionHelper { } } + // TODO: do we actually want this? security questionable... if (calltype == CALLTYPE_DELEGATECALL) { return _executeDelegateCallReturnData(msg.sender, handler, callData); } From 85105132957c5a60cef10cfe0eafc9d53f7c771c Mon Sep 17 00:00:00 2001 From: zeroknots Date: Thu, 14 Mar 2024 15:34:30 +0700 Subject: [PATCH 14/64] fixed fallbacks --- accounts/safe7579/src/core/ModuleManager.sol | 74 ++----------------- accounts/safe7579/test/SafeERC7579.t.sol | 20 ++--- accounts/safe7579/test/mocks/MockFallback.sol | 2 +- 3 files changed, 19 insertions(+), 77 deletions(-) diff --git a/accounts/safe7579/src/core/ModuleManager.sol b/accounts/safe7579/src/core/ModuleManager.sol index c443881a..055cc6a0 100644 --- a/accounts/safe7579/src/core/ModuleManager.sol +++ b/accounts/safe7579/src/core/ModuleManager.sol @@ -242,74 +242,16 @@ abstract contract ModuleManager is AccessControl, Receiver, ExecutionHelper { CallType calltype = $fallbackHandler.calltype; if (handler == address(0)) revert NoFallbackHandler(msg.sig); - if (calltype == CALLTYPE_STATIC) { - 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 := - staticcall(gas(), handler, calldataPtr, add(calldatasize(), 20), 0, 0) - - let returnDataPtr := allocate(returndatasize()) - returndatacopy(returnDataPtr, 0, returndatasize()) - if iszero(success) { revert(returnDataPtr, returndatasize()) } - return(returnDataPtr, returndatasize()) - } - } + // dis wont work. need Enum.Operation static, cause safe account emits event + // if (calltype == CALLTYPE_STATIC) { + // return _executeStaticReturnData( + // msg.sender, handler, 0, abi.encodePacked(callData, _msgSender()) + // ); + // } if (calltype == CALLTYPE_SINGLE) { - 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()) - } + return + _executeReturnData(msg.sender, handler, 0, abi.encodePacked(callData, _msgSender())); } - // TODO: do we actually want this? security questionable... if (calltype == CALLTYPE_DELEGATECALL) { return _executeDelegateCallReturnData(msg.sender, handler, callData); diff --git a/accounts/safe7579/test/SafeERC7579.t.sol b/accounts/safe7579/test/SafeERC7579.t.sol index 95bdedc2..91e82a02 100644 --- a/accounts/safe7579/test/SafeERC7579.t.sol +++ b/accounts/safe7579/test/SafeERC7579.t.sol @@ -159,21 +159,21 @@ contract Safe7579Test is TestBaseUtil { (uint256 ret, address msgSender, address context) = MockFallback(address(safe)).target(1337); assertEq(ret, 1337); - assertEq(msgSender, address(safe7579)); - assertEq(context, address(safe)); + assertEq(msgSender, address(safe)); + assertEq(context, address(this)); vm.prank(address(safe)); IERC7579Account(address(safe)).uninstallModule( 3, address(_fallback), abi.encode(MockFallback.target.selector, CALLTYPE_SINGLE, "") ); - vm.prank(address(safe)); - IERC7579Account(address(safe)).installModule( - 3, address(_fallback), abi.encode(MockFallback.target.selector, CALLTYPE_STATIC, "") - ); - (ret, msgSender, context) = MockFallback(address(safe)).target(1337); - assertEq(ret, 1337); - assertEq(msgSender, address(safe7579)); - assertEq(context, address(safe)); + // vm.prank(address(safe)); + // IERC7579Account(address(safe)).installModule( + // 3, address(_fallback), abi.encode(MockFallback.target.selector, CALLTYPE_STATIC, "") + // ); + // (ret, msgSender, context) = MockFallback(address(safe)).target(1337); + // assertEq(ret, 1337); + // assertEq(msgSender, address(safe7579)); + // assertEq(context, address(safe)); vm.prank(address(safe)); IERC7579Account(address(safe)).installModule( diff --git a/accounts/safe7579/test/mocks/MockFallback.sol b/accounts/safe7579/test/mocks/MockFallback.sol index c5cdf51d..c599b3b3 100644 --- a/accounts/safe7579/test/mocks/MockFallback.sol +++ b/accounts/safe7579/test/mocks/MockFallback.sol @@ -21,7 +21,7 @@ contract MockFallback is MockFallbackBase, HandlerContext { returns (uint256 _value, address _this, address msgSender) { _value = value; - msgSender = msg.sender; _this = address(this); + msgSender = msg.sender; } } From 6c96a29c913e5841108bd58738977aac5f026d14 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Fri, 15 Mar 2024 09:05:19 +0700 Subject: [PATCH 15/64] rm: remove not implemented calltype --- accounts/safe7579/src/core/ModuleManager.sol | 2 -- 1 file changed, 2 deletions(-) diff --git a/accounts/safe7579/src/core/ModuleManager.sol b/accounts/safe7579/src/core/ModuleManager.sol index 055cc6a0..ca516be2 100644 --- a/accounts/safe7579/src/core/ModuleManager.sol +++ b/accounts/safe7579/src/core/ModuleManager.sol @@ -9,8 +9,6 @@ import { Receiver } from "erc7579/core/Receiver.sol"; import { AccessControl } from "./AccessControl.sol"; import { CallType, CALLTYPE_SINGLE, CALLTYPE_DELEGATECALL } from "erc7579/lib/ModeLib.sol"; -CallType constant CALLTYPE_STATIC = CallType.wrap(0xFE); - struct FallbackHandler { address handler; CallType calltype; From 00261acd24a2cc29ce9773f0e3451acfd983f307 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Sat, 16 Mar 2024 08:02:25 +0700 Subject: [PATCH 16/64] =?UTF-8?q?=E2=9C=A8=20Add=20ERC1271=20fallback=20fo?= =?UTF-8?q?r=20safe=20native=20signatures?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit if no signature or address(0) validation module or an not installed 7579 validation module is provided within the abi.encodePacked signature data in erc1271, it falls back to safe's signature check --- accounts/safe7579/src/SafeERC7579.sol | 54 ++++++++++++++++++- accounts/safe7579/src/interfaces/IERC1271.sol | 22 ++++++++ accounts/safe7579/src/interfaces/ISafe.sol | 2 + 3 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 accounts/safe7579/src/interfaces/IERC1271.sol diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index 81ba53b2..7fe55a07 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -30,6 +30,7 @@ import { import { _packValidationData } from "@ERC4337/account-abstraction/contracts/core/Helpers.sol"; import { IEntryPoint } from "@ERC4337/account-abstraction/contracts/interfaces/IEntryPoint.sol"; import { ISafe7579Init } from "./interfaces/ISafe7579Init.sol"; +import { IERC1271 } from "./interfaces/IERC1271.sol"; /** * @title ERC7579 Adapter for Safe accounts. @@ -56,6 +57,12 @@ contract SafeERC7579 is bytes32 private constant DOMAIN_SEPARATOR_TYPEHASH = 0x47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a79469218; + // keccak256("SafeMessage(bytes message)"); + bytes32 private constant SAFE_MSG_TYPEHASH = + 0x60b3cbf8b4a223d68d641b3b6ddf9a298e7f33710cf3d3a9d1146b5a6150fbca; + // keccak256("safeSignature(bytes32,bytes32,bytes,bytes)"); + bytes4 private constant SAFE_SIGNATURE_MAGIC_VALUE = 0x5fd7e97d; + /** * @inheritdoc IERC7579Account */ @@ -201,7 +208,13 @@ contract SafeERC7579 is } /** - * @inheritdoc IERC7579Account + * Will use Safe's signed messages or checkSignatures features or ERC7579 validation modules + * if no signature is provided, it makes use of Safe's signedMessages + * if address(0) or a non-installed validator module is provided, it will use Safe's + * checkSignatures + * if a valid validator module is provided, it will use the module's validateUserOp function + * @param hash message hash of ERC1271 request + * @param data abi.encodePacked(address validationModule, bytes signatures) */ function isValidSignature( bytes32 hash, @@ -211,9 +224,27 @@ contract SafeERC7579 is view returns (bytes4 magicValue) { + ISafe safe = ISafe(msg.sender); + + // check for safe's approved hashes + if (data.length == 0 && safe.signedMessages(hash) != 0) { + // return magic value + return IERC1271.isValidSignature.selector; + } address validationModule = address(bytes20(data[:20])); - if (!_isValidatorInstalled(validationModule)) return 0xFFFFFFFF; + if (validationModule == address(0) || !_isValidatorInstalled(validationModule)) { + bytes memory messageData = EIP712.encodeMessageData( + safe.domainSeparator(), SAFE_MSG_TYPEHASH, abi.encode(keccak256(abi.encode(hash))) + ); + + bytes32 messageHash = keccak256(messageData); + + safe.checkSignatures(messageHash, messageData, data[20:]); + return IERC1271.isValidSignature.selector; + } + + // use 7579 validation module magicValue = IValidator(validationModule).isValidSignatureWithSender(msg.sender, hash, data[20:]); } @@ -454,3 +485,22 @@ contract SafeERC7579 is nonce = IEntryPoint(entryPoint()).getNonce(safe, key); } } + +library EIP712 { + function encodeMessageData( + bytes32 domainSeparator, + bytes32 typeHash, + bytes memory message + ) + internal + pure + returns (bytes memory) + { + return abi.encodePacked( + bytes1(0x19), + bytes1(0x01), + domainSeparator, + keccak256(abi.encodePacked(typeHash, message)) + ); + } +} diff --git a/accounts/safe7579/src/interfaces/IERC1271.sol b/accounts/safe7579/src/interfaces/IERC1271.sol new file mode 100644 index 00000000..5aff1322 --- /dev/null +++ b/accounts/safe7579/src/interfaces/IERC1271.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: LGPL-3.0-only +pragma solidity ^0.8.23; + +interface IERC1271 { + /** + * @dev Should return whether the signature provided is valid for the provided data + * @param _dataHash Arbitrary length data signed on behalf of address(this) + * @param _signature Signature byte array associated with _data + * + * MUST return the bytes4 magic value 0x1626ba7e when function passes. + * MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > + * 0.5) + * MUST allow external calls + */ + function isValidSignature( + bytes32 _dataHash, + bytes calldata _signature + ) + external + view + returns (bytes4); +} diff --git a/accounts/safe7579/src/interfaces/ISafe.sol b/accounts/safe7579/src/interfaces/ISafe.sol index be60fa30..9d770160 100644 --- a/accounts/safe7579/src/interfaces/ISafe.sol +++ b/accounts/safe7579/src/interfaces/ISafe.sol @@ -65,6 +65,8 @@ interface ISafe { external view; + function signedMessages(bytes32) external view returns (uint256); + /** * @dev Returns the domain separator for this contract, as defined in the EIP-712 standard. * @return bytes32 The domain separator hash. From b10a3f1ac7151c418745a60e7a9ad0e943aea14f Mon Sep 17 00:00:00 2001 From: zeroknots Date: Thu, 4 Apr 2024 10:17:45 +0700 Subject: [PATCH 17/64] chore: fix validator call --- accounts/safe7579/src/SafeERC7579.sol | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index 7fe55a07..5d07d966 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -167,7 +167,13 @@ contract SafeERC7579 is return _validateSignatures(userOp); } else { // bubble up the return value of the validator module - validSignature = IValidator(validator).validateUserOp(userOp, userOpHash); + bytes memory retData = _executeReturnData( + msg.sender, + validator, + 0, + abi.encodeCall(IValidator.validateUserOp, (userOp, userOpHash)) + ); + validSignature = abi.decode(retData, (uint256)); } // pay prefund From 691f926a56010765ba532376a694b85a761dc19a Mon Sep 17 00:00:00 2001 From: zeroknots Date: Thu, 4 Apr 2024 10:18:25 +0700 Subject: [PATCH 18/64] add hook calls --- accounts/safe7579/src/SafeERC7579.sol | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index 5d07d966..7d0f892e 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -131,14 +131,8 @@ 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(); + function executeUserOp(PackedUserOperation calldata userOp) external payable override { + revert Unsupported(); } /** @@ -266,6 +260,7 @@ contract SafeERC7579 is external payable override + withHook onlyEntryPointOrSelf { if (moduleType == MODULE_TYPE_VALIDATOR) _installValidator(module, initData); @@ -287,6 +282,7 @@ contract SafeERC7579 is external payable override + withHook onlyEntryPointOrSelf { if (moduleType == MODULE_TYPE_VALIDATOR) _uninstallValidator(module, deInitData); From b2187bdd70a85c0b42fa490954500030bfb3c46f Mon Sep 17 00:00:00 2001 From: zeroknots Date: Thu, 4 Apr 2024 10:52:49 +0700 Subject: [PATCH 19/64] feat: implement staticcalls via safes simulate feature --- accounts/safe7579/src/SafeERC7579.sol | 2 +- .../safe7579/src/core/ExecutionHelper.sol | 28 +++++++++++++++++-- accounts/safe7579/src/core/ModuleManager.sol | 13 +++++---- accounts/safe7579/test/SafeERC7579.t.sol | 16 +++++------ 4 files changed, 41 insertions(+), 18 deletions(-) diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index 7d0f892e..91b2e625 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -131,7 +131,7 @@ contract SafeERC7579 is /** * @inheritdoc IERC7579Account */ - function executeUserOp(PackedUserOperation calldata userOp) external payable override { + function executeUserOp(PackedUserOperation calldata /*userOp*/ ) external payable override { revert Unsupported(); } diff --git a/accounts/safe7579/src/core/ExecutionHelper.sol b/accounts/safe7579/src/core/ExecutionHelper.sol index cc50f31d..e9d4b6b3 100644 --- a/accounts/safe7579/src/core/ExecutionHelper.sol +++ b/accounts/safe7579/src/core/ExecutionHelper.sol @@ -3,6 +3,12 @@ pragma solidity >=0.8.0 <0.9.0; import { Execution } from "erc7579/interfaces/IERC7579Account.sol"; import { ISafe } from "../interfaces/ISafe.sol"; +import { + SimulateTxAccessor, + Enum +} from "@safe-global/safe-contracts/contracts/accessors/SimulateTxAccessor.sol"; + +import "forge-std/console2.sol"; /** * @title Helper contract to execute transactions from a safe @@ -13,6 +19,12 @@ import { ISafe } from "../interfaces/ISafe.sol"; abstract contract ExecutionHelper { error ExecutionFailed(); + SimulateTxAccessor immutable SIMULATETX; + + constructor() { + SIMULATETX = new SimulateTxAccessor(); + } + /** * Execute call on Safe * @dev This function will revert if the call fails @@ -115,6 +127,9 @@ abstract contract ExecutionHelper { /** * Execute staticcall on Safe, get return value from call + * Safe does not implement Enum.Operation for staticcall. + * we are using a trick, of nudging the Safe account to delegatecall to the SimulateTxAccessor, + * and call simulate() * @dev This function will revert if the call fails * @param safe address of the safe * @param target address of the contract to call @@ -129,13 +144,20 @@ abstract contract ExecutionHelper { bytes memory callData ) internal - view returns (bytes memory returnData) { bool success; - (success, returnData) = safe.staticcall( - abi.encodeCall(ISafe.execTransactionFromModuleReturnData, (target, value, callData, 0)) + // this is the return data from the Safe.execTransactionFromModuleReturnData call. NOT the + // simulation + (success, returnData) = ISafe(safe).execTransactionFromModuleReturnData( + address(SIMULATETX), + 0, + abi.encodeCall(SIMULATETX.simulate, (target, value, callData, Enum.Operation.Call)), + 1 ); if (!success) revert ExecutionFailed(); + // decode according to simulate() return values + (, success, returnData) = abi.decode(returnData, (uint256, bool, bytes)); + if (!success) revert ExecutionFailed(); } } diff --git a/accounts/safe7579/src/core/ModuleManager.sol b/accounts/safe7579/src/core/ModuleManager.sol index ca516be2..8321b215 100644 --- a/accounts/safe7579/src/core/ModuleManager.sol +++ b/accounts/safe7579/src/core/ModuleManager.sol @@ -9,6 +9,8 @@ import { Receiver } from "erc7579/core/Receiver.sol"; import { AccessControl } from "./AccessControl.sol"; import { CallType, CALLTYPE_SINGLE, CALLTYPE_DELEGATECALL } from "erc7579/lib/ModeLib.sol"; +CallType constant CALLTYPE_STATIC = CallType.wrap(0xFE); + struct FallbackHandler { address handler; CallType calltype; @@ -240,12 +242,11 @@ abstract contract ModuleManager is AccessControl, Receiver, ExecutionHelper { CallType calltype = $fallbackHandler.calltype; if (handler == address(0)) revert NoFallbackHandler(msg.sig); - // dis wont work. need Enum.Operation static, cause safe account emits event - // if (calltype == CALLTYPE_STATIC) { - // return _executeStaticReturnData( - // msg.sender, handler, 0, abi.encodePacked(callData, _msgSender()) - // ); - // } + if (calltype == CALLTYPE_STATIC) { + return _executeStaticReturnData( + msg.sender, handler, 0, abi.encodePacked(callData, _msgSender()) + ); + } if (calltype == CALLTYPE_SINGLE) { return _executeReturnData(msg.sender, handler, 0, abi.encodePacked(callData, _msgSender())); diff --git a/accounts/safe7579/test/SafeERC7579.t.sol b/accounts/safe7579/test/SafeERC7579.t.sol index 91e82a02..88527109 100644 --- a/accounts/safe7579/test/SafeERC7579.t.sol +++ b/accounts/safe7579/test/SafeERC7579.t.sol @@ -166,14 +166,14 @@ contract Safe7579Test is TestBaseUtil { IERC7579Account(address(safe)).uninstallModule( 3, address(_fallback), abi.encode(MockFallback.target.selector, CALLTYPE_SINGLE, "") ); - // vm.prank(address(safe)); - // IERC7579Account(address(safe)).installModule( - // 3, address(_fallback), abi.encode(MockFallback.target.selector, CALLTYPE_STATIC, "") - // ); - // (ret, msgSender, context) = MockFallback(address(safe)).target(1337); - // assertEq(ret, 1337); - // assertEq(msgSender, address(safe7579)); - // assertEq(context, address(safe)); + vm.prank(address(safe)); + IERC7579Account(address(safe)).installModule( + 3, address(_fallback), abi.encode(MockFallback.target.selector, CALLTYPE_STATIC, "") + ); + (ret, msgSender, context) = MockFallback(address(safe)).target(1337); + assertEq(ret, 1337); + assertEq(msgSender, address(safe)); + assertEq(context, address(this)); vm.prank(address(safe)); IERC7579Account(address(safe)).installModule( From 28d66b80de89384ecb76aaf8aedb4f64dc3db700 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Thu, 4 Apr 2024 10:58:02 +0700 Subject: [PATCH 20/64] feat: blacklisting onInstall and onUninstall msg.sigs for fallbacks. here be dragons --- accounts/safe7579/src/SafeERC7579.sol | 4 ++-- accounts/safe7579/src/core/ModuleManager.sol | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index 91b2e625..ca4000c0 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -199,8 +199,8 @@ contract SafeERC7579 is try ISafe(payable(userOp.getSender())).checkSignatures( keccak256(operationData), operationData, signatures ) { - // The timestamps are validated by the entry point, therefore we will not check them - // again + // The timestamps are validated by the entry point, + // therefore we will not check them again validationData = _packValidationData(false, validUntil, validAfter); } catch { validationData = _packValidationData(true, validUntil, validAfter); diff --git a/accounts/safe7579/src/core/ModuleManager.sol b/accounts/safe7579/src/core/ModuleManager.sol index 8321b215..9790c257 100644 --- a/accounts/safe7579/src/core/ModuleManager.sol +++ b/accounts/safe7579/src/core/ModuleManager.sol @@ -37,6 +37,7 @@ abstract contract ModuleManager is AccessControl, Receiver, ExecutionHelper { error InitializerError(); error ValidatorStorageHelperError(); error NoFallbackHandler(bytes4 msgSig); + error InvalidFallbackHandler(bytes4 msgSig); error FallbackInstalled(bytes4 msgSig); mapping(address smartAccount => ModuleManagerStorage moduleManagerStorage) internal @@ -180,6 +181,12 @@ abstract contract ModuleManager is AccessControl, Receiver, ExecutionHelper { function _installFallbackHandler(address handler, bytes calldata params) internal virtual { (bytes4 functionSig, CallType calltype, bytes memory initData) = abi.decode(params, (bytes4, CallType, bytes)); + + // disallow calls to onInstall or onUninstall. + // this could create a security issue + if ( + functionSig == IModule.onInstall.selector || functionSig == IModule.onUninstall.selector + ) revert InvalidFallbackHandler(functionSig); if (_isFallbackHandlerInstalled(functionSig)) revert FallbackInstalled(functionSig); FallbackHandler storage $fallbacks = $moduleManager[msg.sender]._fallbacks[functionSig]; From 7cce2a061a06f525f0782e0071ebf46798769fd7 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Thu, 4 Apr 2024 11:01:21 +0700 Subject: [PATCH 21/64] chore: cleaning up --- accounts/safe7579/src/core/ExecutionHelper.sol | 4 +--- accounts/safe7579/src/interfaces/ISafe7579Init.sol | 2 -- accounts/safe7579/src/utils/Launchpad.sol | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/accounts/safe7579/src/core/ExecutionHelper.sol b/accounts/safe7579/src/core/ExecutionHelper.sol index e9d4b6b3..52c1e473 100644 --- a/accounts/safe7579/src/core/ExecutionHelper.sol +++ b/accounts/safe7579/src/core/ExecutionHelper.sol @@ -8,8 +8,6 @@ import { Enum } from "@safe-global/safe-contracts/contracts/accessors/SimulateTxAccessor.sol"; -import "forge-std/console2.sol"; - /** * @title Helper contract to execute transactions from a safe * All functions implemented in this contract check, @@ -19,7 +17,7 @@ import "forge-std/console2.sol"; abstract contract ExecutionHelper { error ExecutionFailed(); - SimulateTxAccessor immutable SIMULATETX; + SimulateTxAccessor private immutable SIMULATETX; constructor() { SIMULATETX = new SimulateTxAccessor(); diff --git a/accounts/safe7579/src/interfaces/ISafe7579Init.sol b/accounts/safe7579/src/interfaces/ISafe7579Init.sol index eb86459a..8af559f9 100644 --- a/accounts/safe7579/src/interfaces/ISafe7579Init.sol +++ b/accounts/safe7579/src/interfaces/ISafe7579Init.sol @@ -1,8 +1,6 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.23; -import { CallType } from "erc7579/lib/ModeLib.sol"; - interface ISafe7579Init { struct ModuleInit { address module; diff --git a/accounts/safe7579/src/utils/Launchpad.sol b/accounts/safe7579/src/utils/Launchpad.sol index b53725e0..cc14d3dd 100644 --- a/accounts/safe7579/src/utils/Launchpad.sol +++ b/accounts/safe7579/src/utils/Launchpad.sol @@ -10,7 +10,7 @@ import { ISafe7579Init } from "../interfaces/ISafe7579Init.sol"; * as well as initializing Safe7579 for the SafeProxy */ contract Safe7579Launchpad { - address immutable SAFE7579Singleton; + address public immutable SAFE7579Singleton; constructor(address _safe7579Singleton) { SAFE7579Singleton = _safe7579Singleton; From 2a99dd20f62cb006369dfb3aed8bb7fda24ebe7b Mon Sep 17 00:00:00 2001 From: zeroknots Date: Thu, 4 Apr 2024 11:52:12 +0700 Subject: [PATCH 22/64] =?UTF-8?q?=F0=9F=94=A5=20Changing=20initAccount=20t?= =?UTF-8?q?o=20only=20use=20validators=20for=20ERC4337=20compliance?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit foo --- accounts/safe7579/src/SafeERC7579.sol | 39 +++++-------------- .../safe7579/src/interfaces/ISafe7579Init.sol | 9 +---- accounts/safe7579/src/utils/Launchpad.sol | 17 +++----- accounts/safe7579/test/Base.t.sol | 22 +++++++---- accounts/safe7579/test/SafeERC7579.t.sol | 2 - 5 files changed, 31 insertions(+), 58 deletions(-) diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index ca4000c0..88e87c5c 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -435,19 +435,18 @@ contract SafeERC7579 is } function initializeAccount(bytes calldata callData) external payable override { - // TODO: destructuring callData + ModuleInit[] calldata validators; + assembly ("memory-safe") { + let dataPointer := add(callData.offset, calldataload(callData.offset)) + + validators.offset := add(dataPointer, 32) + validators.length := calldataload(dataPointer) + } + initializeAccount(validators); } - function initializeAccount( - ModuleInit[] calldata validators, - ModuleInit[] calldata executors, - ModuleInit[] calldata fallbacks, - ModuleInit[] calldata hooks - ) - public - payable - override - { + function initializeAccount(ModuleInit[] calldata validators) public payable { + // this will revert if already initialized _initModuleManager(); uint256 length = validators.length; @@ -456,24 +455,6 @@ contract SafeERC7579 is _installValidator(validator.module, validator.initData); } - length = executors.length; - for (uint256 i; i < length; i++) { - ModuleInit calldata executor = executors[i]; - _installExecutor(executor.module, executor.initData); - } - - length = fallbacks.length; - for (uint256 i; i < length; i++) { - ModuleInit calldata fallBack = fallbacks[i]; - _installFallbackHandler(fallBack.module, fallBack.initData); - } - - length = hooks.length; - for (uint256 i; i < length; i++) { - ModuleInit calldata hook = hooks[i]; - _installFallbackHandler(hook.module, hook.initData); - } - emit Safe7579Initialized(msg.sender); } diff --git a/accounts/safe7579/src/interfaces/ISafe7579Init.sol b/accounts/safe7579/src/interfaces/ISafe7579Init.sol index 8af559f9..cf92d0eb 100644 --- a/accounts/safe7579/src/interfaces/ISafe7579Init.sol +++ b/accounts/safe7579/src/interfaces/ISafe7579Init.sol @@ -7,12 +7,5 @@ interface ISafe7579Init { bytes initData; } - function initializeAccount( - ModuleInit[] calldata validators, - ModuleInit[] calldata executors, - ModuleInit[] calldata fallbacks, - ModuleInit[] calldata hooks - ) - external - payable; + function initializeAccount(ModuleInit[] calldata validators) external payable; } diff --git a/accounts/safe7579/src/utils/Launchpad.sol b/accounts/safe7579/src/utils/Launchpad.sol index cc14d3dd..ceb5076c 100644 --- a/accounts/safe7579/src/utils/Launchpad.sol +++ b/accounts/safe7579/src/utils/Launchpad.sol @@ -23,15 +23,12 @@ contract Safe7579Launchpad { function initSafe7579( address safe7579, - ISafe7579Init.ModuleInit[] calldata validators, - ISafe7579Init.ModuleInit[] calldata executors, - ISafe7579Init.ModuleInit[] calldata fallbacks, - ISafe7579Init.ModuleInit[] calldata hooks + ISafe7579Init.ModuleInit[] calldata validators ) public { ISafe(address(this)).enableModule(safe7579); - SafeERC7579(payable(safe7579)).initializeAccount(validators, executors, fallbacks, hooks); + SafeERC7579(payable(safe7579)).initializeAccount(abi.encode(validators)); } function predictSafeAddress( @@ -68,18 +65,14 @@ contract Safe7579Launchpad { function getInitCode( address[] memory signers, uint256 threshold, - ISafe7579Init.ModuleInit[] calldata validators, - ISafe7579Init.ModuleInit[] calldata executors, - ISafe7579Init.ModuleInit[] calldata fallbacks, - ISafe7579Init.ModuleInit[] calldata hooks + ISafe7579Init.ModuleInit[] calldata validators ) external view returns (bytes memory initCode) { - bytes memory safeLaunchPadSetup = abi.encodeCall( - this.initSafe7579, (address(SAFE7579Singleton), validators, executors, fallbacks, hooks) - ); + bytes memory safeLaunchPadSetup = + abi.encodeCall(this.initSafe7579, (address(SAFE7579Singleton), validators)); // SETUP SAFE initCode = abi.encodeCall( ISafe.setup, diff --git a/accounts/safe7579/test/Base.t.sol b/accounts/safe7579/test/Base.t.sol index d1f18061..75d9ccde 100644 --- a/accounts/safe7579/test/Base.t.sol +++ b/accounts/safe7579/test/Base.t.sol @@ -54,16 +54,13 @@ contract TestBaseUtil is Test { ISafe7579Init.ModuleInit[] memory executors = new ISafe7579Init.ModuleInit[](1); executors[0] = ISafe7579Init.ModuleInit({ module: address(defaultExecutor), initData: bytes("") }); - ISafe7579Init.ModuleInit[] memory fallbacks = new ISafe7579Init.ModuleInit[](0); - ISafe7579Init.ModuleInit[] memory hooks = new ISafe7579Init.ModuleInit[](0); + // ISafe7579Init.ModuleInit[] memory fallbacks = new ISafe7579Init.ModuleInit[](0); + // ISafe7579Init.ModuleInit[] memory hooks = new ISafe7579Init.ModuleInit[](0); bytes memory initializer = launchpad.getInitCode({ signers: Solarray.addresses(signer1.addr, signer2.addr), threshold: 2, - validators: validators, - executors: executors, - fallbacks: fallbacks, - hooks: hooks + validators: validators }); // computer counterfactual address for SafeProxy safe = Safe( @@ -77,7 +74,18 @@ contract TestBaseUtil is Test { }) ) ); - userOpInitCode = initCode(initializer, salt); + + PackedUserOperation memory userOp = + getDefaultUserOp(address(safe), address(defaultValidator)); + + userOp.callData = + abi.encodeCall(SafeERC7579.installModule, (2, address(defaultExecutor), bytes(""))); + userOp.initCode = initCode(initializer, salt); + PackedUserOperation[] memory userOps = new PackedUserOperation[](1); + userOps[0] = userOp; + deal(address(safe), 1 ether); + + entrypoint.handleOps(userOps, payable(address(0x69))); } function initCode( diff --git a/accounts/safe7579/test/SafeERC7579.t.sol b/accounts/safe7579/test/SafeERC7579.t.sol index 88527109..3966c9c1 100644 --- a/accounts/safe7579/test/SafeERC7579.t.sol +++ b/accounts/safe7579/test/SafeERC7579.t.sol @@ -16,7 +16,6 @@ contract Safe7579Test is TestBaseUtil { function setUp() public override { super.setUp(); target = new MockTarget(); - deal(address(safe), 1 ether); } modifier alreadyInitialized(bool initNow) { @@ -41,7 +40,6 @@ contract Safe7579Test is TestBaseUtil { ExecutionLib.encodeSingle(address(target), uint256(0), setValueOnTarget) ) ); - userOp.initCode = userOpInitCode; userOp.callData = userOpCalldata; // Create userOps array PackedUserOperation[] memory userOps = new PackedUserOperation[](1); From 7432b7aed74253d0fc325c6e6898c9040cef7e05 Mon Sep 17 00:00:00 2001 From: kopy-kat Date: Thu, 4 Apr 2024 12:29:56 +0200 Subject: [PATCH 23/64] feat: implement come's feedback --- accounts/safe7579/src/SafeERC7579.sol | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index ca4000c0..8cd726a3 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -146,6 +146,7 @@ contract SafeERC7579 is external payable override + onlyEntryPointOrSelf returns (uint256 validSignature) { address validator; @@ -158,7 +159,7 @@ contract SafeERC7579 is // check if validator is enabled. If not, use Safe's checkSignatures() if (validator == address(0) || !_isValidatorInstalled(validator)) { - return _validateSignatures(userOp); + validSignature = _validateSignatures(userOp); } else { // bubble up the return value of the validator module bytes memory retData = _executeReturnData( From b12287785b1aaaa20b288b4da206682e5d4fc77a Mon Sep 17 00:00:00 2001 From: kopy-kat Date: Thu, 4 Apr 2024 14:18:17 +0200 Subject: [PATCH 24/64] fix: access control on validateUserOp --- accounts/safe7579/src/SafeERC7579.sol | 2 +- accounts/safe7579/src/core/AccessControl.sol | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index 8cd726a3..d1fc4b06 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -146,7 +146,7 @@ contract SafeERC7579 is external payable override - onlyEntryPointOrSelf + onlyEntryPoint returns (uint256 validSignature) { address validator; diff --git a/accounts/safe7579/src/core/AccessControl.sol b/accounts/safe7579/src/core/AccessControl.sol index 5a866403..1a3563ac 100644 --- a/accounts/safe7579/src/core/AccessControl.sol +++ b/accounts/safe7579/src/core/AccessControl.sol @@ -12,6 +12,13 @@ contract AccessControl is HandlerContext, AccountBase { _; } + modifier onlyEntryPoint() virtual { + if (_msgSender() != entryPoint()) { + revert AccountAccessUnauthorized(); + } + _; + } + function entryPoint() public view virtual override returns (address) { return 0x0000000071727De22E5E9d8BAf0edAc6f37da032; } From 579ea0b858f96a1aa25e550a30b83389d0be8b2a Mon Sep 17 00:00:00 2001 From: kopy-kat Date: Thu, 4 Apr 2024 17:06:11 +0200 Subject: [PATCH 25/64] fix: pass correct deinitdata to fallback --- accounts/safe7579/src/core/ModuleManager.sol | 12 +++++++++--- accounts/safe7579/test/SafeERC7579.t.sol | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/accounts/safe7579/src/core/ModuleManager.sol b/accounts/safe7579/src/core/ModuleManager.sol index 9790c257..5478026c 100644 --- a/accounts/safe7579/src/core/ModuleManager.sol +++ b/accounts/safe7579/src/core/ModuleManager.sol @@ -206,8 +206,14 @@ abstract contract ModuleManager is AccessControl, Receiver, ExecutionHelper { return $fallback.handler != address(0); } - function _uninstallFallbackHandler(address handler, bytes calldata initData) internal virtual { - (bytes4 functionSig) = abi.decode(initData, (bytes4)); + function _uninstallFallbackHandler( + address handler, + bytes calldata deInitData + ) + internal + virtual + { + bytes4 functionSig = bytes4(deInitData[0:4]); ModuleManagerStorage storage $mms = $moduleManager[msg.sender]; $mms._fallbacks[functionSig].handler = address(0); @@ -216,7 +222,7 @@ abstract contract ModuleManager is AccessControl, Receiver, ExecutionHelper { safe: msg.sender, target: handler, value: 0, - callData: abi.encodeCall(IModule.onUninstall, (initData)) + callData: abi.encodeWithSelector(IModule.onUninstall.selector, (deInitData[4:])) }); } diff --git a/accounts/safe7579/test/SafeERC7579.t.sol b/accounts/safe7579/test/SafeERC7579.t.sol index 88527109..6eb16bab 100644 --- a/accounts/safe7579/test/SafeERC7579.t.sol +++ b/accounts/safe7579/test/SafeERC7579.t.sol @@ -164,7 +164,7 @@ contract Safe7579Test is TestBaseUtil { vm.prank(address(safe)); IERC7579Account(address(safe)).uninstallModule( - 3, address(_fallback), abi.encode(MockFallback.target.selector, CALLTYPE_SINGLE, "") + 3, address(_fallback), abi.encodePacked(MockFallback.target.selector, "") ); vm.prank(address(safe)); IERC7579Account(address(safe)).installModule( From ec3760e3b795c65acebde8f5bf8cadf9bcb77e6f Mon Sep 17 00:00:00 2001 From: kopy-kat Date: Thu, 4 Apr 2024 17:18:55 +0200 Subject: [PATCH 26/64] fix: use msg.sender instead of userOp.sender --- accounts/safe7579/src/SafeERC7579.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index d1fc4b06..fabc26ef 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -174,7 +174,7 @@ contract SafeERC7579 is // pay prefund if (missingAccountFunds != 0) { _execute({ - safe: userOp.getSender(), + safe: msg.sender, target: entryPoint(), value: missingAccountFunds, callData: "" @@ -197,7 +197,7 @@ contract SafeERC7579 is uint48 validUntil, bytes calldata signatures ) = _getSafeOp(userOp); - try ISafe(payable(userOp.getSender())).checkSignatures( + try ISafe(payable(msg.sender)).checkSignatures( keccak256(operationData), operationData, signatures ) { // The timestamps are validated by the entry point, @@ -397,7 +397,7 @@ contract SafeERC7579 is // result of `abi.encode`-ing the individual fields. EncodedSafeOpStruct memory encodedSafeOp = EncodedSafeOpStruct({ typeHash: SAFE_OP_TYPEHASH, - safe: userOp.sender, + safe: msg.sender, nonce: userOp.nonce, initCodeHash: keccak256(userOp.initCode), callDataHash: keccak256(userOp.callData), From 08009a21e23575db83cf6dcd1722e9dbce26ab62 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Mon, 8 Apr 2024 08:57:37 +0700 Subject: [PATCH 27/64] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20Adding=20ERC7484=20r?= =?UTF-8?q?egistry?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- accounts/safe7579/src/SafeERC7579.sol | 67 +++- accounts/safe7579/src/core/HookManager.sol | 11 +- accounts/safe7579/src/core/ModuleManager.sol | 36 +- .../safe7579/src/core/RegistryAdapter.sol | 29 ++ accounts/safe7579/src/interfaces/IERC7484.sol | 48 +++ .../safe7579/src/interfaces/ISafe7579Init.sol | 27 +- accounts/safe7579/src/utils/Launchpadv2.sol | 340 ++++++++++++++++++ accounts/safe7579/src/utils/SignerFactory.sol | 134 +++++++ accounts/safe7579/test/Launchpad.t.sol | 189 ++++++++++ accounts/safe7579/test/mocks/MockRegistry.sol | 53 +++ 10 files changed, 923 insertions(+), 11 deletions(-) create mode 100644 accounts/safe7579/src/core/RegistryAdapter.sol create mode 100644 accounts/safe7579/src/interfaces/IERC7484.sol create mode 100644 accounts/safe7579/src/utils/Launchpadv2.sol create mode 100644 accounts/safe7579/src/utils/SignerFactory.sol create mode 100644 accounts/safe7579/test/Launchpad.t.sol create mode 100644 accounts/safe7579/test/mocks/MockRegistry.sol diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index 88e87c5c..90265991 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -31,13 +31,14 @@ import { _packValidationData } from "@ERC4337/account-abstraction/contracts/core import { IEntryPoint } from "@ERC4337/account-abstraction/contracts/interfaces/IEntryPoint.sol"; import { ISafe7579Init } from "./interfaces/ISafe7579Init.sol"; import { IERC1271 } from "./interfaces/IERC1271.sol"; - +import { IERC7484 } from "./interfaces/IERC7484.sol"; /** * @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, @@ -261,6 +262,7 @@ contract SafeERC7579 is payable override withHook + // withRegistry(module, moduleType) onlyEntryPointOrSelf { if (moduleType == MODULE_TYPE_VALIDATOR) _installValidator(module, initData); @@ -442,19 +444,65 @@ contract SafeERC7579 is validators.offset := add(dataPointer, 32) validators.length := calldataload(dataPointer) } - initializeAccount(validators); + // initializeAccount(validators); + } + + function initializeAccountWithRegistry( + ModuleInit[] calldata validators, + ModuleInit[] calldata executors, + ModuleInit[] calldata fallbacks, + ModuleInit calldata hook, + RegistryInit calldata registryInit + ) + public + payable + { + _configureRegistry(registryInit.registry, registryInit.attesters, registryInit.threshold); + _initModules(validators, executors, fallbacks, hook); } - function initializeAccount(ModuleInit[] calldata validators) public payable { + function initializeAccount( + ModuleInit[] calldata validators, + ModuleInit[] calldata executors, + ModuleInit[] calldata fallbacks, + ModuleInit calldata hook + ) + public + payable + { + _initModules(validators, executors, fallbacks, hook); + } + + function _initModules( + ModuleInit[] calldata validators, + ModuleInit[] calldata executors, + ModuleInit[] calldata fallbacks, + ModuleInit calldata hook + ) + internal + { // this will revert if already initialized _initModuleManager(); - uint256 length = validators.length; for (uint256 i; i < length; i++) { ModuleInit calldata validator = validators[i]; _installValidator(validator.module, validator.initData); } + length = executors.length; + for (uint256 i; i < length; i++) { + ModuleInit calldata executor = executors[i]; + _installValidator(executor.module, executor.initData); + } + + length = fallbacks.length; + for (uint256 i; i < length; i++) { + ModuleInit calldata _fallback = fallbacks[i]; + _installValidator(_fallback.module, _fallback.initData); + } + + _installHook(hook.module, hook.initData); + emit Safe7579Initialized(msg.sender); } @@ -467,6 +515,17 @@ contract SafeERC7579 is uint192 key = uint192(bytes24(bytes20(address(validator)))); nonce = IEntryPoint(entryPoint()).getNonce(safe, key); } + + function setRegistry( + IERC7484 registry, + address[] calldata attesters, + uint8 threshold + ) + external + onlyEntryPointOrSelf + { + _configureRegistry(registry, attesters, threshold); + } } library EIP712 { diff --git a/accounts/safe7579/src/core/HookManager.sol b/accounts/safe7579/src/core/HookManager.sol index 1330e279..14c1d82e 100644 --- a/accounts/safe7579/src/core/HookManager.sol +++ b/accounts/safe7579/src/core/HookManager.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.23; -import { ModuleManager } from "./ModuleManager.sol"; +import { ModuleManager, MODULE_TYPE_HOOK } from "./ModuleManager.sol"; import { IHook, IModule } from "erc7579/interfaces/IERC7579Module.sol"; /** @@ -49,7 +49,14 @@ abstract contract HookManager is ModuleManager { }); } - function _installHook(address hook, bytes calldata data) internal virtual { + function _installHook( + address hook, + bytes calldata data + ) + internal + virtual + withRegistry(hook, MODULE_TYPE_HOOK) + { address currentHook = $hookManager[msg.sender]; if (currentHook != address(0)) { revert HookAlreadyInstalled(currentHook); diff --git a/accounts/safe7579/src/core/ModuleManager.sol b/accounts/safe7579/src/core/ModuleManager.sol index 9790c257..08f5d1f7 100644 --- a/accounts/safe7579/src/core/ModuleManager.sol +++ b/accounts/safe7579/src/core/ModuleManager.sol @@ -5,10 +5,19 @@ 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 { RegistryAdapter } from "./RegistryAdapter.sol"; import { Receiver } from "erc7579/core/Receiver.sol"; import { AccessControl } from "./AccessControl.sol"; import { CallType, CALLTYPE_SINGLE, CALLTYPE_DELEGATECALL } from "erc7579/lib/ModeLib.sol"; +import { + IValidator, + MODULE_TYPE_VALIDATOR, + MODULE_TYPE_HOOK, + MODULE_TYPE_EXECUTOR, + MODULE_TYPE_FALLBACK +} from "erc7579/interfaces/IERC7579Module.sol"; + CallType constant CALLTYPE_STATIC = CallType.wrap(0xFE); struct FallbackHandler { @@ -27,7 +36,7 @@ struct ModuleManagerStorage { * Contract that implements ERC7579 Module compatibility for Safe accounts * @author zeroknots.eth | rhinestone.wtf */ -abstract contract ModuleManager is AccessControl, Receiver, ExecutionHelper { +abstract contract ModuleManager is AccessControl, Receiver, ExecutionHelper, RegistryAdapter { using SentinelListLib for SentinelListLib.SentinelList; using SentinelList4337Lib for SentinelList4337Lib.SentinelList; @@ -66,7 +75,13 @@ abstract contract ModuleManager is AccessControl, Receiver, ExecutionHelper { /** * install and initialize validator module */ - function _installValidator(address validator, bytes calldata data) internal virtual { + function _installValidator( + address validator, + bytes calldata data + ) + internal + withRegistry(validator, MODULE_TYPE_VALIDATOR) + { $validators.push({ account: msg.sender, newEntry: validator }); // Initialize Validator Module via Safe @@ -131,7 +146,13 @@ abstract contract ModuleManager is AccessControl, Receiver, ExecutionHelper { // Manage Executors //////////////////////////////////////////////////// - function _installExecutor(address executor, bytes calldata data) internal { + function _installExecutor( + address executor, + bytes calldata data + ) + internal + withRegistry(executor, MODULE_TYPE_EXECUTOR) + { SentinelListLib.SentinelList storage $executors = $moduleManager[msg.sender]._executors; $executors.push(executor); // Initialize Executor Module via Safe @@ -178,7 +199,14 @@ abstract contract ModuleManager is AccessControl, Receiver, ExecutionHelper { ///////////////////////////////////////////////////// // Manage Fallback //////////////////////////////////////////////////// - function _installFallbackHandler(address handler, bytes calldata params) internal virtual { + function _installFallbackHandler( + address handler, + bytes calldata params + ) + internal + virtual + withRegistry(handler, MODULE_TYPE_FALLBACK) + { (bytes4 functionSig, CallType calltype, bytes memory initData) = abi.decode(params, (bytes4, CallType, bytes)); diff --git a/accounts/safe7579/src/core/RegistryAdapter.sol b/accounts/safe7579/src/core/RegistryAdapter.sol new file mode 100644 index 00000000..7821a2f4 --- /dev/null +++ b/accounts/safe7579/src/core/RegistryAdapter.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import "../interfaces/IERC7484.sol"; + +contract RegistryAdapter { + event ERC7484RegistryConfigured(address indexed smartAccount, address indexed registry); + + mapping(address smartAccount => IERC7484 registry) internal $registry; + + modifier withRegistry(address module, uint256 moduleType) { + IERC7484 registry = $registry[msg.sender]; + if (address(registry) != address(0)) { + registry.check(module, moduleType); + } + _; + } + + function _configureRegistry( + IERC7484 registry, + address[] calldata attesters, + uint8 threshold + ) + internal + { + $registry[msg.sender] = registry; + registry.trustAttesters(threshold, attesters); + } +} diff --git a/accounts/safe7579/src/interfaces/IERC7484.sol b/accounts/safe7579/src/interfaces/IERC7484.sol new file mode 100644 index 00000000..f8cc48e5 --- /dev/null +++ b/accounts/safe7579/src/interfaces/IERC7484.sol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IERC7484 { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* Check with Registry internal attesters */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + function check(address module) external view; + + function checkForAccount(address smartAccount, address module) external view; + + function check(address module, uint256 moduleType) external view; + + function checkForAccount( + address smartAccount, + address module, + uint256 moduleType + ) + external + view; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* Check with external attester(s) */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + function check(address module, address attester) external view; + + function check(address module, uint256 moduleType, address attester) external view; + + function checkN( + address module, + address[] calldata attesters, + uint256 threshold + ) + external + view; + + function checkN( + address module, + uint256 moduleType, + address[] calldata attesters, + uint256 threshold + ) + external + view; + + function trustAttesters(uint8 threshold, address[] calldata attesters) external; +} diff --git a/accounts/safe7579/src/interfaces/ISafe7579Init.sol b/accounts/safe7579/src/interfaces/ISafe7579Init.sol index cf92d0eb..c54ea52d 100644 --- a/accounts/safe7579/src/interfaces/ISafe7579Init.sol +++ b/accounts/safe7579/src/interfaces/ISafe7579Init.sol @@ -1,11 +1,36 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.23; +import { IERC7484 } from "./IERC7484.sol"; + interface ISafe7579Init { struct ModuleInit { address module; bytes initData; } - function initializeAccount(ModuleInit[] calldata validators) external payable; + struct RegistryInit { + IERC7484 registry; + address[] attesters; + uint8 threshold; + } + + function initializeAccountWithRegistry( + ModuleInit[] calldata validators, + ModuleInit[] calldata executors, + ModuleInit[] calldata fallbacks, + ModuleInit calldata hook, + RegistryInit calldata registryInit + ) + external + payable; + + function initializeAccount( + ModuleInit[] calldata validators, + ModuleInit[] calldata executors, + ModuleInit[] calldata fallbacks, + ModuleInit calldata hook + ) + external + payable; } diff --git a/accounts/safe7579/src/utils/Launchpadv2.sol b/accounts/safe7579/src/utils/Launchpadv2.sol new file mode 100644 index 00000000..9e1dcf31 --- /dev/null +++ b/accounts/safe7579/src/utils/Launchpadv2.sol @@ -0,0 +1,340 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.22; + +import { IAccount, PackedUserOperation } from "account-abstraction/interfaces/IAccount.sol"; +import { _packValidationData } from "account-abstraction/core/Helpers.sol"; +import { ISafe } from "../interfaces/ISafe.sol"; +import { IUniqueSignerFactory } from "./SignerFactory.sol"; +import { ISafe7579Init } from "../interfaces/ISafe7579Init.sol"; +import { SafeERC7579 } from "../SafeERC7579.sol"; + +import { SafeStorage } from "@safe-global/safe-contracts/contracts/libraries/SafeStorage.sol"; +import { ISignatureValidator } from + "@safe-global/safe-contracts/contracts/interfaces/ISignatureValidator.sol"; + +/** + * @title SafeOpLaunchpad - A contract for Safe initialization with custom unique signers that would + * violate ERC-4337 factory rules. + * @dev The is intended to be set as a Safe proxy's implementation for ERC-4337 user operation that + * deploys the account. + */ +contract SafeSignerLaunchpad is IAccount, SafeStorage { + bytes32 private constant DOMAIN_SEPARATOR_TYPEHASH = + keccak256("EIP712Domain(uint256 chainId,address verifyingContract)"); + + // keccak256("SafeSignerLaunchpad.initHash") - 1 + uint256 private constant INIT_HASH_SLOT = + 0x1d2f0b9dbb6ed3f829c9614e6c5d2ea2285238801394dc57e8500e0e306d8f80; + + /** + * @notice The keccak256 hash of the EIP-712 SafeInit struct, representing the structure of a + * ERC-4337 compatible deferred Safe initialization. + * {address} singleton - The singleton to evolve into during the setup. + * {address} signerFactory - The unique signer factory to use for creating an owner. + * {bytes} signerData - The signer data to use the owner. + * {address} setupTo - The contract to delegatecall during setup. + * {bytes} setupData - The calldata for the setup delegatecall. + * {address} fallbackHandler - The fallback handler to initialize the Safe with. + */ + bytes32 private constant SAFE_INIT_TYPEHASH = keccak256( + "SafeInit(address singleton,address signerFactory,bytes signerData,address setupTo,bytes setupData,address fallbackHandler)" + ); + + /** + * @notice The keccak256 hash of the EIP-712 SafeInitOp struct, representing the user operation + * to execute alongside initialization. + * {bytes32} userOpHash - The user operation hash being executed. + * {uint48} validAfter - A timestamp representing from when the user operation is valid. + * {uint48} validUntil - A timestamp representing until when the user operation is valid, or 0 + * to indicated "forever". + * {address} entryPoint - The address of the entry point that will execute the user operation. + */ + bytes32 private constant SAFE_INIT_OP_TYPEHASH = keccak256( + "SafeInitOp(bytes32 userOpHash,uint48 validAfter,uint48 validUntil,address entryPoint)" + ); + + address private immutable SELF; + address public immutable SUPPORTED_ENTRYPOINT; + + constructor(address entryPoint) { + require(entryPoint != address(0), "Invalid entry point"); + + SELF = address(this); + SUPPORTED_ENTRYPOINT = entryPoint; + } + + function initSafe7579WithRegistry( + address safe7579, + ISafe7579Init.ModuleInit[] calldata validators, + ISafe7579Init.ModuleInit[] calldata executors, + ISafe7579Init.ModuleInit[] calldata fallbacks, + ISafe7579Init.ModuleInit calldata hook, + ISafe7579Init.RegistryInit calldata registryInit + ) + public + { + ISafe(address(this)).enableModule(safe7579); + SafeERC7579(payable(safe7579)).initializeAccountWithRegistry( + validators, executors, fallbacks, hook, registryInit + ); + } + + function initSafe7579( + address safe7579, + ISafe7579Init.ModuleInit[] calldata validators, + ISafe7579Init.ModuleInit[] calldata executors, + ISafe7579Init.ModuleInit[] calldata fallbacks, + ISafe7579Init.ModuleInit calldata hook + ) + public + { + ISafe(address(this)).enableModule(safe7579); + SafeERC7579(payable(safe7579)).initializeAccount(validators, executors, fallbacks, hook); + } + + function predictSafeAddress( + address singleton, + address safeProxyFactory, + bytes memory creationCode, + bytes32 salt, + bytes memory factoryInitializer + ) + external + pure + returns (address safeProxy) + { + salt = keccak256(abi.encodePacked(keccak256(factoryInitializer), salt)); + + safeProxy = address( + uint160( + uint256( + keccak256( + abi.encodePacked( + bytes1(0xff), + address(safeProxyFactory), + salt, + keccak256( + abi.encodePacked(creationCode, uint256(uint160(address(singleton)))) + ) + ) + ) + ) + ) + ); + } + + modifier onlyProxy() { + require(singleton == SELF, "Not called from proxy"); + _; + } + + modifier onlySupportedEntryPoint() { + require(msg.sender == SUPPORTED_ENTRYPOINT, "Unsupported entry point"); + _; + } + + receive() external payable { } + + function preValidationSetup( + bytes32 initHash, + address to, + bytes calldata preInit + ) + external + onlyProxy + { + _setInitHash(initHash); + if (to != address(0)) { + (bool success,) = to.delegatecall(preInit); + require(success, "Pre-initialization failed"); + } + } + + function getInitHash( + address singleton, + address signerFactory, + bytes memory signerData, + address setupTo, + bytes memory setupData, + address fallbackHandler + ) + public + view + returns (bytes32 initHash) + { + initHash = keccak256( + abi.encodePacked( + bytes1(0x19), + bytes1(0x01), + _domainSeparator(), + keccak256( + abi.encode( + SAFE_INIT_TYPEHASH, + singleton, + signerFactory, + keccak256(signerData), + setupTo, + keccak256(setupData), + fallbackHandler + ) + ) + ) + ); + } + + function getOperationHash( + bytes32 userOpHash, + uint48 validAfter, + uint48 validUntil + ) + public + view + returns (bytes32 operationHash) + { + operationHash = keccak256(_getOperationData(userOpHash, validAfter, validUntil)); + } + + function validateUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash, + uint256 missingAccountFunds + ) + external + override + onlyProxy + onlySupportedEntryPoint + returns (uint256 validationData) + { + address signerFactory; + bytes memory signerData; + { + require( + this.initializeThenUserOp.selector == bytes4(userOp.callData[:4]), + "invalid user operation data" + ); + + address singleton; + address setupTo; + bytes memory setupData; + address fallbackHandler; + (singleton, signerFactory, signerData, setupTo, setupData, fallbackHandler,) = abi + .decode(userOp.callData[4:], (address, address, bytes, address, bytes, address, bytes)); + bytes32 initHash = getInitHash( + singleton, signerFactory, signerData, setupTo, setupData, fallbackHandler + ); + + require(initHash == _initHash(), "invalid init hash"); + } + + uint48 validAfter; + uint48 validUntil; + bytes calldata signature; + { + bytes calldata sig = userOp.signature; + validAfter = uint48(bytes6(sig[0:6])); + validUntil = uint48(bytes6(sig[6:12])); + signature = sig[12:]; + } + + bytes memory operationData = _getOperationData(userOpHash, validAfter, validUntil); + // bytes4 magicValue = IUniqueSignerFactory(signerFactory).isValidSignatureForSigner( + // operationData, signature, signerData + // ); + bytes4 magicValue = ISignatureValidator.isValidSignature.selector; + validationData = _packValidationData( + magicValue != ISignatureValidator.isValidSignature.selector, validUntil, validAfter + ); + + if (missingAccountFunds > 0) { + // solhint-disable-next-line no-inline-assembly + assembly ("memory-safe") { + pop(call(gas(), caller(), missingAccountFunds, 0, 0, 0, 0)) + } + } + } + + function initializeThenUserOp( + address singleton, + address signerFactory, + bytes calldata signerData, + address setupTo, + bytes calldata setupData, + address fallbackHandler, + bytes memory callData + ) + external + onlySupportedEntryPoint + { + SafeStorage.singleton = singleton; + { + // address[] memory owners = new address[](1); + // owners[0] = IUniqueSignerFactory(signerFactory).createSigner(signerData); + + (address[] memory owners) = abi.decode(signerData, (address[])); + + ISafe(address(this)).setup( + owners, 1, setupTo, setupData, fallbackHandler, address(0), 0, payable(address(0)) + ); + } + + (bool success, bytes memory returnData) = address(this).delegatecall(callData); + if (!success) { + // solhint-disable-next-line no-inline-assembly + assembly ("memory-safe") { + revert(add(returnData, 0x20), mload(returnData)) + } + } + + _setInitHash(0); + } + + function _domainSeparator() internal view returns (bytes32) { + return keccak256(abi.encode(DOMAIN_SEPARATOR_TYPEHASH, block.chainid, SELF)); + } + + function _getOperationData( + bytes32 userOpHash, + uint48 validAfter, + uint48 validUntil + ) + public + view + returns (bytes memory operationData) + { + operationData = abi.encodePacked( + bytes1(0x19), + bytes1(0x01), + _domainSeparator(), + keccak256( + abi.encode( + SAFE_INIT_OP_TYPEHASH, userOpHash, validAfter, validUntil, SUPPORTED_ENTRYPOINT + ) + ) + ); + } + + function _initHash() public view returns (bytes32 value) { + // solhint-disable-next-line no-inline-assembly + assembly ("memory-safe") { + value := sload(INIT_HASH_SLOT) + } + } + + function _setInitHash(bytes32 value) internal { + // solhint-disable-next-line no-inline-assembly + assembly ("memory-safe") { + sstore(INIT_HASH_SLOT, value) + } + } + + function _isContract(address account) internal view returns (bool) { + uint256 size; + /* solhint-disable no-inline-assembly */ + /// @solidity memory-safe-assembly + assembly { + size := extcodesize(account) + } + /* solhint-enable no-inline-assembly */ + return size > 0; + } +} diff --git a/accounts/safe7579/src/utils/SignerFactory.sol b/accounts/safe7579/src/utils/SignerFactory.sol new file mode 100644 index 00000000..050643a4 --- /dev/null +++ b/accounts/safe7579/src/utils/SignerFactory.sol @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import { ISignatureValidator } from + "@safe-global/safe-contracts/contracts/interfaces/ISignatureValidator.sol"; + +interface IUniqueSignerFactory { + /** + * @notice Gets the unique signer address for the specified data. + * @dev The unique signer address must be unique for some given data. The signer is not + * guaranteed to be created yet. + * @param data The signer specific data. + * @return signer The signer address. + */ + function getSigner(bytes memory data) external view returns (address signer); + + /** + * @notice Create a new unique signer for the specified data. + * @dev The unique signer address must be unique for some given data. This must not revert if + * the unique owner already exists. + * @param data The signer specific data. + * @return signer The signer address. + */ + function createSigner(bytes memory data) external returns (address signer); + + /** + * @notice Verifies a signature for the specified address without deploying it. + * @dev This must be equivalent to first deploying the signer with the factory, and then + * verifying the signature + * with it directly: `factory.createSigner(signerData).isValidSignature(data, signature)` + * @param data The data whose signature should be verified. + * @param signature The signature bytes. + * @param signerData The signer data to verify signature for. + * @return magicValue Returns `ISignatureValidator.isValidSignature.selector` when the signature + * is valid. Reverting or returning any other value implies an invalid signature. + */ + function isValidSignatureForSigner( + bytes calldata data, + bytes calldata signature, + bytes calldata signerData + ) + external + view + returns (bytes4 magicValue); +} + +function checkSignature( + bytes memory data, + uint256 signature, + uint256 key +) + pure + returns (bytes4 magicValue) +{ + uint256 message = uint256(keccak256(data)); + + // A very silly signing scheme where the `message = signature ^ key` + if (message == signature ^ key) { + magicValue = ISignatureValidator.isValidSignature.selector; + } +} + +contract UniqueSignerFactory is IUniqueSignerFactory { + function getSigner(bytes calldata data) public view returns (address signer) { + uint256 key = abi.decode(data, (uint256)); + signer = _getSigner(key); + } + + function createSigner(bytes calldata data) external returns (address signer) { + uint256 key = abi.decode(data, (uint256)); + signer = _getSigner(key); + if (_hasNoCode(signer)) { + TestUniqueSigner created = new TestUniqueSigner{ salt: bytes32(0) }(key); + require(address(created) == signer); + } + } + + function isValidSignatureForSigner( + bytes memory data, + bytes memory signatureData, + bytes memory signerData + ) + external + pure + override + returns (bytes4 magicValue) + { + uint256 key = abi.decode(signerData, (uint256)); + uint256 signature = abi.decode(signatureData, (uint256)); + magicValue = checkSignature(data, signature, key); + } + + function _getSigner(uint256 key) internal view returns (address) { + bytes32 codeHash = keccak256(abi.encodePacked(type(TestUniqueSigner).creationCode, key)); + return address( + uint160( + uint256(keccak256(abi.encodePacked(hex"ff", address(this), bytes32(0), codeHash))) + ) + ); + } + + function _hasNoCode(address account) internal view returns (bool) { + uint256 size; + /* solhint-disable no-inline-assembly */ + /// @solidity memory-safe-assembly + assembly { + size := extcodesize(account) + } + /* solhint-enable no-inline-assembly */ + return size == 0; + } +} + +contract TestUniqueSigner is ISignatureValidator { + uint256 public immutable KEY; + + constructor(uint256 key) { + KEY = key; + } + + function isValidSignature( + bytes memory data, + bytes memory signatureData + ) + public + view + virtual + override + returns (bytes4 magicValue) + { + uint256 signature = abi.decode(signatureData, (uint256)); + magicValue = checkSignature(data, signature, KEY); + } +} diff --git a/accounts/safe7579/test/Launchpad.t.sol b/accounts/safe7579/test/Launchpad.t.sol new file mode 100644 index 00000000..c78363b2 --- /dev/null +++ b/accounts/safe7579/test/Launchpad.t.sol @@ -0,0 +1,189 @@ +// 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 { MockRegistry } from "./mocks/MockRegistry.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 { + SafeProxy, + SafeProxyFactory +} from "@safe-global/safe-contracts/contracts/proxies/SafeProxyFactory.sol"; +import { LibClone } from "solady/src/utils/LibClone.sol"; +import "src/utils/Launchpadv2.sol"; +import "src/utils/SignerFactory.sol"; +import "src/interfaces/ISafe7579Init.sol"; + +import { Solarray } from "solarray/Solarray.sol"; +import "./dependencies/EntryPoint.sol"; + +contract LaunchpadBase is Test { + SafeERC7579 safe7579; + Safe singleton; + Safe safe; + SafeProxyFactory safeProxyFactory; + TestUniqueSigner uniqueSigner; + UniqueSignerFactory uniqueSignerFactory; + SafeSignerLaunchpad launchpad; + + MockValidator defaultValidator; + MockExecutor defaultExecutor; + + Account signer1 = makeAccount("signer1"); + Account signer2 = makeAccount("signer2"); + + IEntryPoint entrypoint; + bytes userOpInitCode; + + struct Setup { + address singleton; + address signerFactory; + bytes signerData; + address setupTo; + bytes setupData; + address fallbackHandler; + } + + function setUp() public virtual { + // Set up EntryPoint + entrypoint = etchEntrypoint(); + singleton = new Safe(); + safeProxyFactory = new SafeProxyFactory(); + safe7579 = new SafeERC7579(); + launchpad = new SafeSignerLaunchpad(address(entrypoint)); + uniqueSignerFactory = new UniqueSignerFactory(); + uint256 key = 1; + uniqueSigner = new TestUniqueSigner(key); + + // Set up Modules + defaultValidator = new MockValidator(); + defaultExecutor = new MockExecutor(); + + bytes32 salt; + + ISafe7579Init.ModuleInit[] memory validators = new ISafe7579Init.ModuleInit[](1); + validators[0] = + ISafe7579Init.ModuleInit({ module: address(defaultValidator), initData: bytes("") }); + ISafe7579Init.ModuleInit[] memory executors = new ISafe7579Init.ModuleInit[](1); + executors[0] = + ISafe7579Init.ModuleInit({ module: address(defaultExecutor), initData: bytes("") }); + ISafe7579Init.ModuleInit[] memory fallbacks = new ISafe7579Init.ModuleInit[](0); + ISafe7579Init.ModuleInit memory hook = + ISafe7579Init.ModuleInit({ module: address(0), initData: bytes("") }); + + ISafe7579Init.RegistryInit memory registryInit = ISafe7579Init.RegistryInit({ + registry: IERC7484(address(new MockRegistry())), + attesters: Solarray.addresses(makeAddr("attester1"), makeAddr("attester2")), + threshold: 2 + }); + + Setup memory _setup = Setup({ + singleton: address(singleton), + signerFactory: address(uniqueSignerFactory), + signerData: abi.encode(Solarray.addresses(signer1.addr, signer2.addr)), + setupTo: address(launchpad), + setupData: abi.encodeCall( + SafeSignerLaunchpad.initSafe7579WithRegistry, + (address(safe7579), validators, executors, fallbacks, hook, registryInit) + ), + fallbackHandler: address(safe7579) + }); + bytes32 initHash = launchpad.getInitHash({ + singleton: _setup.singleton, + signerFactory: _setup.signerFactory, + signerData: _setup.signerData, + setupTo: _setup.setupTo, + setupData: _setup.setupData, + fallbackHandler: _setup.fallbackHandler + }); + + bytes memory factoryInitializer = abi.encodeCall( + SafeSignerLaunchpad.preValidationSetup, (initHash, address(safe7579), "") + ); + + PackedUserOperation memory userOp = + getDefaultUserOp(address(safe), address(defaultValidator)); + + userOp.callData = abi.encodeCall( + SafeSignerLaunchpad.initializeThenUserOp, + ( + _setup.singleton, + _setup.signerFactory, + _setup.signerData, + _setup.setupTo, + _setup.setupData, + _setup.fallbackHandler, + "" + ) + ); + userOp.initCode = _initCode(factoryInitializer, salt); + + address predict = launchpad.predictSafeAddress({ + singleton: address(launchpad), + safeProxyFactory: address(safeProxyFactory), + creationCode: type(SafeProxy).creationCode, + salt: salt, + factoryInitializer: factoryInitializer + }); + userOp.sender = predict; + assertEq(userOp.sender, predict); + userOp.signature = abi.encodePacked( + uint48(0), uint48(type(uint48).max), hex"4141414141414141414141414141414141" + ); + + bytes32 userOpHash = entrypoint.getUserOpHash(userOp); + PackedUserOperation[] memory userOps = new PackedUserOperation[](1); + userOps[0] = userOp; + deal(address(userOp.sender), 1 ether); + + entrypoint.handleOps(userOps, payable(address(0x69))); + } + + function _initCode( + bytes memory initializer, + bytes32 salt + ) + internal + view + returns (bytes memory _initCode) + { + _initCode = abi.encodePacked( + address(safeProxyFactory), + abi.encodeCall( + SafeProxyFactory.createProxyWithNonce, + (address(launchpad), initializer, uint256(salt)) + ) + ); + } + + function test_foo() public { + assertTrue(true); + } + + function getDefaultUserOp( + address account, + address validator + ) + internal + view + returns (PackedUserOperation memory userOp) + { + userOp = PackedUserOperation({ + sender: account, + nonce: safe7579.getNonce(account, validator), + 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/mocks/MockRegistry.sol b/accounts/safe7579/test/mocks/MockRegistry.sol new file mode 100644 index 00000000..51fbdfd7 --- /dev/null +++ b/accounts/safe7579/test/mocks/MockRegistry.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import { IERC7484 } from "src/interfaces/IERC7484.sol"; + +contract MockRegistry is IERC7484 { + event NewTrustedAttesters(); + + function check(address module) external view override { } + + function checkForAccount(address smartAccount, address module) external view override { } + + function check(address module, uint256 moduleType) external view override { } + + function checkForAccount( + address smartAccount, + address module, + uint256 moduleType + ) + external + view + override + { } + + function check(address module, address attester) external view override { } + + function check(address module, uint256 moduleType, address attester) external view override { } + + function checkN( + address module, + address[] calldata attesters, + uint256 threshold + ) + external + view + override + { } + + function checkN( + address module, + uint256 moduleType, + address[] calldata attesters, + uint256 threshold + ) + external + view + override + { } + + function trustAttesters(uint8 threshold, address[] calldata attesters) external override { + emit NewTrustedAttesters(); + } +} From b0ac136d66ee82784823922d42b70998d1151c01 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Mon, 8 Apr 2024 10:26:08 +0700 Subject: [PATCH 28/64] refactoring executions --- accounts/safe7579/src/SafeERC7579.sol | 122 +++++++++++----- .../safe7579/src/core/ExecutionHelper.sol | 131 +++++++++++++++++- accounts/safe7579/test/Base.t.sol | 4 +- accounts/safe7579/test/Launchpad.t.sol | 4 +- accounts/safe7579/test/mocks/MockTarget.sol | 19 +++ 5 files changed, 241 insertions(+), 39 deletions(-) create mode 100644 accounts/safe7579/test/mocks/MockTarget.sol diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index 90265991..374dd2dd 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -5,8 +5,11 @@ import { IERC7579Account, Execution } from "erc7579/interfaces/IERC7579Account.s import { IMSA } from "erc7579/interfaces/IMSA.sol"; import { CallType, + ExecType, ModeCode, ModeLib, + EXECTYPE_DEFAULT, + EXECTYPE_TRY, CALLTYPE_SINGLE, CALLTYPE_BATCH, CALLTYPE_DELEGATECALL @@ -77,21 +80,47 @@ contract SafeERC7579 is withHook // ! this modifier has side effects / external calls onlyEntryPointOrSelf { - CallType callType = mode.getCallType(); - - if (callType == CALLTYPE_BATCH) { - Execution[] calldata executions = executionCalldata.decodeBatch(); - _execute(msg.sender, executions); - } else if (callType == CALLTYPE_SINGLE) { - (address target, uint256 value, bytes calldata callData) = - executionCalldata.decodeSingle(); - _execute(msg.sender, target, value, callData); - } else if (callType == CALLTYPE_DELEGATECALL) { - address target = address(bytes20(executionCalldata[:20])); - bytes calldata callData = executionCalldata[20:]; - _executeDelegateCall(msg.sender, target, callData); - } else { - revert UnsupportedCallType(callType); + CallType callType; + ExecType execType; + assembly { + callType := mode + execType := shl(8, mode) + } + + if (execType == EXECTYPE_DEFAULT) { + if (callType == CALLTYPE_BATCH) { + Execution[] calldata executions = executionCalldata.decodeBatch(); + _execute(msg.sender, executions); + } else if (callType == CALLTYPE_SINGLE) { + (address target, uint256 value, bytes calldata callData) = + executionCalldata.decodeSingle(); + _execute(msg.sender, target, value, callData); + } else if (callType == CALLTYPE_DELEGATECALL) { + address target = address(bytes20(executionCalldata[:20])); + bytes calldata callData = executionCalldata[20:]; + _executeDelegateCall(msg.sender, target, callData); + } else { + revert UnsupportedCallType(callType); + } + } else if (execType == EXECTYPE_TRY) { + if (callType == CALLTYPE_BATCH) { + Execution[] calldata executions = executionCalldata.decodeBatch(); + _tryExecute(msg.sender, executions); + } else if (callType == CALLTYPE_SINGLE) { + (address target, uint256 value, bytes calldata callData) = + executionCalldata.decodeSingle(); + _tryExecute(msg.sender, target, value, callData); + } else if (callType == CALLTYPE_DELEGATECALL) { + address target = address(bytes20(executionCalldata[:20])); + bytes calldata callData = executionCalldata[20:]; + _tryExecuteDelegateCall(msg.sender, target, callData); + } else { + revert UnsupportedCallType(callType); + } + } + // account reverts when using unsupported execution type + else { + revert UnsupportedExecType(execType); } } @@ -106,26 +135,54 @@ contract SafeERC7579 is payable override onlyExecutorModule + withRegistry(msg.sender, MODULE_TYPE_EXECUTOR) withHook // ! this modifier has side effects / external calls returns (bytes[] memory returnData) { - CallType callType = mode.getCallType(); - - if (callType == CALLTYPE_BATCH) { - Execution[] calldata executions = executionCalldata.decodeBatch(); - returnData = _executeReturnData(msg.sender, executions); - } else if (callType == CALLTYPE_SINGLE) { - (address target, uint256 value, bytes calldata callData) = - executionCalldata.decodeSingle(); - returnData = new bytes[](1); - returnData[0] = _executeReturnData(msg.sender, target, value, callData); - } else if (callType == CALLTYPE_DELEGATECALL) { - address target = address(bytes20(executionCalldata[:20])); - bytes calldata callData = executionCalldata[20:]; - returnData = new bytes[](1); - returnData[0] = _executeDelegateCallReturnData(msg.sender, target, callData); - } else { - revert UnsupportedCallType(callType); + CallType callType; + ExecType execType; + assembly { + callType := mode + execType := shl(8, mode) + } + if (execType == EXECTYPE_DEFAULT) { + if (callType == CALLTYPE_BATCH) { + Execution[] calldata executions = executionCalldata.decodeBatch(); + returnData = _executeReturnData(msg.sender, executions); + } else if (callType == CALLTYPE_SINGLE) { + (address target, uint256 value, bytes calldata callData) = + executionCalldata.decodeSingle(); + returnData = new bytes[](1); + returnData[0] = _executeReturnData(msg.sender, target, value, callData); + } else if (callType == CALLTYPE_DELEGATECALL) { + address target = address(bytes20(executionCalldata[:20])); + bytes calldata callData = executionCalldata[20:]; + returnData = new bytes[](1); + returnData[0] = _executeDelegateCallReturnData(msg.sender, target, callData); + } else { + revert UnsupportedCallType(callType); + } + } else if (execType == EXECTYPE_TRY) { + if (callType == CALLTYPE_BATCH) { + Execution[] calldata executions = executionCalldata.decodeBatch(); + returnData = _tryExecuteReturnData(msg.sender, executions); + } else if (callType == CALLTYPE_SINGLE) { + (address target, uint256 value, bytes calldata callData) = + executionCalldata.decodeSingle(); + returnData = new bytes[](1); + returnData[0] = _tryExecuteReturnData(msg.sender, target, value, callData); + } else if (callType == CALLTYPE_DELEGATECALL) { + address target = address(bytes20(executionCalldata[:20])); + bytes calldata callData = executionCalldata[20:]; + returnData = new bytes[](1); + returnData[0] = _tryExecuteDelegateCallReturnData(msg.sender, target, callData); + } else { + revert UnsupportedCallType(callType); + } + } + // account reverts when using unsupported execution type + else { + revert UnsupportedExecType(execType); } } @@ -444,7 +501,6 @@ contract SafeERC7579 is validators.offset := add(dataPointer, 32) validators.length := calldataload(dataPointer) } - // initializeAccount(validators); } function initializeAccountWithRegistry( diff --git a/accounts/safe7579/src/core/ExecutionHelper.sol b/accounts/safe7579/src/core/ExecutionHelper.sol index 52c1e473..4ec6d337 100644 --- a/accounts/safe7579/src/core/ExecutionHelper.sol +++ b/accounts/safe7579/src/core/ExecutionHelper.sol @@ -10,19 +10,24 @@ import { /** * @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(); + event TryExecutionFailed(uint256 numberInBatch); + SimulateTxAccessor private immutable SIMULATETX; constructor() { SIMULATETX = new SimulateTxAccessor(); } + ///////////////////////////////////////////////////// + // DEFAULT EXEC TYPE + //////////////////////////////////////////////////// + /** * Execute call on Safe * @dev This function will revert if the call fails @@ -123,6 +128,128 @@ abstract contract ExecutionHelper { } } + ///////////////////////////////////////////////////// + // TRY EXEC TYPE + //////////////////////////////////////////////////// + + /** + * Try 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 _tryExecute( + address safe, + address target, + uint256 value, + bytes memory callData + ) + internal + { + bool success = ISafe(safe).execTransactionFromModule(target, value, callData, 0); + if (!success) emit TryExecutionFailed(0); + } + + /** + * Try 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 _tryExecuteReturnData( + 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) emit TryExecutionFailed(0); + } + + /** + * Try 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 _tryExecute(address safe, Execution[] calldata executions) internal { + uint256 length = executions.length; + for (uint256 i; i < length; i++) { + Execution calldata execution = executions[i]; + + bool success = ISafe(safe).execTransactionFromModule( + execution.target, execution.value, execution.callData, 0 + ); + if (!success) emit TryExecutionFailed(i); + } + } + + function _tryExecuteDelegateCall( + address safe, + address target, + bytes calldata callData + ) + internal + { + bool success = ISafe(safe).execTransactionFromModule(target, 0, callData, 1); + if (!success) emit TryExecutionFailed(0); + } + + function _tryExecuteDelegateCallReturnData( + address safe, + address target, + bytes calldata callData + ) + internal + returns (bytes memory returnData) + { + bool success; + (success, returnData) = + ISafe(safe).execTransactionFromModuleReturnData(target, 0, callData, 1); + if (!success) emit TryExecutionFailed(0); + } + + /** + * 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 _tryExecuteReturnData( + 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]; + + bool success; + (success, returnDatas[i]) = ISafe(safe).execTransactionFromModuleReturnData( + execution.target, execution.value, execution.callData, 0 + ); + if (!success) emit TryExecutionFailed(i); + } + } + + ///////////////////////////////////////////////////// + // STATICCALL + //////////////////////////////////////////////////// + /** * Execute staticcall on Safe, get return value from call * Safe does not implement Enum.Operation for staticcall. diff --git a/accounts/safe7579/test/Base.t.sol b/accounts/safe7579/test/Base.t.sol index 75d9ccde..d9bd7fd9 100644 --- a/accounts/safe7579/test/Base.t.sol +++ b/accounts/safe7579/test/Base.t.sol @@ -7,12 +7,12 @@ 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 { MockTarget } from "./mocks/MockTarget.sol"; import { Safe } from "@safe-global/safe-contracts/contracts/Safe.sol"; import { SafeProxyFactory } from "@safe-global/safe-contracts/contracts/proxies/SafeProxyFactory.sol"; -import { LibClone } from "solady/src/utils/LibClone.sol"; +import { LibClone } from "solady/utils/LibClone.sol"; import "src/utils/Launchpad.sol"; import { Solarray } from "solarray/Solarray.sol"; diff --git a/accounts/safe7579/test/Launchpad.t.sol b/accounts/safe7579/test/Launchpad.t.sol index c78363b2..22e72d4a 100644 --- a/accounts/safe7579/test/Launchpad.t.sol +++ b/accounts/safe7579/test/Launchpad.t.sol @@ -8,14 +8,14 @@ import { MockValidator } from "./mocks/MockValidator.sol"; import { MockRegistry } from "./mocks/MockRegistry.sol"; import { MockExecutor } from "./mocks/MockExecutor.sol"; import { MockFallback } from "./mocks/MockFallback.sol"; -import { MockTarget } from "@rhinestone/modulekit/src/mocks/MockTarget.sol"; +import { MockTarget } from "./mocks/MockTarget.sol"; import { Safe } from "@safe-global/safe-contracts/contracts/Safe.sol"; import { SafeProxy, SafeProxyFactory } from "@safe-global/safe-contracts/contracts/proxies/SafeProxyFactory.sol"; -import { LibClone } from "solady/src/utils/LibClone.sol"; +import { LibClone } from "solady/utils/LibClone.sol"; import "src/utils/Launchpadv2.sol"; import "src/utils/SignerFactory.sol"; import "src/interfaces/ISafe7579Init.sol"; diff --git a/accounts/safe7579/test/mocks/MockTarget.sol b/accounts/safe7579/test/mocks/MockTarget.sol new file mode 100644 index 00000000..06c2cbe3 --- /dev/null +++ b/accounts/safe7579/test/mocks/MockTarget.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +contract MockTarget { + uint256 public value; + + function set(uint256 _value) public returns (uint256) { + value = _value; + return _value; + } + + function setAccessControl(uint256 _value) public returns (uint256) { + if (msg.sender != address(this)) { + revert("MockTarget: not authorized"); + } + value = _value; + return _value; + } +} From 6fcb644ef52f1a4a771f2f773bb55b2bddaf2ed8 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Mon, 8 Apr 2024 10:41:21 +0700 Subject: [PATCH 29/64] chore: fixing deps and tests clean --- accounts/safe7579/foundry.toml | 2 +- accounts/safe7579/package.json | 2 +- accounts/safe7579/remappings.txt | 4 +- accounts/safe7579/src/SafeERC7579.sol | 20 +- accounts/safe7579/test/Launchpad.t.sol | 2 + accounts/safe7579/test/SafeERC7579.t.sol | 54 +- pnpm-lock.yaml | 4893 +++++++--------------- 7 files changed, 1614 insertions(+), 3363 deletions(-) diff --git a/accounts/safe7579/foundry.toml b/accounts/safe7579/foundry.toml index 962d64a6..7644348e 100644 --- a/accounts/safe7579/foundry.toml +++ b/accounts/safe7579/foundry.toml @@ -1,7 +1,7 @@ [profile.default] src = "src" out = "out" -libs = ["lib"] +libs = ["node_modules"] fs_permissions = [{ access = "read", path = "out-optimized" }] allow_paths = ["*", "/"] diff --git a/accounts/safe7579/package.json b/accounts/safe7579/package.json index 6d0df445..ef1a54f9 100644 --- a/accounts/safe7579/package.json +++ b/accounts/safe7579/package.json @@ -21,8 +21,8 @@ "@prb/math": "^4.0.2", "forge-std": "github:foundry-rs/forge-std", "ds-test": "github:dapphub/ds-test", - "erc7579": "github:erc7579/erc7579-implementation", "sentinellist": "github:zeroknots/sentinellist", + "erc7579": "github:erc7579/erc7579-implementation", "solady": "github:vectorized/solady", "solarray": "github:sablier-labs/solarray", "solmate": "github:transmissions11/solmate", diff --git a/accounts/safe7579/remappings.txt b/accounts/safe7579/remappings.txt index 24b26f77..dc197035 100644 --- a/accounts/safe7579/remappings.txt +++ b/accounts/safe7579/remappings.txt @@ -5,8 +5,10 @@ account-abstraction-v0.6/=node_modules/@ERC4337/account-abstraction-v0.6/contrac erc7579/=node_modules/erc7579/src/ sentinellist/=node_modules/sentinellist/src/ solmate/=node_modules/solmate/src/ -solady/=node_modules/solady/ +solady/=node_modules/solady/src/ solarray/=node_modules/solarray/src/ +@rhinestone/modulekit/=node_modules/@rhinestone/modulekit/packages/modulekit/ +@rhinestone/sessionkeymanager/=node_modules/@rhinestone/modulekit/packages/sessionkeymanager/ @rhinestone/=node_modules/@rhinestone/ @safe-global/=node_modules/@safe-global/ @ERC4337/=node_modules/@ERC4337/ diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index 374dd2dd..2f751f02 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -35,6 +35,8 @@ import { IEntryPoint } from "@ERC4337/account-abstraction/contracts/interfaces/I import { ISafe7579Init } from "./interfaces/ISafe7579Init.sol"; import { IERC1271 } from "./interfaces/IERC1271.sol"; import { IERC7484 } from "./interfaces/IERC7484.sol"; + +import "forge-std/console2.sol"; /** * @title ERC7579 Adapter for Safe accounts. * By using Safe's Fallback and Execution modules, @@ -187,14 +189,10 @@ contract SafeERC7579 is } /** - * @inheritdoc IERC7579Account - */ - function executeUserOp(PackedUserOperation calldata /*userOp*/ ) external payable override { - revert Unsupported(); - } - - /** - * @inheritdoc IERC7579Account + * ERC4337 v0.7 validation function + * @dev expects that a ERC7579 validator module is encoded within the UserOp nonce. + * if no validator module is provided, it will fallback to validate the transaction with + * Safe's signers */ function validateUserOp( PackedUserOperation calldata userOp, @@ -203,7 +201,6 @@ contract SafeERC7579 is ) external payable - override returns (uint256 validSignature) { address validator; @@ -319,7 +316,6 @@ contract SafeERC7579 is payable override withHook - // withRegistry(module, moduleType) onlyEntryPointOrSelf { if (moduleType == MODULE_TYPE_VALIDATOR) _installValidator(module, initData); @@ -548,13 +544,13 @@ contract SafeERC7579 is length = executors.length; for (uint256 i; i < length; i++) { ModuleInit calldata executor = executors[i]; - _installValidator(executor.module, executor.initData); + _installExecutor(executor.module, executor.initData); } length = fallbacks.length; for (uint256 i; i < length; i++) { ModuleInit calldata _fallback = fallbacks[i]; - _installValidator(_fallback.module, _fallback.initData); + _installFallbackHandler(_fallback.module, _fallback.initData); } _installHook(hook.module, hook.initData); diff --git a/accounts/safe7579/test/Launchpad.t.sol b/accounts/safe7579/test/Launchpad.t.sol index 22e72d4a..f8206962 100644 --- a/accounts/safe7579/test/Launchpad.t.sol +++ b/accounts/safe7579/test/Launchpad.t.sol @@ -143,6 +143,8 @@ contract LaunchpadBase is Test { deal(address(userOp.sender), 1 ether); entrypoint.handleOps(userOps, payable(address(0x69))); + + safe = Safe(payable(predict)); } function _initCode( diff --git a/accounts/safe7579/test/SafeERC7579.t.sol b/accounts/safe7579/test/SafeERC7579.t.sol index 3966c9c1..bc5f1ea5 100644 --- a/accounts/safe7579/test/SafeERC7579.t.sol +++ b/accounts/safe7579/test/SafeERC7579.t.sol @@ -4,13 +4,11 @@ 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"; +import "./Launchpad.t.sol"; import "forge-std/console2.sol"; -CallType constant CALLTYPE_STATIC = CallType.wrap(0xFE); - -contract Safe7579Test is TestBaseUtil { +contract Safe7579Test is LaunchpadBase { MockTarget target; function setUp() public override { @@ -18,45 +16,7 @@ contract Safe7579Test is TestBaseUtil { target = new MockTarget(); } - modifier alreadyInitialized(bool initNow) { - if (initNow) { - test_initializeAccount(); - } - _; - } - - function test_initializeAccount() public { - PackedUserOperation memory userOp = - getDefaultUserOp(address(safe), address(defaultValidator)); - - // Create calldata for the account to execute - bytes memory setValueOnTarget = abi.encodeCall(MockTarget.set, 777); - - // 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) - ) - ); - 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() == 777); - userOpInitCode = ""; - } - - function test_execSingle(bool withInitializedAccount) - public - alreadyInitialized(withInitializedAccount) - { + function test_execSingle() public { // Create calldata for the account to execute bytes memory setValueOnTarget = abi.encodeCall(MockTarget.set, 1337); @@ -85,10 +45,7 @@ contract Safe7579Test is TestBaseUtil { assertTrue(target.value() == 1337); } - function test_execBatch(bool withInitializedAccount) - public - alreadyInitialized(withInitializedAccount) - { + function test_execBatch() public { // Create calldata for the account to execute bytes memory setValueOnTarget = abi.encodeCall(MockTarget.set, 1337); address target2 = address(0x420); @@ -123,7 +80,6 @@ contract Safe7579Test is TestBaseUtil { } function test_execViaExecutor() public { - test_initializeAccount(); defaultExecutor.executeViaAccount( IERC7579Account(address(safe)), address(target), @@ -133,7 +89,6 @@ contract Safe7579Test is TestBaseUtil { } function test_execBatchFromExecutor() public { - test_initializeAccount(); bytes memory setValueOnTarget = abi.encodeCall(MockTarget.set, 1338); Execution[] memory executions = new Execution[](2); executions[0] = Execution({ target: address(target), value: 0, callData: setValueOnTarget }); @@ -148,7 +103,6 @@ contract Safe7579Test is TestBaseUtil { } function test_fallback() public { - test_initializeAccount(); MockFallback _fallback = new MockFallback(); vm.prank(address(safe)); IERC7579Account(address(safe)).installModule( diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f894f4c9..3f45b6d0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,19 +1,20 @@ -lockfileVersion: "6.0" +lockfileVersion: '6.0' settings: autoInstallPeers: true excludeLinksFromLockfile: false importers: + .: devDependencies: - "@rhinestone/modulekit": + '@rhinestone/modulekit': specifier: workspace:* - version: link:packages/modulekit - "@rhinestone/safe7579": + version: 'link:' + '@rhinestone/safe7579': specifier: workspace:* version: link:accounts/safe7579 - "@rhinestone/sessionkeymanager": + '@rhinestone/sessionkeymanager': specifier: workspace:* version: link:packages/SessionKeyManager prettier: @@ -21,29 +22,29 @@ importers: version: 2.8.8 solhint: specifier: ^4.1.1 - version: 4.1.1(typescript@5.3.3) + version: 4.1.1(typescript@5.4.4) accounts/safe7579: devDependencies: - "@ERC4337/account-abstraction": + '@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": + version: github.com/kopy-kat/account-abstraction/3c0127e9f7cb76e4a0fdb2d35cac51900f252bdc(ethers@5.4.0)(hardhat@2.22.2)(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": + version: github.com/eth-infinitism/account-abstraction/7174d6d845618dbd11cee68eefa715f5263690b6(ethers@5.4.0)(hardhat@2.22.2)(lodash@4.17.21)(typechain@5.2.0) + '@openzeppelin/contracts': specifier: 5.0.1 version: 5.0.1 - "@prb/math": + '@prb/math': specifier: ^4.0.2 version: 4.0.2 - "@rhinestone/modulekit": + '@rhinestone/modulekit': specifier: workspace:* - version: link:../../packages/modulekit - "@rhinestone/sessionkeymanager": + version: link:../.. + '@rhinestone/sessionkeymanager': specifier: workspace:* version: link:../../packages/SessionKeyManager - "@safe-global/safe-contracts": + '@safe-global/safe-contracts': specifier: ^1.4.1 version: 1.4.1(ethers@5.4.0) ds-test: @@ -54,7 +55,7 @@ importers: version: github.com/rhinestonewtf/erc4337-validation/19a97d86f8f29709664334078925b2a843be19e0 erc7579: specifier: github:erc7579/erc7579-implementation - version: github.com/erc7579/erc7579-implementation/9b6b326bdb5df94f29091280b281a617084dfba1 + version: github.com/erc7579/erc7579-implementation/c28f305d96467200c44c1ee3af2a7bb184dc0420 forge-std: specifier: github:foundry-rs/forge-std version: github.com/foundry-rs/forge-std/1d0766bc5d814f117c7b1e643828f7d85024fb51 @@ -72,35 +73,35 @@ importers: version: github.com/sablier-labs/solarray/6bf10cb34cdace52a3ba5fe437e78cc82df92684 solhint: specifier: ^4.1.1 - version: 4.1.1(typescript@5.3.3) + version: 4.1.1(typescript@5.4.4) solmate: specifier: github:transmissions11/solmate version: github.com/transmissions11/solmate/c892309933b25c03d32b1b0d674df7ae292ba925 examples: devDependencies: - "@ERC4337/account-abstraction": + '@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": + version: github.com/kopy-kat/account-abstraction/3c0127e9f7cb76e4a0fdb2d35cac51900f252bdc(ethers@5.4.0)(hardhat@2.22.2)(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": + version: github.com/eth-infinitism/account-abstraction/7174d6d845618dbd11cee68eefa715f5263690b6(ethers@5.4.0)(hardhat@2.22.2)(lodash@4.17.21)(typechain@5.2.0) + '@openzeppelin/contracts': specifier: 5.0.1 version: 5.0.1 - "@prb/math": + '@prb/math': specifier: ^4.0.2 version: 4.0.2 - "@rhinestone/modulekit": + '@rhinestone/modulekit': specifier: workspace:* - version: link:../packages/modulekit - "@rhinestone/safe7579": + version: link:.. + '@rhinestone/safe7579': specifier: workspace:* version: link:../accounts/safe7579 - "@rhinestone/sessionkeymanager": + '@rhinestone/sessionkeymanager': specifier: workspace:* version: link:../packages/SessionKeyManager - "@safe-global/safe-contracts": + '@safe-global/safe-contracts': specifier: ^1.4.1 version: 1.4.1(ethers@5.4.0) ds-test: @@ -129,22 +130,22 @@ importers: version: github.com/sablier-labs/solarray/6bf10cb34cdace52a3ba5fe437e78cc82df92684 solhint: specifier: ^4.1.1 - version: 4.1.1(typescript@5.3.3) + version: 4.1.1(typescript@5.4.4) solmate: specifier: github:transmissions11/solmate version: github.com/transmissions11/solmate/c892309933b25c03d32b1b0d674df7ae292ba925 packages/SessionKeyManager: devDependencies: - "@ERC4337/account-abstraction": + '@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": + version: github.com/kopy-kat/account-abstraction/3c0127e9f7cb76e4a0fdb2d35cac51900f252bdc(ethers@5.7.2)(hardhat@2.22.2)(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": + version: github.com/eth-infinitism/account-abstraction/7174d6d845618dbd11cee68eefa715f5263690b6(ethers@5.7.2)(hardhat@2.22.2)(lodash@4.17.21)(typechain@5.2.0) + '@rhinestone/modulekit': specifier: workspace:* - version: link:../modulekit + version: link:../.. ds-test: specifier: github:dapphub/ds-test version: github.com/dapphub/ds-test/e282159d5170298eb2455a6c05280ab5a73a4ef0 @@ -165,29 +166,29 @@ importers: version: github.com/vectorized/solady/72e47ca417d24a30801b2921584e8486462cfc7b solhint: specifier: ^4.1.1 - version: 4.1.1(typescript@5.3.3) + version: 4.1.1(typescript@5.4.4) packages/modulekit: devDependencies: - "@ERC4337/account-abstraction": + '@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": + version: github.com/kopy-kat/account-abstraction/3c0127e9f7cb76e4a0fdb2d35cac51900f252bdc(ethers@5.4.0)(hardhat@2.22.2)(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": + version: github.com/eth-infinitism/account-abstraction/7174d6d845618dbd11cee68eefa715f5263690b6(ethers@5.4.0)(hardhat@2.22.2)(lodash@4.17.21)(typechain@5.2.0) + '@openzeppelin/contracts': specifier: 5.0.1 version: 5.0.1 - "@prb/math": + '@prb/math': specifier: ^4.0.2 version: 4.0.2 - "@rhinestone/safe7579": + '@rhinestone/safe7579': specifier: workspace:* version: link:../../accounts/safe7579 - "@rhinestone/sessionkeymanager": + '@rhinestone/sessionkeymanager': specifier: workspace:* version: link:../SessionKeyManager - "@safe-global/safe-contracts": + '@safe-global/safe-contracts': specifier: ^1.4.1 version: 1.4.1(ethers@5.4.0) ds-test: @@ -216,537 +217,412 @@ importers: version: github.com/sablier-labs/solarray/6bf10cb34cdace52a3ba5fe437e78cc82df92684 solhint: specifier: ^4.1.1 - version: 4.1.1(typescript@5.3.3) + version: 4.1.1(typescript@5.4.4) packages: + /@babel/code-frame@7.23.5: - resolution: - { - integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==, - } - engines: { node: ">=6.9.0" } + resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==} + engines: {node: '>=6.9.0'} dependencies: - "@babel/highlight": 7.23.4 + '@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" } + 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" } + resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==} + engines: {node: '>=6.9.0'} dependencies: - "@babel/helper-validator-identifier": 7.22.20 + '@babel/helper-validator-identifier': 7.22.20 chalk: 2.4.2 js-tokens: 4.0.0 dev: true /@ethereumjs/rlp@4.0.1: - resolution: - { - integrity: sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==, - } - engines: { node: ">=14" } + 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" } + resolution: {integrity: sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==} + engines: {node: '>=14'} dependencies: - "@ethereumjs/rlp": 4.0.1 + '@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 + resolution: {integrity: sha512-9gU2H+/yK1j2eVMdzm6xvHSnMxk8waIHQGYCZg5uvAyH0rsAzxkModzBSpbAkAuhKFEovC2S9hM4nPuLym8IZw==} + 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/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 + 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==, - } + 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 + '@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-provider@5.7.0: - resolution: - { - integrity: sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==, - } + 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 + '@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==, - } + 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 + '@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/abstract-signer@5.7.0: - resolution: - { - integrity: sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==, - } + 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 + '@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==, - } + 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 + '@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/address@5.7.0: - resolution: - { - integrity: sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==, - } + 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 + '@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==, - } + resolution: {integrity: sha512-CjQw6E17QDSSC5jiM9YpF7N1aSCHmYGMt9bWD8PWv6YPMxjsys2/Q8xLrROKI3IWJ7sFfZ8B3flKDTM5wlWuZQ==} dependencies: - "@ethersproject/bytes": 5.4.0 + '@ethersproject/bytes': 5.7.0 dev: true /@ethersproject/base64@5.7.0: - resolution: - { - integrity: sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==, - } + resolution: {integrity: sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==} dependencies: - "@ethersproject/bytes": 5.7.0 + '@ethersproject/bytes': 5.7.0 dev: true /@ethersproject/basex@5.4.0: - resolution: - { - integrity: sha512-J07+QCVJ7np2bcpxydFVf/CuYo9mZ7T73Pe7KQY4c1lRlrixMeblauMxHXD0MPwFmUHZIILDNViVkykFBZylbg==, - } + resolution: {integrity: sha512-J07+QCVJ7np2bcpxydFVf/CuYo9mZ7T73Pe7KQY4c1lRlrixMeblauMxHXD0MPwFmUHZIILDNViVkykFBZylbg==} dependencies: - "@ethersproject/bytes": 5.4.0 - "@ethersproject/properties": 5.4.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/properties': 5.7.0 dev: true /@ethersproject/basex@5.7.0: - resolution: - { - integrity: sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==, - } + resolution: {integrity: sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==} dependencies: - "@ethersproject/bytes": 5.7.0 - "@ethersproject/properties": 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/properties': 5.7.0 dev: true /@ethersproject/bignumber@5.4.0: - resolution: - { - integrity: sha512-OXUu9f9hO3vGRIPxU40cignXZVaYyfx6j9NNMjebKdnaCL3anCLSSy8/b8d03vY6dh7duCC0kW72GEC4tZer2w==, - } + resolution: {integrity: sha512-OXUu9f9hO3vGRIPxU40cignXZVaYyfx6j9NNMjebKdnaCL3anCLSSy8/b8d03vY6dh7duCC0kW72GEC4tZer2w==} dependencies: - "@ethersproject/bytes": 5.4.0 - "@ethersproject/logger": 5.4.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 bn.js: 4.12.0 dev: true /@ethersproject/bignumber@5.7.0: - resolution: - { - integrity: sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==, - } + resolution: {integrity: sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==} dependencies: - "@ethersproject/bytes": 5.7.0 - "@ethersproject/logger": 5.7.0 + '@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==, - } + resolution: {integrity: sha512-H60ceqgTHbhzOj4uRc/83SCN9d+BSUnOkrr2intevqdtEMO1JFVZ1XL84OEZV+QjV36OaZYxtnt4lGmxcGsPfA==} dependencies: - "@ethersproject/logger": 5.4.0 + '@ethersproject/logger': 5.7.0 dev: true /@ethersproject/bytes@5.7.0: - resolution: - { - integrity: sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==, - } + resolution: {integrity: sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==} dependencies: - "@ethersproject/logger": 5.7.0 + '@ethersproject/logger': 5.7.0 dev: true /@ethersproject/constants@5.4.0: - resolution: - { - integrity: sha512-tzjn6S7sj9+DIIeKTJLjK9WGN2Tj0P++Z8ONEIlZjyoTkBuODN+0VfhAyYksKi43l1Sx9tX2VlFfzjfmr5Wl3Q==, - } + resolution: {integrity: sha512-tzjn6S7sj9+DIIeKTJLjK9WGN2Tj0P++Z8ONEIlZjyoTkBuODN+0VfhAyYksKi43l1Sx9tX2VlFfzjfmr5Wl3Q==} dependencies: - "@ethersproject/bignumber": 5.4.0 + '@ethersproject/bignumber': 5.7.0 dev: true /@ethersproject/constants@5.7.0: - resolution: - { - integrity: sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==, - } + resolution: {integrity: sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==} dependencies: - "@ethersproject/bignumber": 5.7.0 + '@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 + resolution: {integrity: sha512-hkO3L3IhS1Z3ZtHtaAG/T87nQ7KiPV+/qnvutag35I0IkiQ8G3ZpCQ9NNOpSCzn4pWSW4CfzmtE02FcqnLI+hw==} + 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/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 + 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==, - } + 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 + '@ethersproject/abstract-signer': 5.7.0 + '@ethersproject/address': 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/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 + 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 + resolution: {integrity: sha512-pKxdS0KAaeVGfZPp1KOiDLB0jba11tG6OP1u11QnYfb7pXn6IZx0xceqWRr6ygke8+Kw74IpOoSi7/DwANhy8Q==} + 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/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 + 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 + resolution: {integrity: sha512-igWcu3fx4aiczrzEHwG1xJZo9l1cFfQOWzTqwRw/xcvxTk58q4f9M7cjh51EKphMHvrJtcezJ1gf1q1AUOfEQQ==} + 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/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 + 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==, - } + resolution: {integrity: sha512-FBI1plWet+dPUvAzPAeHzRKiPpETQzqSUWR1wXJGHVWi4i8bOSrpC3NwpkPjgeXG7MnugVc1B42VbfnQikyC/A==} dependencies: - "@ethersproject/bytes": 5.4.0 + '@ethersproject/bytes': 5.7.0 js-sha3: 0.5.7 dev: true /@ethersproject/keccak256@5.7.0: - resolution: - { - integrity: sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==, - } + resolution: {integrity: sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==} dependencies: - "@ethersproject/bytes": 5.7.0 + '@ethersproject/bytes': 5.7.0 js-sha3: 0.8.0 dev: true /@ethersproject/logger@5.4.0: - resolution: - { - integrity: sha512-xYdWGGQ9P2cxBayt64d8LC8aPFJk6yWCawQi/4eJ4+oJdMMjEBMrIcIMZ9AxhwpPVmnBPrsB10PcXGmGAqgUEQ==, - } + resolution: {integrity: sha512-xYdWGGQ9P2cxBayt64d8LC8aPFJk6yWCawQi/4eJ4+oJdMMjEBMrIcIMZ9AxhwpPVmnBPrsB10PcXGmGAqgUEQ==} dev: true /@ethersproject/logger@5.7.0: - resolution: - { - integrity: sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==, - } + resolution: {integrity: sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==} dev: true /@ethersproject/networks@5.4.0: - resolution: - { - integrity: sha512-5fywtKRDcnaVeA5SjxXH3DOQqe/IbeD/plwydi94SdPps1fbDUrnO6SzDExaruBZXxpxJcO9upG9UComsei4bg==, - } + resolution: {integrity: sha512-5fywtKRDcnaVeA5SjxXH3DOQqe/IbeD/plwydi94SdPps1fbDUrnO6SzDExaruBZXxpxJcO9upG9UComsei4bg==} dependencies: - "@ethersproject/logger": 5.4.0 + '@ethersproject/logger': 5.7.0 dev: true /@ethersproject/networks@5.7.1: - resolution: - { - integrity: sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==, - } + resolution: {integrity: sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==} dependencies: - "@ethersproject/logger": 5.7.0 + '@ethersproject/logger': 5.7.0 dev: true /@ethersproject/pbkdf2@5.4.0: - resolution: - { - integrity: sha512-x94aIv6tiA04g6BnazZSLoRXqyusawRyZWlUhKip2jvoLpzJuLb//KtMM6PEovE47pMbW+Qe1uw+68ameJjB7g==, - } + resolution: {integrity: sha512-x94aIv6tiA04g6BnazZSLoRXqyusawRyZWlUhKip2jvoLpzJuLb//KtMM6PEovE47pMbW+Qe1uw+68ameJjB7g==} dependencies: - "@ethersproject/bytes": 5.4.0 - "@ethersproject/sha2": 5.4.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/sha2': 5.7.0 dev: true /@ethersproject/pbkdf2@5.7.0: - resolution: - { - integrity: sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==, - } + resolution: {integrity: sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==} dependencies: - "@ethersproject/bytes": 5.7.0 - "@ethersproject/sha2": 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/sha2': 5.7.0 dev: true /@ethersproject/properties@5.4.0: - resolution: - { - integrity: sha512-7jczalGVRAJ+XSRvNA6D5sAwT4gavLq3OXPuV/74o3Rd2wuzSL035IMpIMgei4CYyBdialJMrTqkOnzccLHn4A==, - } + resolution: {integrity: sha512-7jczalGVRAJ+XSRvNA6D5sAwT4gavLq3OXPuV/74o3Rd2wuzSL035IMpIMgei4CYyBdialJMrTqkOnzccLHn4A==} dependencies: - "@ethersproject/logger": 5.4.0 + '@ethersproject/logger': 5.7.0 dev: true /@ethersproject/properties@5.7.0: - resolution: - { - integrity: sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==, - } + resolution: {integrity: sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==} dependencies: - "@ethersproject/logger": 5.7.0 + '@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 + resolution: {integrity: sha512-XRmI9syLnkNdLA8ikEeg0duxmwSWTTt9S+xabnTOyI51JPJyhQ0QUNT+wvmod218ebb7rLupHDPQ7UVe2/+Tjg==} + dependencies: + '@ethersproject/abstract-provider': 5.7.0 + '@ethersproject/abstract-signer': 5.7.0 + '@ethersproject/address': 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: @@ -755,29 +631,26 @@ packages: 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 + 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: @@ -786,311 +659,239 @@ packages: dev: true /@ethersproject/random@5.4.0: - resolution: - { - integrity: sha512-pnpWNQlf0VAZDEOVp1rsYQosmv2o0ITS/PecNw+mS2/btF8eYdspkN0vIXrCMtkX09EAh9bdk8GoXmFXM1eAKw==, - } + resolution: {integrity: sha512-pnpWNQlf0VAZDEOVp1rsYQosmv2o0ITS/PecNw+mS2/btF8eYdspkN0vIXrCMtkX09EAh9bdk8GoXmFXM1eAKw==} dependencies: - "@ethersproject/bytes": 5.4.0 - "@ethersproject/logger": 5.4.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 dev: true /@ethersproject/random@5.7.0: - resolution: - { - integrity: sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==, - } + resolution: {integrity: sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==} dependencies: - "@ethersproject/bytes": 5.7.0 - "@ethersproject/logger": 5.7.0 + '@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==, - } + resolution: {integrity: sha512-0I7MZKfi+T5+G8atId9QaQKHRvvasM/kqLyAH4XxBCBchAooH2EX5rL9kYZWwcm3awYV+XC7VF6nLhfeQFKVPg==} dependencies: - "@ethersproject/bytes": 5.4.0 - "@ethersproject/logger": 5.4.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 dev: true /@ethersproject/rlp@5.7.0: - resolution: - { - integrity: sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==, - } + resolution: {integrity: sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==} dependencies: - "@ethersproject/bytes": 5.7.0 - "@ethersproject/logger": 5.7.0 + '@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==, - } + resolution: {integrity: sha512-siheo36r1WD7Cy+bDdE1BJ8y0bDtqXCOxRMzPa4bV1TGt/eTUUt03BHoJNB6reWJD8A30E/pdJ8WFkq+/uz4Gg==} dependencies: - "@ethersproject/bytes": 5.4.0 - "@ethersproject/logger": 5.4.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 hash.js: 1.1.7 dev: true /@ethersproject/sha2@5.7.0: - resolution: - { - integrity: sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==, - } + resolution: {integrity: sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==} dependencies: - "@ethersproject/bytes": 5.7.0 - "@ethersproject/logger": 5.7.0 + '@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 + resolution: {integrity: sha512-q8POUeywx6AKg2/jX9qBYZIAmKSB4ubGXdQ88l40hmATj29JnG5pp331nAWwwxPn2Qao4JpWHNZsQN+bPiSW9A==} + dependencies: + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/properties': 5.7.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 + 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==, - } + 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 + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/keccak256': 5.7.0 + '@ethersproject/sha2': 5.7.0 + '@ethersproject/strings': 5.7.0 dev: true /@ethersproject/solidity@5.7.0: - resolution: - { - integrity: sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==, - } + 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 + '@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==, - } + resolution: {integrity: sha512-k/9DkH5UGDhv7aReXLluFG5ExurwtIpUfnDNhQA29w896Dw3i4uDTz01Quaptbks1Uj9kI8wo9tmW73wcIEaWA==} dependencies: - "@ethersproject/bytes": 5.4.0 - "@ethersproject/constants": 5.4.0 - "@ethersproject/logger": 5.4.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/constants': 5.7.0 + '@ethersproject/logger': 5.7.0 dev: true /@ethersproject/strings@5.7.0: - resolution: - { - integrity: sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==, - } + resolution: {integrity: sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==} dependencies: - "@ethersproject/bytes": 5.7.0 - "@ethersproject/constants": 5.7.0 - "@ethersproject/logger": 5.7.0 + '@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 + resolution: {integrity: sha512-s3EjZZt7xa4BkLknJZ98QGoIza94rVjaEed0rzZ/jB9WrIuu/1+tjvYCWzVrystXtDswy7TPBeIepyXwSYa4WQ==} + 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/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 + 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==, - } + resolution: {integrity: sha512-Z88krX40KCp+JqPCP5oPv5p750g+uU6gopDYRTBGcDvOASh6qhiEYCRatuM/suC4S2XW9Zz90QI35MfSrTIaFg==} dependencies: - "@ethersproject/bignumber": 5.4.0 - "@ethersproject/constants": 5.4.0 - "@ethersproject/logger": 5.4.0 + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/constants': 5.7.0 + '@ethersproject/logger': 5.7.0 dev: true /@ethersproject/units@5.7.0: - resolution: - { - integrity: sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==, - } + resolution: {integrity: sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==} dependencies: - "@ethersproject/bignumber": 5.7.0 - "@ethersproject/constants": 5.7.0 - "@ethersproject/logger": 5.7.0 + '@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 + resolution: {integrity: sha512-wU29majLjM6AjCjpat21mPPviG+EpK7wY1+jzKD0fg3ui5fgedf2zEu1RDgpfIMsfn8fJHJuzM4zXZ2+hSHaSQ==} + 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/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 + 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==, - } + 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 + '@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/web@5.7.1: - resolution: - { - integrity: sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==, - } + 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 + '@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==, - } + 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 + '@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 /@ethersproject/wordlists@5.7.0: - resolution: - { - integrity: sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==, - } + 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 + '@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" } + /@fastify/busboy@2.1.1: + resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} + engines: {node: '>=14'} dev: true /@gnosis.pm/safe-contracts@1.3.0(ethers@5.4.0): - resolution: - { - integrity: sha512-1p+1HwGvxGUVzVkFjNzglwHrLNA67U/axP0Ct85FzzH8yhGJb4t9jDjPYocVMzLorDoWAfKicGy1akPY9jXRVw==, - } + resolution: {integrity: sha512-1p+1HwGvxGUVzVkFjNzglwHrLNA67U/axP0Ct85FzzH8yhGJb4t9jDjPYocVMzLorDoWAfKicGy1akPY9jXRVw==} peerDependencies: ethers: ^5.1.4 dependencies: @@ -1098,10 +899,7 @@ packages: dev: true /@gnosis.pm/safe-contracts@1.3.0(ethers@5.7.2): - resolution: - { - integrity: sha512-1p+1HwGvxGUVzVkFjNzglwHrLNA67U/axP0Ct85FzzH8yhGJb4t9jDjPYocVMzLorDoWAfKicGy1akPY9jXRVw==, - } + resolution: {integrity: sha512-1p+1HwGvxGUVzVkFjNzglwHrLNA67U/axP0Ct85FzzH8yhGJb4t9jDjPYocVMzLorDoWAfKicGy1akPY9jXRVw==} peerDependencies: ethers: ^5.1.4 dependencies: @@ -1109,11 +907,8 @@ packages: dev: true /@metamask/eth-sig-util@4.0.1: - resolution: - { - integrity: sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ==, - } - engines: { node: ">=12.0.0" } + resolution: {integrity: sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ==} + engines: {node: '>=12.0.0'} dependencies: ethereumjs-abi: 0.6.8 ethereumjs-util: 6.2.1 @@ -1123,283 +918,186 @@ packages: dev: true /@noble/curves@1.3.0: - resolution: - { - integrity: sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA==, - } + resolution: {integrity: sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA==} dependencies: - "@noble/hashes": 1.3.3 + '@noble/hashes': 1.3.3 dev: true /@noble/hashes@1.2.0: - resolution: - { - integrity: sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==, - } + 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" } + 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==, - } + 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" } + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} dependencies: - "@nodelib/fs.stat": 2.0.5 + '@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" } + 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" } + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} dependencies: - "@nodelib/fs.scandir": 2.1.5 + '@nodelib/fs.scandir': 2.1.5 fastq: 1.17.1 dev: true - /@nomicfoundation/ethereumjs-block@5.0.4: - resolution: - { - integrity: sha512-AcyacJ9eX/uPEvqsPiB+WO1ymE+kyH48qGGiGV+YTojdtas8itUTW5dehDSOXEEItWGbbzEJ4PRqnQZlWaPvDw==, - } - engines: { node: ">=18" } - dependencies: - "@nomicfoundation/ethereumjs-common": 4.0.4 - "@nomicfoundation/ethereumjs-rlp": 5.0.4 - "@nomicfoundation/ethereumjs-trie": 6.0.4 - "@nomicfoundation/ethereumjs-tx": 5.0.4 - "@nomicfoundation/ethereumjs-util": 9.0.4 - ethereum-cryptography: 0.1.3 - transitivePeerDependencies: - - c-kzg + /@nomicfoundation/edr-darwin-arm64@0.3.3: + resolution: {integrity: sha512-E9VGsUD+1Ga4mn/5ooHsMi8JEfhZbKP6CXN/BhJ8kXbIC10NqTD1RuhCKGRtYq4vqH/3Nfq25Xg8E8RWOF4KBQ==} + engines: {node: '>= 18'} + cpu: [arm64] + os: [darwin] + requiresBuild: true dev: true + optional: true - /@nomicfoundation/ethereumjs-blockchain@7.0.4: - resolution: - { - integrity: sha512-jYsd/kwzbmpnxx86tXsYV8wZ5xGvFL+7/P0c6OlzpClHsbFzeF41KrYA9scON8Rg6bZu3ZTv6JOAgj3t7USUfg==, - } - engines: { node: ">=18" } - dependencies: - "@nomicfoundation/ethereumjs-block": 5.0.4 - "@nomicfoundation/ethereumjs-common": 4.0.4 - "@nomicfoundation/ethereumjs-ethash": 3.0.4 - "@nomicfoundation/ethereumjs-rlp": 5.0.4 - "@nomicfoundation/ethereumjs-trie": 6.0.4 - "@nomicfoundation/ethereumjs-tx": 5.0.4 - "@nomicfoundation/ethereumjs-util": 9.0.4 - debug: 4.3.4(supports-color@8.1.1) - ethereum-cryptography: 0.1.3 - lru-cache: 10.2.0 - transitivePeerDependencies: - - c-kzg - - supports-color + /@nomicfoundation/edr-darwin-x64@0.3.3: + resolution: {integrity: sha512-vkZXZ1ydPg+Ijb2iyqENA+KCkxGTCUWG5itCSliiA0Li2YE7ujDMGhheEpFp1WVlZadviz0bfk1rZXbCqlirpg==} + engines: {node: '>= 18'} + cpu: [x64] + os: [darwin] + requiresBuild: true dev: true + optional: true - /@nomicfoundation/ethereumjs-common@4.0.4: - resolution: - { - integrity: sha512-9Rgb658lcWsjiicr5GzNCjI1llow/7r0k50dLL95OJ+6iZJcVbi15r3Y0xh2cIO+zgX0WIHcbzIu6FeQf9KPrg==, - } - dependencies: - "@nomicfoundation/ethereumjs-util": 9.0.4 - transitivePeerDependencies: - - c-kzg + /@nomicfoundation/edr-linux-arm64-gnu@0.3.3: + resolution: {integrity: sha512-gdIg0Yj1qqS9wVuywc5B/+DqKylfUGB6/CQn/shMqwAfsAVAVpchkhy66PR+REEx7fh/GkNctxLlENXPeLzDiA==} + engines: {node: '>= 18'} + cpu: [arm64] + os: [linux] + requiresBuild: true dev: true + optional: true - /@nomicfoundation/ethereumjs-ethash@3.0.4: - resolution: - { - integrity: sha512-xvIrwIMl9sSaiYKRem68+O7vYdj7Q2XWv5P7JXiIkn83918QzWHvqbswTRsH7+r6X1UEvdsURRnZbvZszEjAaQ==, - } - engines: { node: ">=18" } - dependencies: - "@nomicfoundation/ethereumjs-block": 5.0.4 - "@nomicfoundation/ethereumjs-rlp": 5.0.4 - "@nomicfoundation/ethereumjs-util": 9.0.4 - bigint-crypto-utils: 3.3.0 - ethereum-cryptography: 0.1.3 - transitivePeerDependencies: - - c-kzg + /@nomicfoundation/edr-linux-arm64-musl@0.3.3: + resolution: {integrity: sha512-AXZ08MFvhNeBZbOBNmz1SJ/DMrMOE2mHEJtaNnsctlxIunjxfrWww4q+WXB34jbr9iaVYYlPsaWe5sueuw6s3Q==} + engines: {node: '>= 18'} + cpu: [arm64] + os: [linux] + requiresBuild: true dev: true + optional: true - /@nomicfoundation/ethereumjs-evm@2.0.4(@nomicfoundation/ethereumjs-verkle@0.0.2): - resolution: - { - integrity: sha512-lTyZZi1KpeMHzaO6cSVisR2tjiTTedjo7PcmhI/+GNFo9BmyY6QYzGeSti0sFttmjbEMioHgXxl5yrLNRg6+1w==, - } - engines: { node: ">=18" } - dependencies: - "@nomicfoundation/ethereumjs-common": 4.0.4 - "@nomicfoundation/ethereumjs-statemanager": 2.0.4(@nomicfoundation/ethereumjs-verkle@0.0.2) - "@nomicfoundation/ethereumjs-tx": 5.0.4 - "@nomicfoundation/ethereumjs-util": 9.0.4 - "@types/debug": 4.1.12 - debug: 4.3.4(supports-color@8.1.1) - ethereum-cryptography: 0.1.3 - rustbn-wasm: 0.2.0 - transitivePeerDependencies: - - "@nomicfoundation/ethereumjs-verkle" - - c-kzg - - supports-color + /@nomicfoundation/edr-linux-x64-gnu@0.3.3: + resolution: {integrity: sha512-xElOs1U+E6lBLtv1mnJ+E8nr2MxZgKiLo8bZAgBboy9odYtmkDVwhMjtsFKSuZbGxFtsSyGRT4cXw3JAbtUDeA==} + engines: {node: '>= 18'} + cpu: [x64] + os: [linux] + requiresBuild: true dev: true + optional: true - /@nomicfoundation/ethereumjs-rlp@5.0.4: - resolution: - { - integrity: sha512-8H1S3s8F6QueOc/X92SdrA4RDenpiAEqMg5vJH99kcQaCy/a3Q6fgseo75mgWlbanGJXSlAPtnCeG9jvfTYXlw==, - } - engines: { node: ">=18" } - hasBin: true + /@nomicfoundation/edr-linux-x64-musl@0.3.3: + resolution: {integrity: sha512-2Fe6gwm1RAGQ/PfMYiaSba2OrFp8zzYWh+am9lYObOFjV9D+A1zhIzfy0UC74glPks5eV8eY4pBPrVR042m2Nw==} + engines: {node: '>= 18'} + cpu: [x64] + os: [linux] + requiresBuild: true dev: true + optional: true - /@nomicfoundation/ethereumjs-statemanager@2.0.4(@nomicfoundation/ethereumjs-verkle@0.0.2): - resolution: - { - integrity: sha512-HPDjeFrxw6llEi+BzqXkZ+KkvFnTOPczuHBtk21hRlDiuKuZz32dPzlhpRsDBGV1b5JTmRDUVqCS1lp3Gghw4Q==, - } - peerDependencies: - "@nomicfoundation/ethereumjs-verkle": 0.0.2 - peerDependenciesMeta: - "@nomicfoundation/ethereumjs-verkle": - optional: true - dependencies: - "@nomicfoundation/ethereumjs-common": 4.0.4 - "@nomicfoundation/ethereumjs-rlp": 5.0.4 - "@nomicfoundation/ethereumjs-trie": 6.0.4 - "@nomicfoundation/ethereumjs-util": 9.0.4 - "@nomicfoundation/ethereumjs-verkle": 0.0.2 - debug: 4.3.4(supports-color@8.1.1) - ethereum-cryptography: 0.1.3 - js-sdsl: 4.4.2 - lru-cache: 10.2.0 - transitivePeerDependencies: - - c-kzg - - supports-color + /@nomicfoundation/edr-win32-arm64-msvc@0.3.3: + resolution: {integrity: sha512-8NHyxIsFrl0ufSQ/ErqF2lKIa/gz1gaaa1a2vKkDEqvqCUcPhBTYhA5NHgTPhLETFTnCFr0z+YbctFCyjh4qrA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@nomicfoundation/edr-win32-ia32-msvc@0.3.3: + resolution: {integrity: sha512-0F6hM0kGia4dQVb/kauho9JcP1ozWisY2/She+ISR5ceuhzmAwQJluM0g+0TYDME0LtxBxiMPq/yPiZMQeq31w==} + engines: {node: '>= 18'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@nomicfoundation/edr-win32-x64-msvc@0.3.3: + resolution: {integrity: sha512-d75q1uaMb6z9i+GQZoblbOfFBvlBnWc+5rB13UWRkCOJSnoYwyFWhGJx5GeM59gC7aIblc5VD9qOAhHuvM9N+w==} + engines: {node: '>= 18'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@nomicfoundation/edr@0.3.3: + resolution: {integrity: sha512-zP+e+3B1nEUx6bW5BPnIzCQbkhmYfdMBJdiVggTqqTfAA82sOkdOG7wsOMcz5qF3fYfx/irNRM1kgc9HVFIbpQ==} + engines: {node: '>= 18'} + optionalDependencies: + '@nomicfoundation/edr-darwin-arm64': 0.3.3 + '@nomicfoundation/edr-darwin-x64': 0.3.3 + '@nomicfoundation/edr-linux-arm64-gnu': 0.3.3 + '@nomicfoundation/edr-linux-arm64-musl': 0.3.3 + '@nomicfoundation/edr-linux-x64-gnu': 0.3.3 + '@nomicfoundation/edr-linux-x64-musl': 0.3.3 + '@nomicfoundation/edr-win32-arm64-msvc': 0.3.3 + '@nomicfoundation/edr-win32-ia32-msvc': 0.3.3 + '@nomicfoundation/edr-win32-x64-msvc': 0.3.3 dev: true - /@nomicfoundation/ethereumjs-trie@6.0.4: - resolution: - { - integrity: sha512-3nSwQiFMvr2VFe/aZUyinuohYvtytUqZCUCvIWcPJ/BwJH6oQdZRB42aNFBJ/8nAh2s3OcroWpBLskzW01mFKA==, - } - engines: { node: ">=18" } + /@nomicfoundation/ethereumjs-common@4.0.4: + resolution: {integrity: sha512-9Rgb658lcWsjiicr5GzNCjI1llow/7r0k50dLL95OJ+6iZJcVbi15r3Y0xh2cIO+zgX0WIHcbzIu6FeQf9KPrg==} dependencies: - "@nomicfoundation/ethereumjs-rlp": 5.0.4 - "@nomicfoundation/ethereumjs-util": 9.0.4 - "@types/readable-stream": 2.3.15 - ethereum-cryptography: 0.1.3 - lru-cache: 10.2.0 - readable-stream: 3.6.2 + '@nomicfoundation/ethereumjs-util': 9.0.4 transitivePeerDependencies: - c-kzg dev: true + /@nomicfoundation/ethereumjs-rlp@5.0.4: + resolution: {integrity: sha512-8H1S3s8F6QueOc/X92SdrA4RDenpiAEqMg5vJH99kcQaCy/a3Q6fgseo75mgWlbanGJXSlAPtnCeG9jvfTYXlw==} + engines: {node: '>=18'} + hasBin: true + dev: true + /@nomicfoundation/ethereumjs-tx@5.0.4: - resolution: - { - integrity: sha512-Xjv8wAKJGMrP1f0n2PeyfFCCojHd7iS3s/Ab7qzF1S64kxZ8Z22LCMynArYsVqiFx6rzYy548HNVEyI+AYN/kw==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-Xjv8wAKJGMrP1f0n2PeyfFCCojHd7iS3s/Ab7qzF1S64kxZ8Z22LCMynArYsVqiFx6rzYy548HNVEyI+AYN/kw==} + engines: {node: '>=18'} peerDependencies: c-kzg: ^2.1.2 peerDependenciesMeta: c-kzg: optional: true dependencies: - "@nomicfoundation/ethereumjs-common": 4.0.4 - "@nomicfoundation/ethereumjs-rlp": 5.0.4 - "@nomicfoundation/ethereumjs-util": 9.0.4 + '@nomicfoundation/ethereumjs-common': 4.0.4 + '@nomicfoundation/ethereumjs-rlp': 5.0.4 + '@nomicfoundation/ethereumjs-util': 9.0.4 ethereum-cryptography: 0.1.3 dev: true /@nomicfoundation/ethereumjs-util@9.0.4: - resolution: - { - integrity: sha512-sLOzjnSrlx9Bb9EFNtHzK/FJFsfg2re6bsGqinFinH1gCqVfz9YYlXiMWwDM4C/L4ywuHFCYwfKTVr/QHQcU0Q==, - } - engines: { node: ">=18" } + resolution: {integrity: sha512-sLOzjnSrlx9Bb9EFNtHzK/FJFsfg2re6bsGqinFinH1gCqVfz9YYlXiMWwDM4C/L4ywuHFCYwfKTVr/QHQcU0Q==} + engines: {node: '>=18'} peerDependencies: c-kzg: ^2.1.2 peerDependenciesMeta: c-kzg: optional: true dependencies: - "@nomicfoundation/ethereumjs-rlp": 5.0.4 + '@nomicfoundation/ethereumjs-rlp': 5.0.4 ethereum-cryptography: 0.1.3 dev: true - /@nomicfoundation/ethereumjs-verkle@0.0.2: - resolution: - { - integrity: sha512-bjnfZElpYGK/XuuVRmLS3yDvr+cDs85D9oonZ0YUa5A3lgFgokWMp76zXrxX2jVQ0BfHaw12y860n1+iOi6yFQ==, - } - engines: { node: ">=18" } - dependencies: - "@nomicfoundation/ethereumjs-rlp": 5.0.4 - "@nomicfoundation/ethereumjs-util": 9.0.4 - lru-cache: 10.2.0 - rust-verkle-wasm: 0.0.1 - transitivePeerDependencies: - - c-kzg - dev: true - - /@nomicfoundation/ethereumjs-vm@7.0.4(@nomicfoundation/ethereumjs-verkle@0.0.2): - resolution: - { - integrity: sha512-gsA4IhmtWHI4BofKy3kio9W+dqZQs5Ji5mLjLYxHCkat+JQBUt5szjRKra2F9nGDJ2XcI/wWb0YWUFNgln4zRQ==, - } - engines: { node: ">=18" } - dependencies: - "@nomicfoundation/ethereumjs-block": 5.0.4 - "@nomicfoundation/ethereumjs-blockchain": 7.0.4 - "@nomicfoundation/ethereumjs-common": 4.0.4 - "@nomicfoundation/ethereumjs-evm": 2.0.4(@nomicfoundation/ethereumjs-verkle@0.0.2) - "@nomicfoundation/ethereumjs-rlp": 5.0.4 - "@nomicfoundation/ethereumjs-statemanager": 2.0.4(@nomicfoundation/ethereumjs-verkle@0.0.2) - "@nomicfoundation/ethereumjs-trie": 6.0.4 - "@nomicfoundation/ethereumjs-tx": 5.0.4 - "@nomicfoundation/ethereumjs-util": 9.0.4 - debug: 4.3.4(supports-color@8.1.1) - ethereum-cryptography: 0.1.3 - transitivePeerDependencies: - - "@nomicfoundation/ethereumjs-verkle" - - c-kzg - - supports-color - dev: true - /@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.1: - resolution: - { - integrity: sha512-KcTodaQw8ivDZyF+D76FokN/HdpgGpfjc/gFCImdLUyqB6eSWVaZPazMbeAjmfhx3R0zm/NYVzxwAokFKgrc0w==, - } - engines: { node: ">= 10" } + resolution: {integrity: sha512-KcTodaQw8ivDZyF+D76FokN/HdpgGpfjc/gFCImdLUyqB6eSWVaZPazMbeAjmfhx3R0zm/NYVzxwAokFKgrc0w==} + engines: {node: '>= 10'} cpu: [arm64] os: [darwin] requiresBuild: true @@ -1407,11 +1105,8 @@ packages: optional: true /@nomicfoundation/solidity-analyzer-darwin-x64@0.1.1: - resolution: - { - integrity: sha512-XhQG4BaJE6cIbjAVtzGOGbK3sn1BO9W29uhk9J8y8fZF1DYz0Doj8QDMfpMu+A6TjPDs61lbsmeYodIDnfveSA==, - } - engines: { node: ">= 10" } + resolution: {integrity: sha512-XhQG4BaJE6cIbjAVtzGOGbK3sn1BO9W29uhk9J8y8fZF1DYz0Doj8QDMfpMu+A6TjPDs61lbsmeYodIDnfveSA==} + engines: {node: '>= 10'} cpu: [x64] os: [darwin] requiresBuild: true @@ -1419,11 +1114,8 @@ packages: optional: true /@nomicfoundation/solidity-analyzer-freebsd-x64@0.1.1: - resolution: - { - integrity: sha512-GHF1VKRdHW3G8CndkwdaeLkVBi5A9u2jwtlS7SLhBc8b5U/GcoL39Q+1CSO3hYqePNP+eV5YI7Zgm0ea6kMHoA==, - } - engines: { node: ">= 10" } + resolution: {integrity: sha512-GHF1VKRdHW3G8CndkwdaeLkVBi5A9u2jwtlS7SLhBc8b5U/GcoL39Q+1CSO3hYqePNP+eV5YI7Zgm0ea6kMHoA==} + engines: {node: '>= 10'} cpu: [x64] os: [freebsd] requiresBuild: true @@ -1431,11 +1123,8 @@ packages: optional: true /@nomicfoundation/solidity-analyzer-linux-arm64-gnu@0.1.1: - resolution: - { - integrity: sha512-g4Cv2fO37ZsUENQ2vwPnZc2zRenHyAxHcyBjKcjaSmmkKrFr64yvzeNO8S3GBFCo90rfochLs99wFVGT/0owpg==, - } - engines: { node: ">= 10" } + resolution: {integrity: sha512-g4Cv2fO37ZsUENQ2vwPnZc2zRenHyAxHcyBjKcjaSmmkKrFr64yvzeNO8S3GBFCo90rfochLs99wFVGT/0owpg==} + engines: {node: '>= 10'} cpu: [arm64] os: [linux] requiresBuild: true @@ -1443,11 +1132,8 @@ packages: optional: true /@nomicfoundation/solidity-analyzer-linux-arm64-musl@0.1.1: - resolution: - { - integrity: sha512-WJ3CE5Oek25OGE3WwzK7oaopY8xMw9Lhb0mlYuJl/maZVo+WtP36XoQTb7bW/i8aAdHW5Z+BqrHMux23pvxG3w==, - } - engines: { node: ">= 10" } + resolution: {integrity: sha512-WJ3CE5Oek25OGE3WwzK7oaopY8xMw9Lhb0mlYuJl/maZVo+WtP36XoQTb7bW/i8aAdHW5Z+BqrHMux23pvxG3w==} + engines: {node: '>= 10'} cpu: [arm64] os: [linux] requiresBuild: true @@ -1455,11 +1141,8 @@ packages: optional: true /@nomicfoundation/solidity-analyzer-linux-x64-gnu@0.1.1: - resolution: - { - integrity: sha512-5WN7leSr5fkUBBjE4f3wKENUy9HQStu7HmWqbtknfXkkil+eNWiBV275IOlpXku7v3uLsXTOKpnnGHJYI2qsdA==, - } - engines: { node: ">= 10" } + resolution: {integrity: sha512-5WN7leSr5fkUBBjE4f3wKENUy9HQStu7HmWqbtknfXkkil+eNWiBV275IOlpXku7v3uLsXTOKpnnGHJYI2qsdA==} + engines: {node: '>= 10'} cpu: [x64] os: [linux] requiresBuild: true @@ -1467,11 +1150,8 @@ packages: optional: true /@nomicfoundation/solidity-analyzer-linux-x64-musl@0.1.1: - resolution: - { - integrity: sha512-KdYMkJOq0SYPQMmErv/63CwGwMm5XHenEna9X9aB8mQmhDBrYrlAOSsIPgFCUSL0hjxE3xHP65/EPXR/InD2+w==, - } - engines: { node: ">= 10" } + resolution: {integrity: sha512-KdYMkJOq0SYPQMmErv/63CwGwMm5XHenEna9X9aB8mQmhDBrYrlAOSsIPgFCUSL0hjxE3xHP65/EPXR/InD2+w==} + engines: {node: '>= 10'} cpu: [x64] os: [linux] requiresBuild: true @@ -1479,11 +1159,8 @@ packages: optional: true /@nomicfoundation/solidity-analyzer-win32-arm64-msvc@0.1.1: - resolution: - { - integrity: sha512-VFZASBfl4qiBYwW5xeY20exWhmv6ww9sWu/krWSesv3q5hA0o1JuzmPHR4LPN6SUZj5vcqci0O6JOL8BPw+APg==, - } - engines: { node: ">= 10" } + resolution: {integrity: sha512-VFZASBfl4qiBYwW5xeY20exWhmv6ww9sWu/krWSesv3q5hA0o1JuzmPHR4LPN6SUZj5vcqci0O6JOL8BPw+APg==} + engines: {node: '>= 10'} cpu: [arm64] os: [win32] requiresBuild: true @@ -1491,11 +1168,8 @@ packages: optional: true /@nomicfoundation/solidity-analyzer-win32-ia32-msvc@0.1.1: - resolution: - { - integrity: sha512-JnFkYuyCSA70j6Si6cS1A9Gh1aHTEb8kOTBApp/c7NRTFGNMH8eaInKlyuuiIbvYFhlXW4LicqyYuWNNq9hkpQ==, - } - engines: { node: ">= 10" } + resolution: {integrity: sha512-JnFkYuyCSA70j6Si6cS1A9Gh1aHTEb8kOTBApp/c7NRTFGNMH8eaInKlyuuiIbvYFhlXW4LicqyYuWNNq9hkpQ==} + engines: {node: '>= 10'} cpu: [ia32] os: [win32] requiresBuild: true @@ -1503,11 +1177,8 @@ packages: optional: true /@nomicfoundation/solidity-analyzer-win32-x64-msvc@0.1.1: - resolution: - { - integrity: sha512-HrVJr6+WjIXGnw3Q9u6KQcbZCtk0caVWhCdFADySvRyUxJ8PnzlaP+MhwNE8oyT8OZ6ejHBRrrgjSqDCFXGirw==, - } - engines: { node: ">= 10" } + resolution: {integrity: sha512-HrVJr6+WjIXGnw3Q9u6KQcbZCtk0caVWhCdFADySvRyUxJ8PnzlaP+MhwNE8oyT8OZ6ejHBRrrgjSqDCFXGirw==} + engines: {node: '>= 10'} cpu: [x64] os: [win32] requiresBuild: true @@ -1515,39 +1186,33 @@ packages: optional: true /@nomicfoundation/solidity-analyzer@0.1.1: - resolution: - { - integrity: sha512-1LMtXj1puAxyFusBgUIy5pZk3073cNXYnXUpuNKFghHbIit/xZgbk0AokpUADbNm3gyD6bFWl3LRFh3dhVdREg==, - } - engines: { node: ">= 12" } + 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.20.1): - resolution: - { - integrity: sha512-0+rj0SsZotVOcTLyDOxnOc3Gulo8upo0rsw/h+gBPcmtj91YqYJNhdARHoBxOhhE8z+5IUQPx+Dii04lXT14PA==, - } + '@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.22.2): + 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 + '@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.20.1(typescript@5.3.3) + hardhat: 2.22.2(typescript@5.4.4) node-fetch: 2.7.0 semver: 6.3.1 transitivePeerDependencies: @@ -1556,61 +1221,40 @@ packages: dev: true /@openzeppelin/contracts@4.9.5: - resolution: - { - integrity: sha512-ZK+W5mVhRppff9BE6YdR8CC52C8zAvsVAiWhEtQ5+oNxFE6h1WdeWo+FJSF8KKvtxxVYZ7MTP/5KoVpAU3aSWg==, - } + resolution: {integrity: sha512-ZK+W5mVhRppff9BE6YdR8CC52C8zAvsVAiWhEtQ5+oNxFE6h1WdeWo+FJSF8KKvtxxVYZ7MTP/5KoVpAU3aSWg==} dev: true /@openzeppelin/contracts@5.0.1: - resolution: - { - integrity: sha512-yQJaT5HDp9hYOOp4jTYxMsR02gdFZFXhewX5HW9Jo4fsqSVqqyIO/xTHdWDaKX5a3pv1txmf076Lziz+sO7L1w==, - } + 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" } + 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" } + 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 + 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 /@prb/math@4.0.2: - resolution: - { - integrity: sha512-kJgqvXR6iyU7+N959RzggSFhBdnRuSDnc/bs8u6MzdWw7aYIUaAr+uMVdpP6Dheypjerd7sfJgFOs19FRFhscg==, - } + resolution: {integrity: sha512-kJgqvXR6iyU7+N959RzggSFhBdnRuSDnc/bs8u6MzdWw7aYIUaAr+uMVdpP6Dheypjerd7sfJgFOs19FRFhscg==} dev: true /@safe-global/safe-contracts@1.4.1(ethers@5.4.0): - resolution: - { - integrity: sha512-fP1jewywSwsIniM04NsqPyVRFKPMAuirC3ftA/TA4X3Zc5EnwQp/UCJUU2PL/37/z/jMo8UUaJ+pnFNWmMU7dQ==, - } + resolution: {integrity: sha512-fP1jewywSwsIniM04NsqPyVRFKPMAuirC3ftA/TA4X3Zc5EnwQp/UCJUU2PL/37/z/jMo8UUaJ+pnFNWmMU7dQ==} peerDependencies: ethers: 5.4.0 dependencies: @@ -1618,104 +1262,81 @@ packages: dev: true /@scure/base@1.1.5: - resolution: - { - integrity: sha512-Brj9FiG2W1MRQSTB212YVPRrcbjkv48FoZi/u4l/zds/ieRrqsh7aUf6CLwkAq61oKXr/ZlTzlY66gLIj3TFTQ==, - } + resolution: {integrity: sha512-Brj9FiG2W1MRQSTB212YVPRrcbjkv48FoZi/u4l/zds/ieRrqsh7aUf6CLwkAq61oKXr/ZlTzlY66gLIj3TFTQ==} + dev: true + + /@scure/base@1.1.6: + resolution: {integrity: sha512-ok9AWwhcgYuGG3Zfhyqg+zwl+Wn5uE+dwC0NV/2qQkx4dABbb/bx96vWu8NSj+BNjjSjno+JRYRjle1jV08k3g==} dev: true /@scure/bip32@1.1.5: - resolution: - { - integrity: sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==, - } + resolution: {integrity: sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==} dependencies: - "@noble/hashes": 1.2.0 - "@noble/secp256k1": 1.7.1 - "@scure/base": 1.1.5 + '@noble/hashes': 1.2.0 + '@noble/secp256k1': 1.7.1 + '@scure/base': 1.1.6 dev: true /@scure/bip32@1.3.3: - resolution: - { - integrity: sha512-LJaN3HwRbfQK0X1xFSi0Q9amqOgzQnnDngIt+ZlsBC3Bm7/nE7K0kwshZHyaru79yIVRv/e1mQAjZyuZG6jOFQ==, - } + resolution: {integrity: sha512-LJaN3HwRbfQK0X1xFSi0Q9amqOgzQnnDngIt+ZlsBC3Bm7/nE7K0kwshZHyaru79yIVRv/e1mQAjZyuZG6jOFQ==} dependencies: - "@noble/curves": 1.3.0 - "@noble/hashes": 1.3.3 - "@scure/base": 1.1.5 + '@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==, - } + resolution: {integrity: sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==} dependencies: - "@noble/hashes": 1.2.0 - "@scure/base": 1.1.5 + '@noble/hashes': 1.2.0 + '@scure/base': 1.1.6 dev: true /@scure/bip39@1.2.2: - resolution: - { - integrity: sha512-HYf9TUXG80beW+hGAt3TRM8wU6pQoYur9iNypTROm42dorCGmLnFe3eWjz3gOq6G62H2WRh0FCzAR1PI+29zIA==, - } + resolution: {integrity: sha512-HYf9TUXG80beW+hGAt3TRM8wU6pQoYur9iNypTROm42dorCGmLnFe3eWjz3gOq6G62H2WRh0FCzAR1PI+29zIA==} dependencies: - "@noble/hashes": 1.3.3 - "@scure/base": 1.1.5 + '@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 + 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 + 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 + 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 + 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 @@ -1725,77 +1346,53 @@ packages: 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 + 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" } + 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" } + resolution: {integrity: sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==} + engines: {node: '>=6'} dependencies: - "@sentry/types": 5.30.0 + '@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" } + 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==, - } + 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==, - } + 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" } + 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==, - } + resolution: {integrity: sha512-g5zeMZ8js/yg6MjFoC+pt0eqfCL2jC46yLY1LbKNriyqftB1tE3jpG/FMMDIW3x9/yRg/AgUb8Nluqj15tQs+A==} dependencies: ethers: 5.7.2 mcl-wasm: 1.4.0 @@ -1804,180 +1401,116 @@ packages: - utf-8-validate dev: true - /@typechain/hardhat@2.3.1(hardhat@2.20.1)(lodash@4.17.21)(typechain@5.2.0): - resolution: - { - integrity: sha512-BQV8OKQi0KAzLXCdsPO0pZBNQQ6ra8A2ucC26uFX/kquRBtJu1yEyWnVSmtr07b5hyRoJRpzUeINLnyqz4/MAw==, - } + /@typechain/hardhat@2.3.1(hardhat@2.22.2)(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.20.1(typescript@5.3.3) + hardhat: 2.22.2(typescript@5.4.4) lodash: 4.17.21 - typechain: 5.2.0(typescript@5.3.3) + typechain: 5.2.0(typescript@5.4.4) dev: true /@types/bn.js@4.11.6: - resolution: - { - integrity: sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==, - } + resolution: {integrity: sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==} dependencies: - "@types/node": 20.11.20 + '@types/node': 20.12.5 dev: true /@types/bn.js@5.1.5: - resolution: - { - integrity: sha512-V46N0zwKRF5Q00AZ6hWtN0T8gGmDUaUzLWQvHFo5yThtVwK/VCenFY3wXVbOvNfajEpsTfQM4IN9k/d6gUVX3A==, - } + resolution: {integrity: sha512-V46N0zwKRF5Q00AZ6hWtN0T8gGmDUaUzLWQvHFo5yThtVwK/VCenFY3wXVbOvNfajEpsTfQM4IN9k/d6gUVX3A==} dependencies: - "@types/node": 20.11.20 + '@types/node': 20.11.20 dev: true /@types/debug@4.1.12: - resolution: - { - integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==, - } + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} dependencies: - "@types/ms": 0.7.34 + '@types/ms': 0.7.34 dev: true /@types/glob@7.2.0: - resolution: - { - integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==, - } + resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} dependencies: - "@types/minimatch": 5.1.2 - "@types/node": 20.11.20 + '@types/minimatch': 5.1.2 + '@types/node': 20.11.20 dev: true /@types/http-cache-semantics@4.0.4: - resolution: - { - integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==, - } + resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} dev: true /@types/lru-cache@5.1.1: - resolution: - { - integrity: sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==, - } + resolution: {integrity: sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==} dev: true /@types/minimatch@5.1.2: - resolution: - { - integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==, - } + resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} dev: true /@types/mocha@9.1.1: - resolution: - { - integrity: sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==, - } + resolution: {integrity: sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==} dev: true /@types/ms@0.7.34: - resolution: - { - integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==, - } + resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} dev: true /@types/node@20.11.20: - resolution: - { - integrity: sha512-7/rR21OS+fq8IyHTgtLkDK949uzsa6n8BkziAKtPVpugIkO6D+/ooXMvzXxDnZrmtXVfjb1bKQafYpb8s89LOg==, - } + resolution: {integrity: sha512-7/rR21OS+fq8IyHTgtLkDK949uzsa6n8BkziAKtPVpugIkO6D+/ooXMvzXxDnZrmtXVfjb1bKQafYpb8s89LOg==} + dependencies: + undici-types: 5.26.5 + dev: true + + /@types/node@20.12.5: + resolution: {integrity: sha512-BD+BjQ9LS/D8ST9p5uqBxghlN+S42iuNxjsUGjeZobe/ciXzk2qb1B6IXc6AnRLS+yFJRpN2IPEHMzwspfDJNw==} dependencies: undici-types: 5.26.5 dev: true /@types/pbkdf2@3.1.2: - resolution: - { - integrity: sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew==, - } + resolution: {integrity: sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew==} dependencies: - "@types/node": 20.11.20 + '@types/node': 20.11.20 dev: true /@types/prettier@2.7.3: - resolution: - { - integrity: sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==, - } + 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.20 - safe-buffer: 5.1.2 + resolution: {integrity: sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==} dev: true /@types/secp256k1@4.0.6: - resolution: - { - integrity: sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ==, - } + resolution: {integrity: sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ==} dependencies: - "@types/node": 20.11.20 + '@types/node': 20.11.20 dev: true /abbrev@1.0.9: - resolution: - { - integrity: sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q==, - } + resolution: {integrity: sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q==} dev: true /adm-zip@0.4.16: - resolution: - { - integrity: sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==, - } - engines: { node: ">=0.3.0" } + resolution: {integrity: sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==} + engines: {node: '>=0.3.0'} dev: true /aes-js@3.0.0: - resolution: - { - integrity: sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==, - } + resolution: {integrity: sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==} dev: true /aes-js@3.1.2: - resolution: - { - integrity: sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ==, - } + 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" } + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} dependencies: debug: 4.3.4(supports-color@8.1.1) transitivePeerDependencies: @@ -1985,21 +1518,15 @@ packages: dev: true /aggregate-error@3.1.0: - resolution: - { - integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==, - } - engines: { node: ">=8" } + 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==, - } + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} dependencies: fast-deep-equal: 3.1.3 fast-json-stable-stringify: 2.1.0 @@ -2008,10 +1535,7 @@ packages: dev: true /ajv@8.12.0: - resolution: - { - integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==, - } + resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} dependencies: fast-deep-equal: 3.1.3 json-schema-traverse: 1.0.0 @@ -2020,190 +1544,124 @@ packages: dev: true /amdefine@1.0.1: - resolution: - { - integrity: sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==, - } - engines: { node: ">=0.4.2" } + 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==, - } + 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" } + 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" } + 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" } + 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" } + 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" } + 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" } + 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" } + resolution: {integrity: sha512-kiXTspaRYvnIArgE97z5YVVf/cDVQABr3abFRR6mE7yesLMkgu4ujuyV/sgxafQ8wgve0DJQUJ38Z8tkgA2izA==} + engines: {node: '>=16'} dev: true /antlr4ts@0.5.0-alpha.4: - resolution: - { - integrity: sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==, - } + resolution: {integrity: sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==} dev: true /anymatch@3.1.3: - resolution: - { - integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==, - } - engines: { node: ">= 8" } + 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==, - } + 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==, - } + 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" } + 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" } + 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" } + 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==, - } + resolution: {integrity: sha512-XHusKxKz3zoYk1ic8Un640joHbFMhbqneyoZfoKnEGtf2ey9Uh/IdpcQplODdO/kENaMIWsD0nJm4+wX3UNLHA==} dev: true /astral-regex@2.0.0: - resolution: - { - integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} + engines: {node: '>=8'} dev: true /async@1.5.2: - resolution: - { - integrity: sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==, - } + resolution: {integrity: sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==} dev: true /asynckit@0.4.0: - resolution: - { - integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==, - } + 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" } + 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==, - } + resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==} dependencies: follow-redirects: 1.15.5(debug@4.3.4) transitivePeerDependencies: @@ -2211,85 +1669,47 @@ packages: dev: true /balanced-match@1.0.2: - resolution: - { - integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==, - } + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: true /base-x@3.0.9: - resolution: - { - integrity: sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==, - } + resolution: {integrity: sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==} dependencies: safe-buffer: 5.2.1 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" } + resolution: {integrity: sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==} dev: true /bignumber.js@9.1.2: - resolution: - { - integrity: sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==, - } + resolution: {integrity: sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==} dev: true /binary-extensions@2.2.0: - resolution: - { - integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} + engines: {node: '>=8'} dev: true /blakejs@1.2.1: - resolution: - { - integrity: sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==, - } + resolution: {integrity: sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==} dev: true /bn.js@4.11.6: - resolution: - { - integrity: sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==, - } + resolution: {integrity: sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==} dev: true /bn.js@4.12.0: - resolution: - { - integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==, - } + resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==} dev: true /bn.js@5.2.1: - resolution: - { - integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==, - } + 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" } + resolution: {integrity: sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==} + engines: {node: '>=10'} dependencies: ansi-align: 3.0.1 camelcase: 6.3.0 @@ -2302,53 +1722,35 @@ packages: dev: true /brace-expansion@1.1.11: - resolution: - { - integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==, - } + 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==, - } + 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" } + 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==, - } + resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} dev: true /browser-stdout@1.3.1: - resolution: - { - integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==, - } + resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} dev: true /browserify-aes@1.2.0: - resolution: - { - integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==, - } + resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==} dependencies: buffer-xor: 1.0.3 cipher-base: 1.0.4 @@ -2359,19 +1761,13 @@ packages: dev: true /bs58@4.0.1: - resolution: - { - integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==, - } + 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==, - } + resolution: {integrity: sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==} dependencies: bs58: 4.0.1 create-hash: 1.2.0 @@ -2379,43 +1775,28 @@ packages: dev: true /buffer-from@1.1.2: - resolution: - { - integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==, - } + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} dev: true /buffer-xor@1.0.3: - resolution: - { - integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==, - } + resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} dev: true /bytes@3.1.2: - resolution: - { - integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==, - } - engines: { node: ">= 0.8" } + 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" } + 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" } + resolution: {integrity: sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==} + engines: {node: '>=14.16'} dependencies: - "@types/http-cache-semantics": 4.0.4 + '@types/http-cache-semantics': 4.0.4 get-stream: 6.0.1 http-cache-semantics: 4.1.1 keyv: 4.5.4 @@ -2425,11 +1806,8 @@ packages: dev: true /call-bind@1.0.7: - resolution: - { - integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==, - } - engines: { node: ">= 0.4" } + resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} + engines: {node: '>= 0.4'} dependencies: es-define-property: 1.0.0 es-errors: 1.3.0 @@ -2439,38 +1817,26 @@ packages: dev: true /callsites@3.1.0: - resolution: - { - integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==, - } - engines: { node: ">=6" } + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} dev: true /camelcase@6.3.0: - resolution: - { - integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} dev: true /cbor@5.2.0: - resolution: - { - integrity: sha512-5IMhi9e1QU76ppa5/ajP1BmMWZ2FHkhAhjeVKQ/EFCgYSEaeVaoGtL7cxJskf9oCCk+XjzaIdc3IuU/dbA/o2A==, - } - engines: { node: ">=6.0.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" } + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} dependencies: ansi-styles: 3.2.1 escape-string-regexp: 1.0.5 @@ -2478,22 +1844,16 @@ packages: dev: true /chalk@4.1.2: - resolution: - { - integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==, - } - engines: { node: ">=10" } + 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" } + resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} + engines: {node: '>= 8.10.0'} dependencies: anymatch: 3.1.3 braces: 3.0.2 @@ -2507,11 +1867,8 @@ packages: dev: true /chokidar@3.6.0: - resolution: - { - integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==, - } - engines: { node: ">= 8.10.0" } + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} dependencies: anymatch: 3.1.3 braces: 3.0.2 @@ -2525,43 +1882,28 @@ packages: dev: true /ci-info@2.0.0: - resolution: - { - integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==, - } + resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} dev: true /cipher-base@1.0.4: - resolution: - { - integrity: sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==, - } + resolution: {integrity: sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==} dependencies: inherits: 2.0.4 safe-buffer: 5.2.1 dev: true /clean-stack@2.2.0: - resolution: - { - integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==, - } - engines: { node: ">=6" } + 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" } + resolution: {integrity: sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==} + engines: {node: '>=6'} dev: true /cliui@7.0.4: - resolution: - { - integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==, - } + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} dependencies: string-width: 4.2.3 strip-ansi: 6.0.1 @@ -2569,60 +1911,39 @@ packages: dev: true /color-convert@1.9.3: - resolution: - { - integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==, - } + 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" } + 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==, - } + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} dev: true /color-name@1.1.4: - resolution: - { - integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==, - } + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} dev: true /combined-stream@1.0.8: - resolution: - { - integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==, - } - engines: { node: ">= 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==, - } + resolution: {integrity: sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==} dev: true /command-line-args@4.0.7: - resolution: - { - integrity: sha512-aUdPvQRAyBvQd2n7jXcsMDz68ckBJELXNzBybCHOibUWEg0mWTnaYCSRU8h9R+aNRSvDihJtssSRCiDRpLaezA==, - } + resolution: {integrity: sha512-aUdPvQRAyBvQd2n7jXcsMDz68ckBJELXNzBybCHOibUWEg0mWTnaYCSRU8h9R+aNRSvDihJtssSRCiDRpLaezA==} hasBin: true dependencies: array-back: 2.0.0 @@ -2631,53 +1952,35 @@ packages: dev: true /commander@10.0.1: - resolution: - { - integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==, - } - engines: { node: ">=14" } + resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} + engines: {node: '>=14'} dev: true /commander@3.0.2: - resolution: - { - integrity: sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==, - } + resolution: {integrity: sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==} dev: true /concat-map@0.0.1: - resolution: - { - integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==, - } + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} dev: true /config-chain@1.1.13: - resolution: - { - integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==, - } + 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" } + resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==} + engines: {node: '>= 0.6'} + dev: true + + /cosmiconfig@8.3.6(typescript@5.4.4): + resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} + engines: {node: '>=14'} peerDependencies: - typescript: ">=4.9.5" + typescript: '>=4.9.5' peerDependenciesMeta: typescript: optional: true @@ -2686,14 +1989,11 @@ packages: js-yaml: 4.1.0 parse-json: 5.2.0 path-type: 4.0.0 - typescript: 5.3.3 + typescript: 5.4.4 dev: true /create-hash@1.2.0: - resolution: - { - integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==, - } + resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} dependencies: cipher-base: 1.0.4 inherits: 2.0.4 @@ -2703,10 +2003,7 @@ packages: dev: true /create-hmac@1.1.7: - resolution: - { - integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==, - } + resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==} dependencies: cipher-base: 1.0.4 create-hash: 1.2.0 @@ -2717,20 +2014,14 @@ packages: dev: true /death@1.1.0: - resolution: - { - integrity: sha512-vsV6S4KVHvTGxbEcij7hkWRv0It+sGGWVOM67dQde/o5Xjnr+KmLjxWJii2uEObIrt1CcM9w0Yaovx+iOlIL+w==, - } + 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" } + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} peerDependencies: - supports-color: "*" + supports-color: '*' peerDependenciesMeta: supports-color: optional: true @@ -2740,52 +2031,34 @@ packages: dev: true /decamelize@4.0.0: - resolution: - { - integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==, - } - engines: { node: ">=10" } + 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" } + 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" } + 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==, - } + 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" } + resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} + engines: {node: '>=10'} dev: true /define-data-property@1.1.4: - resolution: - { - integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==, - } - engines: { node: ">= 0.4" } + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} dependencies: es-define-property: 1.0.0 es-errors: 1.3.0 @@ -2793,53 +2066,47 @@ packages: dev: true /delayed-stream@1.0.0: - resolution: - { - integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==, - } - engines: { node: ">=0.4.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" } + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} dev: true /diff@5.0.0: - resolution: - { - integrity: sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==, - } - engines: { node: ">=0.3.1" } + 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==, - } + 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" } + 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==, - } + 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 + + /elliptic@6.5.5: + resolution: {integrity: sha512-7EjbcmUm17NQFu4Pmgmq2olYMj8nwMnpcddByChSUjArp8F5DQWcIcpriwO4ZToLNAJig0yiyjswfyGNje/ixw==} dependencies: bn.js: 4.12.0 brorand: 1.1.0 @@ -2851,95 +2118,62 @@ packages: dev: true /emoji-regex@8.0.0: - resolution: - { - integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==, - } + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} dev: true /encode-utf8@1.0.3: - resolution: - { - integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==, - } + 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" } + 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" } + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} dev: true /error-ex@1.3.2: - resolution: - { - integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==, - } + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} dependencies: is-arrayish: 0.2.1 dev: true /es-define-property@1.0.0: - resolution: - { - integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==, - } - engines: { node: ">= 0.4" } + resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} + engines: {node: '>= 0.4'} dependencies: get-intrinsic: 1.2.4 dev: true /es-errors@1.3.0: - resolution: - { - integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==, - } - engines: { node: ">= 0.4" } + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} dev: true /escalade@3.1.2: - resolution: - { - integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==, - } - engines: { node: ">=6" } + resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} + engines: {node: '>=6'} dev: true /escape-string-regexp@1.0.5: - resolution: - { - integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==, - } - engines: { node: ">=0.8.0" } + 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" } + 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" } + resolution: {integrity: sha512-yhi5S+mNTOuRvyW4gWlg5W1byMaQGWWSYHXsuFZ7GBo7tpyOwi2EdzMP/QWxh9hwkD2m+wDVHJsxhRIj+v/b/A==} + engines: {node: '>=0.12.0'} hasBin: true dependencies: esprima: 2.7.3 @@ -2951,56 +2185,38 @@ packages: dev: true /esprima@2.7.3: - resolution: - { - integrity: sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==, - } - engines: { node: ">=0.10.0" } + 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" } + 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" } + 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" } + 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==, - } + 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==, - } + resolution: {integrity: sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==} dependencies: - "@types/pbkdf2": 3.1.2 - "@types/secp256k1": 4.0.6 + '@types/pbkdf2': 3.1.2 + '@types/secp256k1': 4.0.6 blakejs: 1.2.1 browserify-aes: 1.2.0 bs58check: 2.1.2 @@ -3017,62 +2233,47 @@ packages: dev: true /ethereum-cryptography@1.2.0: - resolution: - { - integrity: sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==, - } + 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 + '@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==, - } + 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 + '@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==, - } + 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==, - } + resolution: {integrity: sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==} dependencies: - "@types/bn.js": 4.11.6 + '@types/bn.js': 4.11.6 bn.js: 4.12.0 create-hash: 1.2.0 - elliptic: 6.5.4 + elliptic: 6.5.5 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" } + resolution: {integrity: sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==} + engines: {node: '>=10.0.0'} dependencies: - "@types/bn.js": 5.1.5 + '@types/bn.js': 5.1.5 bn.js: 5.2.1 create-hash: 1.2.0 ethereum-cryptography: 0.1.3 @@ -3080,10 +2281,7 @@ packages: dev: true /ethereumjs-wallet@1.0.2: - resolution: - { - integrity: sha512-CCWV4RESJgRdHIvFciVQFnCHfqyhXWchTPlkfp28Qc53ufs+doi5I/cV2+xeK9+qEo25XCWfP9MiL+WEPAZfdA==, - } + resolution: {integrity: sha512-CCWV4RESJgRdHIvFciVQFnCHfqyhXWchTPlkfp28Qc53ufs+doi5I/cV2+xeK9+qEo25XCWfP9MiL+WEPAZfdA==} dependencies: aes-js: 3.1.2 bs58check: 2.1.2 @@ -3096,237 +2294,195 @@ packages: 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 + 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 + 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" } + 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" } + 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==, - } + 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==, - } + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} dev: true /fast-diff@1.3.0: - resolution: - { - integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==, - } + 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 + 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==, - } + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} dev: true /fast-levenshtein@2.0.6: - resolution: - { - integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==, - } + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} dev: true /fastq@1.17.1: - resolution: - { - integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==, - } + resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} dependencies: reusify: 1.0.4 dev: true /fill-range@7.0.1: - resolution: - { - integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==, - } - engines: { node: ">=8" } + 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" } + 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" } + 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" } + 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==, - } + resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} hasBin: true dev: true /fmix@0.1.0: - resolution: - { - integrity: sha512-Y6hyofImk9JdzU8k5INtTXX1cu8LDlePWDFU5sftm9H+zKCr5SGrVjdhkvsim646cw5zD0nADj8oHyXMZmCZ9w==, - } + 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" } + 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 + + /follow-redirects@1.15.6(debug@4.3.4): + resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} + engines: {node: '>=4.0'} peerDependencies: - debug: "*" + debug: '*' peerDependenciesMeta: debug: optional: true @@ -3335,19 +2491,13 @@ packages: dev: true /form-data-encoder@2.1.4: - resolution: - { - integrity: sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==, - } - engines: { node: ">= 14.17" } + 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" } + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 @@ -3355,17 +2505,11 @@ packages: dev: true /fp-ts@1.19.3: - resolution: - { - integrity: sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg==, - } + resolution: {integrity: sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg==} dev: true /fs-extra@0.30.0: - resolution: - { - integrity: sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==, - } + resolution: {integrity: sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==} dependencies: graceful-fs: 4.2.11 jsonfile: 2.4.0 @@ -3375,11 +2519,8 @@ packages: dev: true /fs-extra@10.1.0: - resolution: - { - integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==, - } - engines: { node: ">=12" } + resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} + engines: {node: '>=12'} dependencies: graceful-fs: 4.2.11 jsonfile: 6.1.0 @@ -3387,11 +2528,8 @@ packages: dev: true /fs-extra@7.0.1: - resolution: - { - integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==, - } - engines: { node: ">=6 <7 || >=8" } + resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} + engines: {node: '>=6 <7 || >=8'} dependencies: graceful-fs: 4.2.11 jsonfile: 4.0.0 @@ -3399,11 +2537,8 @@ packages: dev: true /fs-extra@8.1.0: - resolution: - { - integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==, - } - engines: { node: ">=6 <7 || >=8" } + resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} + engines: {node: '>=6 <7 || >=8'} dependencies: graceful-fs: 4.2.11 jsonfile: 4.0.0 @@ -3411,11 +2546,8 @@ packages: dev: true /fs-extra@9.1.0: - resolution: - { - integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} + engines: {node: '>=10'} dependencies: at-least-node: 1.0.0 graceful-fs: 4.2.11 @@ -3424,44 +2556,29 @@ packages: dev: true /fs.realpath@1.0.0: - resolution: - { - integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==, - } + 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 } + 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==, - } + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} dev: true /get-caller-file@2.0.5: - resolution: - { - integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==, - } - engines: { node: 6.* || 8.* || >= 10.* } + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} dev: true /get-intrinsic@1.2.4: - resolution: - { - integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==, - } - engines: { node: ">= 0.4" } + resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} + engines: {node: '>= 0.4'} dependencies: es-errors: 1.3.0 function-bind: 1.1.2 @@ -3471,18 +2588,12 @@ packages: dev: true /get-stream@6.0.1: - resolution: - { - integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} dev: true /ghost-testrpc@0.0.2: - resolution: - { - integrity: sha512-i08dAEgJ2g8z5buJIrCTduwPIhih3DP+hOCTyyryikfV8T0bNvHnGXO67i0DD1H4GBDETTclPy9njZbfluQYrQ==, - } + resolution: {integrity: sha512-i08dAEgJ2g8z5buJIrCTduwPIhih3DP+hOCTyyryikfV8T0bNvHnGXO67i0DD1H4GBDETTclPy9njZbfluQYrQ==} hasBin: true dependencies: chalk: 2.4.2 @@ -3490,20 +2601,14 @@ packages: dev: true /glob-parent@5.1.2: - resolution: - { - integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==, - } - engines: { node: ">= 6" } + 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==, - } + resolution: {integrity: sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==} dependencies: inflight: 1.0.6 inherits: 2.0.4 @@ -3513,10 +2618,7 @@ packages: dev: true /glob@7.2.0: - resolution: - { - integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==, - } + resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==} dependencies: fs.realpath: 1.0.0 inflight: 1.0.6 @@ -3527,10 +2629,7 @@ packages: dev: true /glob@7.2.3: - resolution: - { - integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==, - } + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} dependencies: fs.realpath: 1.0.0 inflight: 1.0.6 @@ -3541,11 +2640,8 @@ packages: dev: true /glob@8.1.0: - resolution: - { - integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==, - } - engines: { node: ">=12" } + resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} + engines: {node: '>=12'} dependencies: fs.realpath: 1.0.0 inflight: 1.0.6 @@ -3555,21 +2651,15 @@ packages: dev: true /global-modules@2.0.0: - resolution: - { - integrity: sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==, - } - engines: { node: ">=6" } + 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" } + resolution: {integrity: sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==} + engines: {node: '>=6'} dependencies: ini: 1.3.8 kind-of: 6.0.3 @@ -3577,13 +2667,10 @@ packages: dev: true /globby@10.0.2: - resolution: - { - integrity: sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==} + engines: {node: '>=8'} dependencies: - "@types/glob": 7.2.0 + '@types/glob': 7.2.0 array-union: 2.1.0 dir-glob: 3.0.1 fast-glob: 3.3.2 @@ -3594,23 +2681,17 @@ packages: dev: true /gopd@1.0.1: - resolution: - { - integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==, - } + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} dependencies: get-intrinsic: 1.2.4 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 + 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 @@ -3623,25 +2704,16 @@ packages: dev: true /graceful-fs@4.2.10: - resolution: - { - integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==, - } + resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} dev: true /graceful-fs@4.2.11: - resolution: - { - integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==, - } + 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" } + resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==} + engines: {node: '>=0.4.7'} hasBin: true dependencies: minimist: 1.2.8 @@ -3652,50 +2724,41 @@ packages: uglify-js: 3.17.4 dev: true - /hardhat-deploy-ethers@0.3.0-beta.13(ethers@5.4.0)(hardhat@2.20.1): - resolution: - { - integrity: sha512-PdWVcKB9coqWV1L7JTpfXRCI91Cgwsm7KLmBcwZ8f0COSm1xtABHZTyz3fvF6p42cTnz1VM0QnfDvMFlIRkSNw==, - } + /hardhat-deploy-ethers@0.3.0-beta.13(ethers@5.4.0)(hardhat@2.22.2): + resolution: {integrity: sha512-PdWVcKB9coqWV1L7JTpfXRCI91Cgwsm7KLmBcwZ8f0COSm1xtABHZTyz3fvF6p42cTnz1VM0QnfDvMFlIRkSNw==} peerDependencies: ethers: ^5.0.0 hardhat: ^2.0.0 dependencies: ethers: 5.4.0 - hardhat: 2.20.1(typescript@5.3.3) + hardhat: 2.22.2(typescript@5.4.4) dev: true - /hardhat-deploy-ethers@0.3.0-beta.13(ethers@5.7.2)(hardhat@2.20.1): - resolution: - { - integrity: sha512-PdWVcKB9coqWV1L7JTpfXRCI91Cgwsm7KLmBcwZ8f0COSm1xtABHZTyz3fvF6p42cTnz1VM0QnfDvMFlIRkSNw==, - } + /hardhat-deploy-ethers@0.3.0-beta.13(ethers@5.7.2)(hardhat@2.22.2): + 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) + hardhat: 2.22.2(typescript@5.4.4) 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 + 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.6.0 @@ -3714,38 +2777,28 @@ packages: - utf-8-validate dev: true - /hardhat@2.20.1(typescript@5.3.3): - resolution: - { - integrity: sha512-q75xDQiQtCZcTMBwjTovrXEU5ECr49baxr4/OBkIu/ULTPzlB20yk1dRWNmD2IFbAeAeXggaWvQAdpiScaHtPw==, - } + /hardhat@2.22.2(typescript@5.4.4): + resolution: {integrity: sha512-0xZ7MdCZ5sJem4MrvpQWLR3R3zGDoHw5lsR+pBFimqwagimIOn3bWuZv69KA+veXClwI1s/zpqgwPwiFrd4Dxw==} hasBin: true peerDependencies: - ts-node: "*" - typescript: "*" + 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.4 - "@nomicfoundation/ethereumjs-blockchain": 7.0.4 - "@nomicfoundation/ethereumjs-common": 4.0.4 - "@nomicfoundation/ethereumjs-evm": 2.0.4(@nomicfoundation/ethereumjs-verkle@0.0.2) - "@nomicfoundation/ethereumjs-rlp": 5.0.4 - "@nomicfoundation/ethereumjs-statemanager": 2.0.4(@nomicfoundation/ethereumjs-verkle@0.0.2) - "@nomicfoundation/ethereumjs-trie": 6.0.4 - "@nomicfoundation/ethereumjs-tx": 5.0.4 - "@nomicfoundation/ethereumjs-util": 9.0.4 - "@nomicfoundation/ethereumjs-verkle": 0.0.2 - "@nomicfoundation/ethereumjs-vm": 7.0.4(@nomicfoundation/ethereumjs-verkle@0.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 + '@ethersproject/abi': 5.7.0 + '@metamask/eth-sig-util': 4.0.1 + '@nomicfoundation/edr': 0.3.3 + '@nomicfoundation/ethereumjs-common': 4.0.4 + '@nomicfoundation/ethereumjs-tx': 5.0.4 + '@nomicfoundation/ethereumjs-util': 9.0.4 + '@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 @@ -3767,7 +2820,7 @@ packages: keccak: 3.0.4 lodash: 4.17.21 mnemonist: 0.38.5 - mocha: 10.3.0 + mocha: 10.4.0 p-map: 4.0.0 raw-body: 2.5.2 resolve: 1.17.0 @@ -3776,8 +2829,8 @@ packages: source-map-support: 0.5.21 stacktrace-parser: 0.1.10 tsort: 0.0.1 - typescript: 5.3.3 - undici: 5.28.3 + typescript: 5.4.4 + undici: 5.28.4 uuid: 8.3.2 ws: 7.5.9 transitivePeerDependencies: @@ -3788,60 +2841,39 @@ packages: dev: true /has-flag@1.0.0: - resolution: - { - integrity: sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==, - } - engines: { node: ">=0.10.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" } + 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" } + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} dev: true /has-property-descriptors@1.0.2: - resolution: - { - integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==, - } + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} dependencies: es-define-property: 1.0.0 dev: true /has-proto@1.0.3: - resolution: - { - integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==, - } - engines: { node: ">= 0.4" } + resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} + engines: {node: '>= 0.4'} dev: true /has-symbols@1.0.3: - resolution: - { - integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==, - } - engines: { node: ">= 0.4" } + 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" } + resolution: {integrity: sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==} + engines: {node: '>=4'} dependencies: inherits: 2.0.4 readable-stream: 3.6.2 @@ -3849,45 +2881,30 @@ packages: dev: true /hash.js@1.1.7: - resolution: - { - integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==, - } + resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} dependencies: inherits: 2.0.4 minimalistic-assert: 1.0.1 dev: true /hasown@2.0.1: - resolution: - { - integrity: sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==, - } - engines: { node: ">= 0.4" } + resolution: {integrity: sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==} + engines: {node: '>= 0.4'} dependencies: function-bind: 1.1.2 dev: true /he@1.2.0: - resolution: - { - integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==, - } + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true dev: true /heap@0.2.7: - resolution: - { - integrity: sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==, - } + resolution: {integrity: sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==} dev: true /hmac-drbg@1.0.1: - resolution: - { - integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==, - } + resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} dependencies: hash.js: 1.1.7 minimalistic-assert: 1.0.1 @@ -3895,18 +2912,12 @@ packages: dev: true /http-cache-semantics@4.1.1: - resolution: - { - integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==, - } + 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" } + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} dependencies: depd: 2.0.0 inherits: 2.0.4 @@ -3916,22 +2927,16 @@ packages: dev: true /http2-wrapper@2.2.1: - resolution: - { - integrity: sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==, - } - engines: { node: ">=10.19.0" } + 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" } + 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) @@ -3940,222 +2945,137 @@ packages: dev: true /iconv-lite@0.4.24: - resolution: - { - integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==, - } - engines: { node: ">=0.10.0" } + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} dependencies: safer-buffer: 2.1.2 dev: true /ignore@5.3.1: - resolution: - { - integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==, - } - engines: { node: ">= 4" } + resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} + engines: {node: '>= 4'} dev: true /immutable@4.3.5: - resolution: - { - integrity: sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==, - } + resolution: {integrity: sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==} dev: true /import-fresh@3.3.0: - resolution: - { - integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==, - } - engines: { node: ">=6" } + 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" } + 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" } + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} dev: true /inflight@1.0.6: - resolution: - { - integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==, - } + 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==, - } + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} dev: true /ini@1.3.8: - resolution: - { - integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==, - } + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} dev: true /interpret@1.4.0: - resolution: - { - integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==, - } - engines: { node: ">= 0.10" } + resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} + engines: {node: '>= 0.10'} dev: true /io-ts@1.10.4: - resolution: - { - integrity: sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g==, - } + 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==, - } + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} dev: true /is-binary-path@2.1.0: - resolution: - { - integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} dependencies: binary-extensions: 2.2.0 dev: true /is-core-module@2.13.1: - resolution: - { - integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==, - } + resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} dependencies: hasown: 2.0.1 dev: true /is-extglob@2.1.1: - resolution: - { - integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==, - } - engines: { node: ">=0.10.0" } + 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" } + 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" } + 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" } + 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" } + 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" } + 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" } + 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==, - } + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} dev: true /js-sha3@0.5.7: - resolution: - { - integrity: sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==, - } + resolution: {integrity: sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==} dev: true /js-sha3@0.8.0: - resolution: - { - integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==, - } + resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==} dev: true /js-tokens@4.0.0: - resolution: - { - integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==, - } + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} dev: true /js-yaml@3.14.1: - resolution: - { - integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==, - } + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} hasBin: true dependencies: argparse: 1.0.10 @@ -4163,66 +3083,42 @@ packages: dev: true /js-yaml@4.1.0: - resolution: - { - integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==, - } + 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==, - } + 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==, - } + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} dev: true /json-schema-traverse@0.4.1: - resolution: - { - integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==, - } + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} dev: true /json-schema-traverse@1.0.0: - resolution: - { - integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==, - } + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} dev: true /jsonfile@2.4.0: - resolution: - { - integrity: sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==, - } + resolution: {integrity: sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==} optionalDependencies: graceful-fs: 4.2.11 dev: true /jsonfile@4.0.0: - resolution: - { - integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==, - } + resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} optionalDependencies: graceful-fs: 4.2.11 dev: true /jsonfile@6.1.0: - resolution: - { - integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==, - } + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} dependencies: universalify: 2.0.1 optionalDependencies: @@ -4230,18 +3126,12 @@ packages: dev: true /jsonschema@1.4.1: - resolution: - { - integrity: sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==, - } + resolution: {integrity: sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==} dev: true /keccak@3.0.4: - resolution: - { - integrity: sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==, - } - engines: { node: ">=10.0.0" } + resolution: {integrity: sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==} + engines: {node: '>=10.0.0'} requiresBuild: true dependencies: node-addon-api: 2.0.2 @@ -4250,160 +3140,101 @@ packages: dev: true /keyv@4.5.4: - resolution: - { - integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==, - } + 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" } + 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==, - } + 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" } + resolution: {integrity: sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==} + engines: {node: '>=14.16'} dependencies: package-json: 8.1.1 dev: true /levn@0.3.0: - resolution: - { - integrity: sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==, - } - engines: { node: ">= 0.8.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==, - } + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} dev: true /locate-path@2.0.0: - resolution: - { - integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==, - } - engines: { node: ">=4" } + 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" } + 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==, - } + resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} dev: true /lodash@4.17.21: - resolution: - { - integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==, - } + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} dev: true /log-symbols@4.1.0: - resolution: - { - integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==, - } - engines: { node: ">=10" } + 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@10.2.0: - resolution: - { - integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==, - } - engines: { node: 14 || >=16.14 } + resolution: {integrity: sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dev: true /lru-cache@6.0.0: - resolution: - { - integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==, - } - engines: { node: ">=10" } + 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==, - } + resolution: {integrity: sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==} dev: true /match-all@1.2.6: - resolution: - { - integrity: sha512-0EESkXiTkWzrQQntBu2uzKvLu6vVkUGz40nGPbSZuegcfE5UuSzNjLaIu76zJWuaT/2I3Z/8M06OlUOZLGwLlQ==, - } + resolution: {integrity: sha512-0EESkXiTkWzrQQntBu2uzKvLu6vVkUGz40nGPbSZuegcfE5UuSzNjLaIu76zJWuaT/2I3Z/8M06OlUOZLGwLlQ==} dev: true /mcl-wasm@1.4.0: - resolution: - { - integrity: sha512-90Tvmg2NXwnKMgTafA01PRELsYNNRb/F2bj3nzdByTLLMUmgkgL8H/oeWcjZtVVffnBJyNjDcYxY7cdOE/WoHg==, - } - engines: { node: ">=14.17" } + resolution: {integrity: sha512-90Tvmg2NXwnKMgTafA01PRELsYNNRb/F2bj3nzdByTLLMUmgkgL8H/oeWcjZtVVffnBJyNjDcYxY7cdOE/WoHg==} + engines: {node: '>=14.17'} dependencies: - "@types/node": 20.11.20 + '@types/node': 20.11.20 dev: true /md5.js@1.3.5: - resolution: - { - integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==, - } + resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} dependencies: hash-base: 3.1.0 inherits: 2.0.4 @@ -4411,157 +3242,130 @@ packages: dev: true /memorystream@0.3.1: - resolution: - { - integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==, - } - engines: { node: ">= 0.10.0" } + 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" } + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} dev: true /micro-ftch@0.3.1: - resolution: - { - integrity: sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==, - } + resolution: {integrity: sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==} dev: true /micromatch@4.0.5: - resolution: - { - integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==, - } - engines: { node: ">=8.6" } + 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" } + 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" } + 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" } + 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 } + 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==, - } + resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} dev: true /minimalistic-crypto-utils@1.0.1: - resolution: - { - integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==, - } + resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} dev: true /minimatch@3.1.2: - resolution: - { - integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==, - } + 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" } + 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" } + 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==, - } + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} dev: true /mkdirp@0.5.6: - resolution: - { - integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==, - } + 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" } + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} hasBin: true dev: true /mnemonist@0.38.5: - resolution: - { - integrity: sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg==, - } + resolution: {integrity: sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg==} dependencies: obliterator: 2.0.4 dev: true /mocha@10.3.0: - resolution: - { - integrity: sha512-uF2XJs+7xSLsrmIvn37i/wnc91nw7XjOQB8ccyx5aEgdnohr7n+rEiZP23WkCYHjilR6+EboEnbq/ZQDz4LSbg==, - } - engines: { node: ">= 14.0.0" } + resolution: {integrity: sha512-uF2XJs+7xSLsrmIvn37i/wnc91nw7XjOQB8ccyx5aEgdnohr7n+rEiZP23WkCYHjilR6+EboEnbq/ZQDz4LSbg==} + 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: 8.1.0 + he: 1.2.0 + js-yaml: 4.1.0 + log-symbols: 4.1.0 + minimatch: 5.0.1 + ms: 2.1.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 + + /mocha@10.4.0: + resolution: {integrity: sha512-eqhGB8JKapEYcC4ytX/xrzKforgEc3j1pGlAXVy3eRwrtAy5/nIfT1SvgGzfN0XZZxeLq0aQWkOUAmqIJiv+bA==} + engines: {node: '>= 14.0.0'} hasBin: true dependencies: ansi-colors: 4.1.1 @@ -4587,24 +3391,15 @@ packages: dev: true /ms@2.1.2: - resolution: - { - integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==, - } + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} dev: true /ms@2.1.3: - resolution: - { - integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==, - } + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} dev: true /murmur-128@0.2.1: - resolution: - { - integrity: sha512-WseEgiRkI6aMFBbj8Cg9yBj/y+OdipwVC7zUo3W2W1JAJITwouUOtpqsmGSg67EQmwwSyod7hsVsWY5LsrfQVg==, - } + resolution: {integrity: sha512-WseEgiRkI6aMFBbj8Cg9yBj/y+OdipwVC7zUo3W2W1JAJITwouUOtpqsmGSg67EQmwwSyod7hsVsWY5LsrfQVg==} dependencies: encode-utf8: 1.0.3 fmix: 0.1.0 @@ -4612,34 +3407,22 @@ packages: dev: true /neo-async@2.6.2: - resolution: - { - integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==, - } + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} dev: true /node-addon-api@2.0.2: - resolution: - { - integrity: sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==, - } + resolution: {integrity: sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==} dev: true /node-emoji@1.11.0: - resolution: - { - integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==, - } + 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 } + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} peerDependencies: encoding: ^0.1.0 peerDependenciesMeta: @@ -4650,87 +3433,57 @@ packages: dev: true /node-gyp-build@4.8.0: - resolution: - { - integrity: sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==, - } + 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" } + 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==, - } + 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" } + 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" } + 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" } + 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==, - } + resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} dev: true /obliterator@2.0.4: - resolution: - { - integrity: sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==, - } + resolution: {integrity: sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==} dev: true /once@1.4.0: - resolution: - { - integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==, - } + 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" } + resolution: {integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==} + engines: {node: '>= 0.8.0'} dependencies: deep-is: 0.1.4 fast-levenshtein: 2.0.6 @@ -4741,85 +3494,58 @@ packages: dev: true /os-tmpdir@1.0.2: - resolution: - { - integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==, - } - engines: { node: ">=0.10.0" } + 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" } + resolution: {integrity: sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==} + engines: {node: '>=12.20'} dev: true /p-limit@1.3.0: - resolution: - { - integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==, - } - engines: { node: ">=4" } + 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" } + 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" } + 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" } + 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" } + 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" } + 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" } + resolution: {integrity: sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==} + engines: {node: '>=14.16'} dependencies: got: 12.6.1 registry-auth-token: 5.0.2 @@ -4828,73 +3554,49 @@ packages: dev: true /parent-module@1.0.1: - resolution: - { - integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==, - } - engines: { node: ">=6" } + 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" } + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} dependencies: - "@babel/code-frame": 7.23.5 + '@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" } + 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" } + 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" } + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} dev: true /path-parse@1.0.7: - resolution: - { - integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==, - } + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} dev: true /path-type@4.0.0: - resolution: - { - integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} dev: true /pbkdf2@3.1.2: - resolution: - { - integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==, - } - engines: { node: ">=0.12" } + resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} + engines: {node: '>=0.12'} dependencies: create-hash: 1.2.0 create-hmac: 1.1.7 @@ -4904,101 +3606,65 @@ packages: dev: true /picomatch@2.3.1: - resolution: - { - integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==, - } - engines: { node: ">=8.6" } + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} dev: true /pify@4.0.1: - resolution: - { - integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==, - } - engines: { node: ">=6" } + resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} + engines: {node: '>=6'} dev: true /pluralize@8.0.0: - resolution: - { - integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==, - } - engines: { node: ">=4" } + 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" } + 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" } + 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==, - } + resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} dev: true /punycode@2.3.1: - resolution: - { - integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==, - } - engines: { node: ">=6" } + 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" } + resolution: {integrity: sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==} + engines: {node: '>=0.6'} dependencies: side-channel: 1.0.5 dev: true /queue-microtask@1.2.3: - resolution: - { - integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==, - } + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true /quick-lru@5.1.1: - resolution: - { - integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} + engines: {node: '>=10'} dev: true /randombytes@2.1.0: - resolution: - { - integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==, - } + 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" } + resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} + engines: {node: '>= 0.8'} dependencies: bytes: 3.1.2 http-errors: 2.0.0 @@ -5007,10 +3673,7 @@ packages: dev: true /rc@1.2.8: - resolution: - { - integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==, - } + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true dependencies: deep-extend: 0.6.0 @@ -5020,11 +3683,8 @@ packages: dev: true /readable-stream@3.6.2: - resolution: - { - integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==, - } - engines: { node: ">= 6" } + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} dependencies: inherits: 2.0.4 string_decoder: 1.3.0 @@ -5032,107 +3692,71 @@ packages: dev: true /readdirp@3.6.0: - resolution: - { - integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==, - } - engines: { node: ">=8.10.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" } + 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" } + 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" } + resolution: {integrity: sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==} + engines: {node: '>=14'} dependencies: - "@pnpm/npm-conf": 2.2.2 + '@pnpm/npm-conf': 2.2.2 dev: true /registry-url@6.0.1: - resolution: - { - integrity: sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==, - } - engines: { node: ">=12" } + 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" } + 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" } + 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==, - } + 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" } + 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==, - } + resolution: {integrity: sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==} dev: true /resolve@1.17.0: - resolution: - { - integrity: sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==, - } + 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==, - } + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true dependencies: is-core-module: 2.13.1 @@ -5141,104 +3765,54 @@ packages: dev: true /responselike@3.0.0: - resolution: - { - integrity: sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==, - } - engines: { node: ">=14.16" } + 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" } + 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==, - } + resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} hasBin: true dependencies: - glob: 7.2.0 + glob: 7.2.3 dev: true /ripemd160@2.0.2: - resolution: - { - integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==, - } + 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==, - } + resolution: {integrity: sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==} hasBin: true dependencies: bn.js: 5.2.1 dev: true /run-parallel@1.2.0: - resolution: - { - integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==, - } + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} dependencies: queue-microtask: 1.2.3 dev: true - /rust-verkle-wasm@0.0.1: - resolution: - { - integrity: sha512-BN6fiTsxcd2dCECz/cHtGTt9cdLJR925nh7iAuRcj8ymKw7OOaPmCneQZ7JePOJ/ia27TjEL91VdOi88Yf+mcA==, - } - dev: true - - /rustbn-wasm@0.2.0: - resolution: - { - integrity: sha512-FThvYFNTqrEKGqXuseeg0zR7yROh/6U1617mCHF68OVqrN1tNKRN7Tdwy4WayPVsCmmK+eMxtIZX1qL6JxTkMg==, - } - dependencies: - "@scure/base": 1.1.5 - 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==, - } + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} dev: true /safer-buffer@2.1.2: - resolution: - { - integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==, - } + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} dev: true /sc-istanbul@0.4.6: - resolution: - { - integrity: sha512-qJFF/8tW/zJsbyfh/iT/ZM5QNHE3CXxtLJbZsL+CzdJLBsPD7SedJZoUA4d8iAcN2IoMp/Dx80shOOd2x96X/g==, - } + resolution: {integrity: sha512-qJFF/8tW/zJsbyfh/iT/ZM5QNHE3CXxtLJbZsL+CzdJLBsPD7SedJZoUA4d8iAcN2IoMp/Dx80shOOd2x96X/g==} hasBin: true dependencies: abbrev: 1.0.9 @@ -5258,18 +3832,12 @@ packages: dev: true /scrypt-js@3.0.1: - resolution: - { - integrity: sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==, - } + resolution: {integrity: sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==} dev: true /secp256k1@4.0.3: - resolution: - { - integrity: sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==, - } - engines: { node: ">=10.0.0" } + resolution: {integrity: sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==} + engines: {node: '>=10.0.0'} requiresBuild: true dependencies: elliptic: 6.5.4 @@ -5278,47 +3846,32 @@ packages: dev: true /semver@5.7.2: - resolution: - { - integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==, - } + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} hasBin: true dev: true /semver@6.3.1: - resolution: - { - integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==, - } + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true dev: true /semver@7.6.0: - resolution: - { - integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} + engines: {node: '>=10'} hasBin: true dependencies: lru-cache: 6.0.0 dev: true /serialize-javascript@6.0.0: - resolution: - { - integrity: sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==, - } + resolution: {integrity: sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==} dependencies: randombytes: 2.1.0 dev: true /set-function-length@1.2.1: - resolution: - { - integrity: sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==, - } - engines: { node: ">= 0.4" } + resolution: {integrity: sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==} + engines: {node: '>= 0.4'} dependencies: define-data-property: 1.1.4 es-errors: 1.3.0 @@ -5329,24 +3882,15 @@ packages: dev: true /setimmediate@1.0.5: - resolution: - { - integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==, - } + resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} dev: true /setprototypeof@1.2.0: - resolution: - { - integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==, - } + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} dev: true /sha.js@2.4.11: - resolution: - { - integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==, - } + resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==} hasBin: true dependencies: inherits: 2.0.4 @@ -5354,11 +3898,8 @@ packages: dev: true /shelljs@0.8.5: - resolution: - { - integrity: sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==, - } - engines: { node: ">=4" } + resolution: {integrity: sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==} + engines: {node: '>=4'} hasBin: true dependencies: glob: 7.2.3 @@ -5367,11 +3908,8 @@ packages: dev: true /side-channel@1.0.5: - resolution: - { - integrity: sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==, - } - engines: { node: ">= 0.4" } + resolution: {integrity: sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 es-errors: 1.3.0 @@ -5380,19 +3918,13 @@ packages: dev: true /slash@3.0.0: - resolution: - { - integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==, - } - engines: { node: ">=8" } + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} dev: true /slice-ansi@4.0.0: - resolution: - { - integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} + engines: {node: '>=10'} dependencies: ansi-styles: 4.3.0 astral-regex: 2.0.0 @@ -5400,16 +3932,13 @@ packages: dev: true /solc@0.7.3(debug@4.3.4): - resolution: - { - integrity: sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA==, - } - engines: { node: ">=8.0.0" } + 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) + follow-redirects: 1.15.6(debug@4.3.4) fs-extra: 0.30.0 js-sha3: 0.8.0 memorystream: 0.3.1 @@ -5420,20 +3949,17 @@ packages: - debug dev: true - /solhint@4.1.1(typescript@5.3.3): - resolution: - { - integrity: sha512-7G4iF8H5hKHc0tR+/uyZesSKtfppFIMvPSW+Ku6MSL25oVRuyFeqNhOsXHfkex64wYJyXs4fe+pvhB069I19Tw==, - } + /solhint@4.1.1(typescript@5.4.4): + resolution: {integrity: sha512-7G4iF8H5hKHc0tR+/uyZesSKtfppFIMvPSW+Ku6MSL25oVRuyFeqNhOsXHfkex64wYJyXs4fe+pvhB069I19Tw==} hasBin: true dependencies: - "@solidity-parser/parser": 0.16.2 + '@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) + cosmiconfig: 8.3.6(typescript@5.4.4) fast-diff: 1.3.0 glob: 8.1.0 ignore: 5.3.1 @@ -5451,17 +3977,14 @@ packages: - typescript dev: true - /solidity-coverage@0.8.8(hardhat@2.20.1): - resolution: - { - integrity: sha512-7RN6/8YAFMQNeMdSulARtE0VC5JitBAUMwvkr10FkOK+nux5q+WykrgSZntkWrX/VHzRa096P4OOViO0T9Q9Cw==, - } + /solidity-coverage@0.8.8(hardhat@2.22.2): + resolution: {integrity: sha512-7RN6/8YAFMQNeMdSulARtE0VC5JitBAUMwvkr10FkOK+nux5q+WykrgSZntkWrX/VHzRa096P4OOViO0T9Q9Cw==} hasBin: true peerDependencies: hardhat: ^2.11.0 dependencies: - "@ethersproject/abi": 5.7.0 - "@solidity-parser/parser": 0.18.0 + '@ethersproject/abi': 5.7.0 + '@solidity-parser/parser': 0.18.0 chalk: 2.4.2 death: 1.1.0 difflib: 0.2.4 @@ -5469,7 +3992,7 @@ packages: ghost-testrpc: 0.0.2 global-modules: 2.0.0 globby: 10.0.2 - hardhat: 2.20.1(typescript@5.3.3) + hardhat: 2.22.2(typescript@5.4.4) jsonschema: 1.4.1 lodash: 4.17.21 mocha: 10.3.0 @@ -5483,21 +4006,15 @@ packages: dev: true /source-map-support@0.5.21: - resolution: - { - integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==, - } + 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" } + resolution: {integrity: sha512-CBdZ2oa/BHhS4xj5DlhjWNHcan57/5YuvfdLf17iVmIpd9KRm+DFLmC6nBNj+6Ua7Kt3TmOjDpQT1aTYOQtoUA==} + engines: {node: '>=0.8.0'} requiresBuild: true dependencies: amdefine: 1.0.1 @@ -5505,44 +4022,29 @@ packages: optional: true /source-map@0.6.1: - resolution: - { - integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==, - } - engines: { node: ">=0.10.0" } + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} dev: true /sprintf-js@1.0.3: - resolution: - { - integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==, - } + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} dev: true /stacktrace-parser@0.1.10: - resolution: - { - integrity: sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==, - } - engines: { node: ">=6" } + 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" } + 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" } + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} dependencies: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 @@ -5550,104 +4052,71 @@ packages: dev: true /string_decoder@1.3.0: - resolution: - { - integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==, - } + 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" } + 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" } + 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" } + 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" } + 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" } + 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" } + 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" } + 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" } + 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" } + 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" } + resolution: {integrity: sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==} + engines: {node: '>=10.0.0'} dependencies: ajv: 8.12.0 lodash.truncate: 4.4.2 @@ -5657,141 +4126,93 @@ packages: dev: true /test-value@2.1.0: - resolution: - { - integrity: sha512-+1epbAxtKeXttkGFMTX9H42oqzOTufR1ceCF+GYA5aOmvaPq9wd4PUS8329fn2RRLGNeUkgRLnVpycjx8DsO2w==, - } - engines: { node: ">=0.10.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==, - } + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true /tmp@0.0.33: - resolution: - { - integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==, - } - engines: { node: ">=0.6.0" } + 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" } + 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" } + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} dev: true /tr46@0.0.3: - resolution: - { - integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==, - } + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} dev: true - /ts-essentials@7.0.3(typescript@5.3.3): - resolution: - { - integrity: sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==, - } + /ts-essentials@7.0.3(typescript@5.4.4): + resolution: {integrity: sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==} peerDependencies: - typescript: ">=3.7.0" + typescript: '>=3.7.0' dependencies: - typescript: 5.3.3 + typescript: 5.4.4 dev: true /tslib@1.14.1: - resolution: - { - integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==, - } + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} dev: true /tsort@0.0.1: - resolution: - { - integrity: sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==, - } + resolution: {integrity: sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==} dev: true /tweetnacl-util@0.15.1: - resolution: - { - integrity: sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==, - } + resolution: {integrity: sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==} dev: true /tweetnacl@1.0.3: - resolution: - { - integrity: sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==, - } + resolution: {integrity: sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==} dev: true /type-check@0.3.2: - resolution: - { - integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==, - } - engines: { node: ">= 0.8.0" } + 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" } + 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" } + 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==, - } + resolution: {integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==} + engines: {node: '>=8'} + dev: true + + /typechain@5.2.0(typescript@5.4.4): + resolution: {integrity: sha512-0INirvQ+P+MwJOeMct+WLkUE4zov06QxC96D+i3uGFEHoiSkZN70MKDQsaj8zkL86wQwByJReI2e7fOUwECFuw==} hasBin: true peerDependencies: - typescript: ">=4.1.0" + typescript: '>=4.1.0' dependencies: - "@types/prettier": 2.7.3 + '@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 @@ -5800,128 +4221,86 @@ packages: 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 + ts-essentials: 7.0.3(typescript@5.4.4) + typescript: 5.4.4 transitivePeerDependencies: - supports-color dev: true /typescript@4.9.5: - resolution: - { - integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==, - } - engines: { node: ">=4.2.0" } + 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" } + /typescript@5.4.4: + resolution: {integrity: sha512-dGE2Vv8cpVvw28v8HCPqyb08EzbBURxDpuhJvTrusShUfGnhHBafDsLdS1EhhxyL6BJQE+2cT3dDPAv+MQ6oLw==} + engines: {node: '>=14.17'} hasBin: true dev: true /typical@2.6.1: - resolution: - { - integrity: sha512-ofhi8kjIje6npGozTip9Fr8iecmYfEbS06i0JnIg+rh51KakryWF4+jX8lLKZVhy6N+ID45WYSFCxPOdTWCzNg==, - } + 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" } + 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==, - } + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} dev: true - /undici@5.28.3: - resolution: - { - integrity: sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==, - } - engines: { node: ">=14.0" } + /undici@5.28.4: + resolution: {integrity: sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==} + engines: {node: '>=14.0'} dependencies: - "@fastify/busboy": 2.1.0 + '@fastify/busboy': 2.1.1 dev: true /universalify@0.1.2: - resolution: - { - integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==, - } - engines: { node: ">= 4.0.0" } + 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" } + 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" } + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} dev: true /uri-js@4.4.1: - resolution: - { - integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==, - } + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: punycode: 2.3.1 dev: true /utf8@3.0.0: - resolution: - { - integrity: sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==, - } + resolution: {integrity: sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==} dev: true /util-deprecate@1.0.2: - resolution: - { - integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==, - } + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} dev: true /uuid@8.3.2: - resolution: - { - integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==, - } + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} hasBin: true dev: true /web3-utils@1.10.4: - resolution: - { - integrity: sha512-tsu8FiKJLk2PzhDl9fXbGUWTkkVXYhtTA+SmEFkKft+9BgwLxfCRpU96sWv7ICC8zixBNd3JURVoiR3dUXgP8A==, - } - engines: { node: ">=8.0.0" } + resolution: {integrity: sha512-tsu8FiKJLk2PzhDl9fXbGUWTkkVXYhtTA+SmEFkKft+9BgwLxfCRpU96sWv7ICC8zixBNd3JURVoiR3dUXgP8A==} + engines: {node: '>=8.0.0'} dependencies: - "@ethereumjs/util": 8.1.0 + '@ethereumjs/util': 8.1.0 bn.js: 5.2.1 ethereum-bloom-filters: 1.0.10 ethereum-cryptography: 2.1.3 @@ -5932,70 +4311,46 @@ packages: dev: true /webidl-conversions@3.0.1: - resolution: - { - integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==, - } + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} dev: true /whatwg-url@5.0.0: - resolution: - { - integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==, - } + 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==, - } + 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" } + 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" } + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} dev: true /wordwrap@1.0.0: - resolution: - { - integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==, - } + resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} dev: true /workerpool@6.2.1: - resolution: - { - integrity: sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==, - } + resolution: {integrity: sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==} dev: true /wrap-ansi@7.0.0: - resolution: - { - integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} dependencies: ansi-styles: 4.3.0 string-width: 4.2.3 @@ -6003,18 +4358,12 @@ packages: dev: true /wrappy@1.0.2: - resolution: - { - integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==, - } + 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" } + resolution: {integrity: sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==} + engines: {node: '>=8.3.0'} peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ^5.0.2 @@ -6026,11 +4375,8 @@ packages: dev: true /ws@7.5.9: - resolution: - { - integrity: sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==, - } - engines: { node: ">=8.3.0" } + resolution: {integrity: sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==} + engines: {node: '>=8.3.0'} peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ^5.0.2 @@ -6042,34 +4388,22 @@ packages: dev: true /y18n@5.0.8: - resolution: - { - integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} dev: true /yallist@4.0.0: - resolution: - { - integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==, - } + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} dev: true /yargs-parser@20.2.4: - resolution: - { - integrity: sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==} + engines: {node: '>=10'} dev: true /yargs-unparser@2.0.0: - resolution: - { - integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} + engines: {node: '>=10'} dependencies: camelcase: 6.3.0 decamelize: 4.0.0 @@ -6078,11 +4412,8 @@ packages: dev: true /yargs@16.2.0: - resolution: - { - integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==, - } - engines: { node: ">=10" } + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} dependencies: cliui: 7.0.4 escalade: 3.1.2 @@ -6094,18 +4425,12 @@ packages: dev: true /yocto-queue@0.1.0: - resolution: - { - integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==, - } - engines: { node: ">=10" } + 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==, - } + 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 @@ -6114,45 +4439,44 @@ packages: dev: true github.com/dapphub/ds-test/e282159d5170298eb2455a6c05280ab5a73a4ef0: - resolution: - { - tarball: https://codeload.github.com/dapphub/ds-test/tar.gz/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/9b6b326bdb5df94f29091280b281a617084dfba1: - resolution: - { - tarball: https://codeload.github.com/erc7579/erc7579-implementation/tar.gz/9b6b326bdb5df94f29091280b281a617084dfba1, - } + resolution: {tarball: https://codeload.github.com/erc7579/erc7579-implementation/tar.gz/9b6b326bdb5df94f29091280b281a617084dfba1} + name: micro-msa + version: 0.3.1 + dependencies: + '@openzeppelin/contracts': 5.0.1 + dev: true + + github.com/erc7579/erc7579-implementation/c28f305d96467200c44c1ee3af2a7bb184dc0420: + resolution: {tarball: https://codeload.github.com/erc7579/erc7579-implementation/tar.gz/c28f305d96467200c44c1ee3af2a7bb184dc0420} name: micro-msa version: 0.3.1 dependencies: - "@openzeppelin/contracts": 5.0.1 + '@openzeppelin/contracts': 5.0.1 dev: true - github.com/eth-infinitism/account-abstraction/7174d6d845618dbd11cee68eefa715f5263690b6(ethers@5.4.0)(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, - } + github.com/eth-infinitism/account-abstraction/7174d6d845618dbd11cee68eefa715f5263690b6(ethers@5.4.0)(hardhat@2.22.2)(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.4.0) - "@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 + '@gnosis.pm/safe-contracts': 1.3.0(ethers@5.4.0) + '@nomiclabs/hardhat-etherscan': 2.1.8(hardhat@2.22.2) + '@openzeppelin/contracts': 4.9.5 + '@thehubbleproject/bls': 0.5.1 + '@typechain/hardhat': 2.3.1(hardhat@2.22.2)(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.20.1) - solidity-coverage: 0.8.8(hardhat@2.20.1) + hardhat-deploy-ethers: 0.3.0-beta.13(ethers@5.4.0)(hardhat@2.22.2) + solidity-coverage: 0.8.8(hardhat@2.22.2) source-map-support: 0.5.21 table: 6.8.1 typescript: 4.9.5 @@ -6167,26 +4491,23 @@ packages: - 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, - } + github.com/eth-infinitism/account-abstraction/7174d6d845618dbd11cee68eefa715f5263690b6(ethers@5.7.2)(hardhat@2.22.2)(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 + '@gnosis.pm/safe-contracts': 1.3.0(ethers@5.7.2) + '@nomiclabs/hardhat-etherscan': 2.1.8(hardhat@2.22.2) + '@openzeppelin/contracts': 4.9.5 + '@thehubbleproject/bls': 0.5.1 + '@typechain/hardhat': 2.3.1(hardhat@2.22.2)(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) + hardhat-deploy-ethers: 0.3.0-beta.13(ethers@5.7.2)(hardhat@2.22.2) + solidity-coverage: 0.8.8(hardhat@2.22.2) source-map-support: 0.5.21 table: 6.8.1 typescript: 4.9.5 @@ -6202,35 +4523,29 @@ packages: dev: true github.com/foundry-rs/forge-std/1d0766bc5d814f117c7b1e643828f7d85024fb51: - resolution: - { - tarball: https://codeload.github.com/foundry-rs/forge-std/tar.gz/1d0766bc5d814f117c7b1e643828f7d85024fb51, - } + resolution: {tarball: https://codeload.github.com/foundry-rs/forge-std/tar.gz/1d0766bc5d814f117c7b1e643828f7d85024fb51} name: forge-std version: 1.7.6 dev: true - github.com/kopy-kat/account-abstraction/3c0127e9f7cb76e4a0fdb2d35cac51900f252bdc(ethers@5.4.0)(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, - } + github.com/kopy-kat/account-abstraction/3c0127e9f7cb76e4a0fdb2d35cac51900f252bdc(ethers@5.4.0)(hardhat@2.22.2)(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 + '@nomiclabs/hardhat-etherscan': 2.1.8(hardhat@2.22.2) + '@openzeppelin/contracts': 5.0.1 + '@thehubbleproject/bls': 0.5.1 + '@typechain/hardhat': 2.3.1(hardhat@2.22.2)(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.4.0)(hardhat@2.20.1) - solidity-coverage: 0.8.8(hardhat@2.20.1) + hardhat-deploy-ethers: 0.3.0-beta.13(ethers@5.4.0)(hardhat@2.22.2) + solidity-coverage: 0.8.8(hardhat@2.22.2) source-map-support: 0.5.21 table: 6.8.1 typescript: 4.9.5 @@ -6245,27 +4560,24 @@ packages: - 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, - } + github.com/kopy-kat/account-abstraction/3c0127e9f7cb76e4a0fdb2d35cac51900f252bdc(ethers@5.7.2)(hardhat@2.22.2)(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 + '@nomiclabs/hardhat-etherscan': 2.1.8(hardhat@2.22.2) + '@openzeppelin/contracts': 5.0.1 + '@thehubbleproject/bls': 0.5.1 + '@typechain/hardhat': 2.3.1(hardhat@2.22.2)(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) + hardhat-deploy-ethers: 0.3.0-beta.13(ethers@5.7.2)(hardhat@2.22.2) + solidity-coverage: 0.8.8(hardhat@2.22.2) source-map-support: 0.5.21 table: 6.8.1 typescript: 4.9.5 @@ -6281,49 +4593,34 @@ packages: dev: true github.com/rhinestonewtf/erc4337-validation/19a97d86f8f29709664334078925b2a843be19e0: - resolution: - { - tarball: https://codeload.github.com/rhinestonewtf/erc4337-validation/tar.gz/19a97d86f8f29709664334078925b2a843be19e0, - } + resolution: {tarball: https://codeload.github.com/rhinestonewtf/erc4337-validation/tar.gz/19a97d86f8f29709664334078925b2a843be19e0} name: erc4337-validation version: 0.0.1 dependencies: - "@openzeppelin/contracts": 5.0.1 + '@openzeppelin/contracts': 5.0.1 solady: github.com/vectorized/solady/72e47ca417d24a30801b2921584e8486462cfc7b dev: true github.com/sablier-labs/solarray/6bf10cb34cdace52a3ba5fe437e78cc82df92684: - resolution: - { - tarball: https://codeload.github.com/sablier-labs/solarray/tar.gz/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, - } + 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, - } + resolution: {tarball: https://codeload.github.com/vectorized/solady/tar.gz/72e47ca417d24a30801b2921584e8486462cfc7b} name: solady version: 0.0.170 dev: true github.com/zeroknots/sentinellist/6294bf412489c0f6d3b9c92ad0aceb08c5b8704b: - resolution: - { - tarball: https://codeload.github.com/zeroknots/sentinellist/tar.gz/6294bf412489c0f6d3b9c92ad0aceb08c5b8704b, - } + resolution: {tarball: https://codeload.github.com/zeroknots/sentinellist/tar.gz/6294bf412489c0f6d3b9c92ad0aceb08c5b8704b} name: sentinellist version: 1.0.0 dev: true From 6e620ce517860e4bc4f5d62bbe389416f713ceac Mon Sep 17 00:00:00 2001 From: zeroknots Date: Mon, 8 Apr 2024 13:53:37 +0700 Subject: [PATCH 30/64] clean up --- accounts/safe7579/README.md | 48 +++++++ accounts/safe7579/src/SafeERC7579.sol | 1 - .../safe7579/src/core/RegistryAdapter.sol | 12 +- accounts/safe7579/src/utils/Launchpad.sol | 91 ------------- accounts/safe7579/src/utils/Launchpadv2.sol | 6 + accounts/safe7579/test/Base.t.sol | 128 ------------------ accounts/safe7579/test/Launchpad.t.sol | 13 +- accounts/safe7579/test/mocks/MockRegistry.sol | 2 + 8 files changed, 75 insertions(+), 226 deletions(-) create mode 100644 accounts/safe7579/README.md delete mode 100644 accounts/safe7579/src/utils/Launchpad.sol delete mode 100644 accounts/safe7579/test/Base.t.sol diff --git a/accounts/safe7579/README.md b/accounts/safe7579/README.md new file mode 100644 index 00000000..1535a2ef --- /dev/null +++ b/accounts/safe7579/README.md @@ -0,0 +1,48 @@ +sequenceDiagram +participant Sender +participant Entrypoint +participant SenderCreator +participant SafeProxyFactory +participant SafeProxy +participant SafeSingleton +participant Launchpad +participant Safe7579 + +rect rgb(255,179,186) +Sender->>Entrypoint: handleUserOps +Entrypoint->>SenderCreator: create this initcode +SenderCreator->>+SafeProxyFactory: createProxyWithNonce(launchpad, intializer, salt) +SafeProxyFactory-->>SafeProxy: create2 +SafeProxy-->Launchpad: singleton = launchpad +SafeProxyFactory->>+SafeProxy: preValidationSetup (initHash, to, preInit) +SafeProxy-->>+Launchpad: preValidationSetup (initHash, to, preInit) [delegatecall] +Note over Launchpad: sstore initHash +Launchpad ->> Registry: set Attesters [call] +Note right of Registry: store attesters +SafeProxy-->>SafeProxyFactory: created +SafeProxyFactory-->>Entrypoint: created sender +end + +rect rgb(255,179,186) +Entrypoint->>+SafeProxy: validateUserOp +SafeProxy-->>Launchpad: validateUserOp [delegatecall] +Note right of Launchpad: only initializeThenUserOp.selector +Note over Launchpad: restore and check inithash (sload) +Launchpad-->>SafeProxy: packedValid +SafeProxy->>-Entrypoint: packedValid +end +rect rgb(186,225,255) +Entrypoint->>+SafeProxy: initializeThenUserOp +SafeProxy-->>Launchpad: initializeThenUserOp [delegatecall] +Note over SafeProxy, Launchpad: sstore safe.singleton == SafeSingleton +Launchpad->>SafeProxy: safe.setup() [call] +SafeProxy->>SafeSingleton: safe.setup() [delegatecall] +Note over SafeSingleton: setup function in Safe has a delegatecall +SafeSingleton-->>Launchpad: initSafe7579 [delegatecall] +Launchpad->>SafeProxy: this.enableModule(safe7579) +SafeProxy-->>SafeSingleton: enableModule (safe7579) [delegatecall] +Launchpad->>Safe7579: initializeAccount +Note over Safe7579: msg.sender: SafeProxy +Safe7579->SafeProxy: exec done +SafeProxy->-Entrypoint: exec done +end diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index 2f751f02..4b3fecbf 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -574,7 +574,6 @@ contract SafeERC7579 is uint8 threshold ) external - onlyEntryPointOrSelf { _configureRegistry(registry, attesters, threshold); } diff --git a/accounts/safe7579/src/core/RegistryAdapter.sol b/accounts/safe7579/src/core/RegistryAdapter.sol index 7821a2f4..4e386e93 100644 --- a/accounts/safe7579/src/core/RegistryAdapter.sol +++ b/accounts/safe7579/src/core/RegistryAdapter.sol @@ -2,8 +2,9 @@ pragma solidity ^0.8.23; import "../interfaces/IERC7484.sol"; +import "./ExecutionHelper.sol"; -contract RegistryAdapter { +abstract contract RegistryAdapter is ExecutionHelper { event ERC7484RegistryConfigured(address indexed smartAccount, address indexed registry); mapping(address smartAccount => IERC7484 registry) internal $registry; @@ -11,7 +12,7 @@ contract RegistryAdapter { modifier withRegistry(address module, uint256 moduleType) { IERC7484 registry = $registry[msg.sender]; if (address(registry) != address(0)) { - registry.check(module, moduleType); + registry.checkForAccount(msg.sender, module, moduleType); } _; } @@ -24,6 +25,11 @@ contract RegistryAdapter { internal { $registry[msg.sender] = registry; - registry.trustAttesters(threshold, attesters); + _execute( + msg.sender, + address(registry), + 0, + abi.encodeCall(IERC7484.trustAttesters, (threshold, attesters)) + ); } } diff --git a/accounts/safe7579/src/utils/Launchpad.sol b/accounts/safe7579/src/utils/Launchpad.sol deleted file mode 100644 index ceb5076c..00000000 --- a/accounts/safe7579/src/utils/Launchpad.sol +++ /dev/null @@ -1,91 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only -pragma solidity ^0.8.0; - -import { ISafe, SafeERC7579 } from "../SafeERC7579.sol"; -import { ISafe7579Init } from "../interfaces/ISafe7579Init.sol"; - -/** - * Helper contract that gets delegatecalled byt SafeProxy.setup() to setup safe7579 as a module - * (safe module) - * as well as initializing Safe7579 for the SafeProxy - */ -contract Safe7579Launchpad { - address public immutable SAFE7579Singleton; - - constructor(address _safe7579Singleton) { - SAFE7579Singleton = _safe7579Singleton; - } - - // function initSafe7579(address safe7579, bytes calldata safe7579InitCode) public { - // ISafe(address(this)).enableModule(safe7579); - // SafeERC7579(payable(safe7579)).initializeAccount(safe7579InitCode); - // } - - function initSafe7579( - address safe7579, - ISafe7579Init.ModuleInit[] calldata validators - ) - public - { - ISafe(address(this)).enableModule(safe7579); - SafeERC7579(payable(safe7579)).initializeAccount(abi.encode(validators)); - } - - function predictSafeAddress( - address singleton, - address safeProxyFactory, - bytes memory creationCode, - bytes32 salt, - bytes memory initializer - ) - external - pure - returns (address safeProxy) - { - salt = keccak256(abi.encodePacked(keccak256(initializer), salt)); - - safeProxy = address( - uint160( - uint256( - keccak256( - abi.encodePacked( - bytes1(0xff), - address(safeProxyFactory), - salt, - keccak256( - abi.encodePacked(creationCode, uint256(uint160(address(singleton)))) - ) - ) - ) - ) - ) - ); - } - - function getInitCode( - address[] memory signers, - uint256 threshold, - ISafe7579Init.ModuleInit[] calldata validators - ) - external - view - returns (bytes memory initCode) - { - bytes memory safeLaunchPadSetup = - abi.encodeCall(this.initSafe7579, (address(SAFE7579Singleton), validators)); - // SETUP SAFE - initCode = abi.encodeCall( - ISafe.setup, - ( - signers, - threshold, - address(this), - safeLaunchPadSetup, - SAFE7579Singleton, - address(0), - 0, - payable(address(0)) - ) - ); - } -} diff --git a/accounts/safe7579/src/utils/Launchpadv2.sol b/accounts/safe7579/src/utils/Launchpadv2.sol index 9e1dcf31..9026c5f3 100644 --- a/accounts/safe7579/src/utils/Launchpadv2.sol +++ b/accounts/safe7579/src/utils/Launchpadv2.sol @@ -12,6 +12,8 @@ import { SafeStorage } from "@safe-global/safe-contracts/contracts/libraries/Saf import { ISignatureValidator } from "@safe-global/safe-contracts/contracts/interfaces/ISignatureValidator.sol"; +import "forge-std/console2.sol"; + /** * @title SafeOpLaunchpad - A contract for Safe initialization with custom unique signers that would * violate ERC-4337 factory rules. @@ -135,6 +137,8 @@ contract SafeSignerLaunchpad is IAccount, SafeStorage { receive() external payable { } + function setupRegistry(address[] calldata attesters, uint8 threshold) external { } + function preValidationSetup( bytes32 initHash, address to, @@ -144,6 +148,7 @@ contract SafeSignerLaunchpad is IAccount, SafeStorage { onlyProxy { _setInitHash(initHash); + console2.log("this", address(this)); if (to != address(0)) { (bool success,) = to.delegatecall(preInit); require(success, "Pre-initialization failed"); @@ -265,6 +270,7 @@ contract SafeSignerLaunchpad is IAccount, SafeStorage { external onlySupportedEntryPoint { + // update singleton to Safe account impl SafeStorage.singleton = singleton; { // address[] memory owners = new address[](1); diff --git a/accounts/safe7579/test/Base.t.sol b/accounts/safe7579/test/Base.t.sol deleted file mode 100644 index d9bd7fd9..00000000 --- a/accounts/safe7579/test/Base.t.sol +++ /dev/null @@ -1,128 +0,0 @@ -// 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 "./mocks/MockTarget.sol"; - -import { Safe } from "@safe-global/safe-contracts/contracts/Safe.sol"; -import { SafeProxyFactory } from - "@safe-global/safe-contracts/contracts/proxies/SafeProxyFactory.sol"; -import { LibClone } from "solady/utils/LibClone.sol"; -import "src/utils/Launchpad.sol"; - -import { Solarray } from "solarray/Solarray.sol"; -import "./dependencies/EntryPoint.sol"; - -contract TestBaseUtil is Test { - SafeERC7579 safe7579; - Safe singleton; - Safe safe; - SafeProxyFactory safeProxyFactory; - Safe7579Launchpad launchpad; - - MockValidator defaultValidator; - MockExecutor defaultExecutor; - - Account signer1 = makeAccount("signer1"); - Account signer2 = makeAccount("signer2"); - - IEntryPoint entrypoint; - bytes userOpInitCode; - - function setUp() public virtual { - // Set up EntryPoint - entrypoint = etchEntrypoint(); - singleton = new Safe(); - safeProxyFactory = new SafeProxyFactory(); - safe7579 = new SafeERC7579(); - launchpad = new Safe7579Launchpad(address(safe7579)); - - // Set up Modules - defaultValidator = new MockValidator(); - defaultExecutor = new MockExecutor(); - - bytes32 salt; - - ISafe7579Init.ModuleInit[] memory validators = new ISafe7579Init.ModuleInit[](1); - validators[0] = - ISafe7579Init.ModuleInit({ module: address(defaultValidator), initData: bytes("") }); - ISafe7579Init.ModuleInit[] memory executors = new ISafe7579Init.ModuleInit[](1); - executors[0] = - ISafe7579Init.ModuleInit({ module: address(defaultExecutor), initData: bytes("") }); - // ISafe7579Init.ModuleInit[] memory fallbacks = new ISafe7579Init.ModuleInit[](0); - // ISafe7579Init.ModuleInit[] memory hooks = new ISafe7579Init.ModuleInit[](0); - - bytes memory initializer = launchpad.getInitCode({ - signers: Solarray.addresses(signer1.addr, signer2.addr), - threshold: 2, - validators: validators - }); - // computer counterfactual address for SafeProxy - safe = Safe( - payable( - launchpad.predictSafeAddress({ - singleton: address(singleton), - safeProxyFactory: address(safeProxyFactory), - creationCode: safeProxyFactory.proxyCreationCode(), - salt: salt, - initializer: initializer - }) - ) - ); - - PackedUserOperation memory userOp = - getDefaultUserOp(address(safe), address(defaultValidator)); - - userOp.callData = - abi.encodeCall(SafeERC7579.installModule, (2, address(defaultExecutor), bytes(""))); - userOp.initCode = initCode(initializer, salt); - PackedUserOperation[] memory userOps = new PackedUserOperation[](1); - userOps[0] = userOp; - deal(address(safe), 1 ether); - - entrypoint.handleOps(userOps, payable(address(0x69))); - } - - function initCode( - bytes memory initializer, - bytes32 salt - ) - internal - view - returns (bytes memory _initCode) - { - _initCode = abi.encodePacked( - address(safeProxyFactory), - abi.encodeCall( - SafeProxyFactory.createProxyWithNonce, - (address(singleton), initializer, uint256(salt)) - ) - ); - } - - function getDefaultUserOp( - address account, - address validator - ) - internal - view - returns (PackedUserOperation memory userOp) - { - userOp = PackedUserOperation({ - sender: account, - nonce: safe7579.getNonce(account, validator), - 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/Launchpad.t.sol b/accounts/safe7579/test/Launchpad.t.sol index f8206962..7dca3179 100644 --- a/accounts/safe7579/test/Launchpad.t.sol +++ b/accounts/safe7579/test/Launchpad.t.sol @@ -89,8 +89,8 @@ contract LaunchpadBase is Test { signerData: abi.encode(Solarray.addresses(signer1.addr, signer2.addr)), setupTo: address(launchpad), setupData: abi.encodeCall( - SafeSignerLaunchpad.initSafe7579WithRegistry, - (address(safe7579), validators, executors, fallbacks, hook, registryInit) + SafeSignerLaunchpad.initSafe7579, + (address(safe7579), validators, executors, fallbacks, hook) ), fallbackHandler: address(safe7579) }); @@ -104,7 +104,14 @@ contract LaunchpadBase is Test { }); bytes memory factoryInitializer = abi.encodeCall( - SafeSignerLaunchpad.preValidationSetup, (initHash, address(safe7579), "") + SafeSignerLaunchpad.preValidationSetup, + ( + initHash, + address(registryInit.registry), + abi.encodeCall( + IERC7484.trustAttesters, (registryInit.threshold, registryInit.attesters) + ) + ) ); PackedUserOperation memory userOp = diff --git a/accounts/safe7579/test/mocks/MockRegistry.sol b/accounts/safe7579/test/mocks/MockRegistry.sol index 51fbdfd7..067cfb98 100644 --- a/accounts/safe7579/test/mocks/MockRegistry.sol +++ b/accounts/safe7579/test/mocks/MockRegistry.sol @@ -5,6 +5,7 @@ import { IERC7484 } from "src/interfaces/IERC7484.sol"; contract MockRegistry is IERC7484 { event NewTrustedAttesters(); + event Log(address sender); function check(address module) external view override { } @@ -48,6 +49,7 @@ contract MockRegistry is IERC7484 { { } function trustAttesters(uint8 threshold, address[] calldata attesters) external override { + emit Log(msg.sender); emit NewTrustedAttesters(); } } From 56fb4b153a85343173e7c9cb078e789d9a6b90d4 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Tue, 9 Apr 2024 08:45:57 +0700 Subject: [PATCH 31/64] note --- accounts/safe7579/src/utils/Launchpadv2.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/accounts/safe7579/src/utils/Launchpadv2.sol b/accounts/safe7579/src/utils/Launchpadv2.sol index 9026c5f3..3a1b8008 100644 --- a/accounts/safe7579/src/utils/Launchpadv2.sol +++ b/accounts/safe7579/src/utils/Launchpadv2.sol @@ -258,6 +258,7 @@ contract SafeSignerLaunchpad is IAccount, SafeStorage { } } + // TODO: change to executeUserOp function initializeThenUserOp( address singleton, address signerFactory, From c0d450d8bf0249886d28970517578c467f3546d0 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Tue, 9 Apr 2024 12:21:48 +0700 Subject: [PATCH 32/64] implemented executeUserOp --- accounts/safe7579/src/utils/Launchpadv2.sol | 257 +++++++++----------- accounts/safe7579/test/Launchpad.t.sol | 70 ++---- 2 files changed, 144 insertions(+), 183 deletions(-) diff --git a/accounts/safe7579/src/utils/Launchpadv2.sol b/accounts/safe7579/src/utils/Launchpadv2.sol index 3a1b8008..570d5209 100644 --- a/accounts/safe7579/src/utils/Launchpadv2.sol +++ b/accounts/safe7579/src/utils/Launchpadv2.sol @@ -2,12 +2,19 @@ pragma solidity ^0.8.22; import { IAccount, PackedUserOperation } from "account-abstraction/interfaces/IAccount.sol"; -import { _packValidationData } from "account-abstraction/core/Helpers.sol"; +import { + _packValidationData, + _parseValidationData, + ValidationData +} from "account-abstraction/core/Helpers.sol"; import { ISafe } from "../interfaces/ISafe.sol"; import { IUniqueSignerFactory } from "./SignerFactory.sol"; import { ISafe7579Init } from "../interfaces/ISafe7579Init.sol"; +import { IERC7484 } from "../interfaces/IERC7484.sol"; import { SafeERC7579 } from "../SafeERC7579.sol"; +import { IValidator } from "erc7579/interfaces/IERC7579Module.sol"; + import { SafeStorage } from "@safe-global/safe-contracts/contracts/libraries/SafeStorage.sol"; import { ISignatureValidator } from "@safe-global/safe-contracts/contracts/interfaces/ISignatureValidator.sol"; @@ -21,6 +28,16 @@ import "forge-std/console2.sol"; * deploys the account. */ contract SafeSignerLaunchpad is IAccount, SafeStorage { + struct InitData { + address singleton; + address[] owners; + uint256 threshold; + address setupTo; + bytes setupData; + address safeFallbackHandler; + bytes callData; + } + bytes32 private constant DOMAIN_SEPARATOR_TYPEHASH = keccak256("EIP712Domain(uint256 chainId,address verifyingContract)"); @@ -57,12 +74,14 @@ contract SafeSignerLaunchpad is IAccount, SafeStorage { address private immutable SELF; address public immutable SUPPORTED_ENTRYPOINT; + IERC7484 public immutable REGISTRY; - constructor(address entryPoint) { + constructor(address entryPoint, IERC7484 registry) { require(entryPoint != address(0), "Invalid entry point"); SELF = address(this); SUPPORTED_ENTRYPOINT = entryPoint; + REGISTRY = registry; } function initSafe7579WithRegistry( @@ -71,13 +90,22 @@ contract SafeSignerLaunchpad is IAccount, SafeStorage { ISafe7579Init.ModuleInit[] calldata executors, ISafe7579Init.ModuleInit[] calldata fallbacks, ISafe7579Init.ModuleInit calldata hook, - ISafe7579Init.RegistryInit calldata registryInit + address[] calldata attesters, + uint8 threshold ) public { ISafe(address(this)).enableModule(safe7579); SafeERC7579(payable(safe7579)).initializeAccountWithRegistry( - validators, executors, fallbacks, hook, registryInit + validators, + executors, + fallbacks, + hook, + ISafe7579Init.RegistryInit({ + registry: REGISTRY, + attesters: attesters, + threshold: threshold + }) ); } @@ -94,37 +122,6 @@ contract SafeSignerLaunchpad is IAccount, SafeStorage { SafeERC7579(payable(safe7579)).initializeAccount(validators, executors, fallbacks, hook); } - function predictSafeAddress( - address singleton, - address safeProxyFactory, - bytes memory creationCode, - bytes32 salt, - bytes memory factoryInitializer - ) - external - pure - returns (address safeProxy) - { - salt = keccak256(abi.encodePacked(keccak256(factoryInitializer), salt)); - - safeProxy = address( - uint160( - uint256( - keccak256( - abi.encodePacked( - bytes1(0xff), - address(safeProxyFactory), - salt, - keccak256( - abi.encodePacked(creationCode, uint256(uint160(address(singleton)))) - ) - ) - ) - ) - ) - ); - } - modifier onlyProxy() { require(singleton == SELF, "Not called from proxy"); _; @@ -137,8 +134,6 @@ contract SafeSignerLaunchpad is IAccount, SafeStorage { receive() external payable { } - function setupRegistry(address[] calldata attesters, uint8 threshold) external { } - function preValidationSetup( bytes32 initHash, address to, @@ -155,50 +150,6 @@ contract SafeSignerLaunchpad is IAccount, SafeStorage { } } - function getInitHash( - address singleton, - address signerFactory, - bytes memory signerData, - address setupTo, - bytes memory setupData, - address fallbackHandler - ) - public - view - returns (bytes32 initHash) - { - initHash = keccak256( - abi.encodePacked( - bytes1(0x19), - bytes1(0x01), - _domainSeparator(), - keccak256( - abi.encode( - SAFE_INIT_TYPEHASH, - singleton, - signerFactory, - keccak256(signerData), - setupTo, - keccak256(setupData), - fallbackHandler - ) - ) - ) - ); - } - - function getOperationHash( - bytes32 userOpHash, - uint48 validAfter, - uint48 validUntil - ) - public - view - returns (bytes32 operationHash) - { - operationHash = keccak256(_getOperationData(userOpHash, validAfter, validUntil)); - } - function validateUserOp( PackedUserOperation calldata userOp, bytes32 userOpHash, @@ -210,45 +161,16 @@ contract SafeSignerLaunchpad is IAccount, SafeStorage { onlySupportedEntryPoint returns (uint256 validationData) { - address signerFactory; - bytes memory signerData; - { - require( - this.initializeThenUserOp.selector == bytes4(userOp.callData[:4]), - "invalid user operation data" - ); - - address singleton; - address setupTo; - bytes memory setupData; - address fallbackHandler; - (singleton, signerFactory, signerData, setupTo, setupData, fallbackHandler,) = abi - .decode(userOp.callData[4:], (address, address, bytes, address, bytes, address, bytes)); - bytes32 initHash = getInitHash( - singleton, signerFactory, signerData, setupTo, setupData, fallbackHandler - ); - - require(initHash == _initHash(), "invalid init hash"); - } + require( + this.executeUserOp.selector == bytes4(userOp.callData[:4]), + "invalid user operation data" + ); - uint48 validAfter; - uint48 validUntil; - bytes calldata signature; - { - bytes calldata sig = userOp.signature; - validAfter = uint48(bytes6(sig[0:6])); - validUntil = uint48(bytes6(sig[6:12])); - signature = sig[12:]; - } + InitData memory initData = abi.decode(userOp.callData[4:], (InitData)); - bytes memory operationData = _getOperationData(userOpHash, validAfter, validUntil); - // bytes4 magicValue = IUniqueSignerFactory(signerFactory).isValidSignatureForSigner( - // operationData, signature, signerData - // ); - bytes4 magicValue = ISignatureValidator.isValidSignature.selector; - validationData = _packValidationData( - magicValue != ISignatureValidator.isValidSignature.selector, validUntil, validAfter - ); + require(hash(initData) == _initHash(), "invalid init hash"); + + // TODO: is it a problem that we dont validate the signature with the validator here? if (missingAccountFunds > 0) { // solhint-disable-next-line no-inline-assembly @@ -258,33 +180,29 @@ contract SafeSignerLaunchpad is IAccount, SafeStorage { } } - // TODO: change to executeUserOp - function initializeThenUserOp( - address singleton, - address signerFactory, - bytes calldata signerData, - address setupTo, - bytes calldata setupData, - address fallbackHandler, - bytes memory callData + function executeUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash ) external onlySupportedEntryPoint { + InitData memory initData = abi.decode(userOp.callData[4:], (InitData)); // update singleton to Safe account impl - SafeStorage.singleton = singleton; - { - // address[] memory owners = new address[](1); - // owners[0] = IUniqueSignerFactory(signerFactory).createSigner(signerData); - - (address[] memory owners) = abi.decode(signerData, (address[])); - - ISafe(address(this)).setup( - owners, 1, setupTo, setupData, fallbackHandler, address(0), 0, payable(address(0)) - ); - } + SafeStorage.singleton = initData.singleton; + + ISafe(address(this)).setup( + initData.owners, + initData.threshold, + initData.setupTo, + initData.setupData, + initData.safeFallbackHandler, + address(0), + 0, + payable(address(0)) + ); - (bool success, bytes memory returnData) = address(this).delegatecall(callData); + (bool success, bytes memory returnData) = address(this).delegatecall(initData.callData); if (!success) { // solhint-disable-next-line no-inline-assembly assembly ("memory-safe") { @@ -293,6 +211,20 @@ contract SafeSignerLaunchpad is IAccount, SafeStorage { } _setInitHash(0); + + // validate user operation + address validator; + uint256 nonce = userOp.nonce; + + // solhint-disable-next-line no-inline-assembly + assembly { + validator := shr(96, nonce) + } + + uint256 ret = IValidator(validator).validateUserOp(userOp, userOpHash); + // TODO: unpack properly + // consider comparing validUntil/validAfter to userOp.signature + if (ret != 0) revert(); } function _domainSeparator() internal view returns (bytes32) { @@ -344,4 +276,51 @@ contract SafeSignerLaunchpad is IAccount, SafeStorage { /* solhint-enable no-inline-assembly */ return size > 0; } + + function getOperationHash( + bytes32 userOpHash, + uint48 validAfter, + uint48 validUntil + ) + public + view + returns (bytes32 operationHash) + { + operationHash = keccak256(_getOperationData(userOpHash, validAfter, validUntil)); + } + + function predictSafeAddress( + address singleton, + address safeProxyFactory, + bytes memory creationCode, + bytes32 salt, + bytes memory factoryInitializer + ) + external + pure + returns (address safeProxy) + { + salt = keccak256(abi.encodePacked(keccak256(factoryInitializer), salt)); + + safeProxy = address( + uint160( + uint256( + keccak256( + abi.encodePacked( + bytes1(0xff), + address(safeProxyFactory), + salt, + keccak256( + abi.encodePacked(creationCode, uint256(uint160(address(singleton)))) + ) + ) + ) + ) + ) + ); + } + + function hash(InitData memory data) public returns (bytes32) { + return keccak256(abi.encode(data)); + } } diff --git a/accounts/safe7579/test/Launchpad.t.sol b/accounts/safe7579/test/Launchpad.t.sol index 7dca3179..235f7d22 100644 --- a/accounts/safe7579/test/Launchpad.t.sol +++ b/accounts/safe7579/test/Launchpad.t.sol @@ -40,6 +40,7 @@ contract LaunchpadBase is Test { IEntryPoint entrypoint; bytes userOpInitCode; + IERC7484 registry; struct Setup { address singleton; @@ -55,8 +56,9 @@ contract LaunchpadBase is Test { entrypoint = etchEntrypoint(); singleton = new Safe(); safeProxyFactory = new SafeProxyFactory(); + registry = new MockRegistry(); safe7579 = new SafeERC7579(); - launchpad = new SafeSignerLaunchpad(address(entrypoint)); + launchpad = new SafeSignerLaunchpad(address(entrypoint), registry); uniqueSignerFactory = new UniqueSignerFactory(); uint256 key = 1; uniqueSigner = new TestUniqueSigner(key); @@ -77,59 +79,39 @@ contract LaunchpadBase is Test { ISafe7579Init.ModuleInit memory hook = ISafe7579Init.ModuleInit({ module: address(0), initData: bytes("") }); - ISafe7579Init.RegistryInit memory registryInit = ISafe7579Init.RegistryInit({ - registry: IERC7484(address(new MockRegistry())), - attesters: Solarray.addresses(makeAddr("attester1"), makeAddr("attester2")), - threshold: 2 - }); - - Setup memory _setup = Setup({ + SafeSignerLaunchpad.InitData memory initData = SafeSignerLaunchpad.InitData({ singleton: address(singleton), - signerFactory: address(uniqueSignerFactory), - signerData: abi.encode(Solarray.addresses(signer1.addr, signer2.addr)), + owners: Solarray.addresses(signer1.addr), + threshold: 1, setupTo: address(launchpad), setupData: abi.encodeCall( - SafeSignerLaunchpad.initSafe7579, - (address(safe7579), validators, executors, fallbacks, hook) + SafeSignerLaunchpad.initSafe7579WithRegistry, + ( + address(safe7579), + validators, + executors, + fallbacks, + hook, + Solarray.addresses(makeAddr("attester1"), makeAddr("attester2")), + 2 + ) ), - fallbackHandler: address(safe7579) - }); - bytes32 initHash = launchpad.getInitHash({ - singleton: _setup.singleton, - signerFactory: _setup.signerFactory, - signerData: _setup.signerData, - setupTo: _setup.setupTo, - setupData: _setup.setupData, - fallbackHandler: _setup.fallbackHandler + safeFallbackHandler: address(safe7579), + callData: "" }); + bytes32 initHash = launchpad.hash(initData); - bytes memory factoryInitializer = abi.encodeCall( - SafeSignerLaunchpad.preValidationSetup, - ( - initHash, - address(registryInit.registry), - abi.encodeCall( - IERC7484.trustAttesters, (registryInit.threshold, registryInit.attesters) - ) - ) - ); + bytes memory factoryInitializer = + abi.encodeCall(SafeSignerLaunchpad.preValidationSetup, (initHash, address(0), "")); PackedUserOperation memory userOp = getDefaultUserOp(address(safe), address(defaultValidator)); - userOp.callData = abi.encodeCall( - SafeSignerLaunchpad.initializeThenUserOp, - ( - _setup.singleton, - _setup.signerFactory, - _setup.signerData, - _setup.setupTo, - _setup.setupData, - _setup.fallbackHandler, - "" - ) - ); - userOp.initCode = _initCode(factoryInitializer, salt); + { + userOp.callData = + abi.encodePacked(SafeSignerLaunchpad.executeUserOp.selector, abi.encode(initData)); + userOp.initCode = _initCode(factoryInitializer, salt); + } address predict = launchpad.predictSafeAddress({ singleton: address(launchpad), From 53dc4bd3b895bb758601f1d01d881c77f86fc9d5 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Wed, 10 Apr 2024 12:02:51 +0700 Subject: [PATCH 33/64] =?UTF-8?q?=F0=9F=90=9B=20Setup=20working?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- accounts/safe7579/src/SafeERC7579.sol | 44 ++++++--- accounts/safe7579/src/core/EventManager.sol | 59 ++++++++++++ .../safe7579/src/interfaces/ISafe7579Init.sol | 4 +- accounts/safe7579/src/utils/Launchpadv2.sol | 93 +++++++++---------- accounts/safe7579/test/Launchpad.t.sol | 24 ++--- 5 files changed, 144 insertions(+), 80 deletions(-) create mode 100644 accounts/safe7579/src/core/EventManager.sol diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index 4b3fecbf..58a5fbfd 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -24,6 +24,8 @@ import { } from "erc7579/interfaces/IERC7579Module.sol"; import { AccessControl } from "./core/AccessControl.sol"; import { HookManager } from "./core/HookManager.sol"; +import { EventManager } from "./core/EventManager.sol"; +import "./core/ModuleManager.sol"; import { ISafeOp, SAFE_OP_TYPEHASH } from "./interfaces/ISafeOp.sol"; import { ISafe } from "./interfaces/ISafe.sol"; import { @@ -50,8 +52,11 @@ contract SafeERC7579 is ISafe7579Init, AccessControl, IMSA, - HookManager + HookManager, + EventManager { + using SentinelList4337Lib for SentinelList4337Lib.SentinelList; + using SentinelListLib for SentinelListLib.SentinelList; using UserOperationLib for PackedUserOperation; using ModeLib for ModeCode; using ExecutionLib for bytes; @@ -323,7 +328,7 @@ contract SafeERC7579 is else if (moduleType == MODULE_TYPE_FALLBACK) _installFallbackHandler(module, initData); else if (moduleType == MODULE_TYPE_HOOK) _installHook(module, initData); else revert UnsupportedModuleType(moduleType); - emit ModuleInstalled(moduleType, module); + _emitModuleInstall(moduleType, module); } /** @@ -345,7 +350,7 @@ contract SafeERC7579 is else if (moduleType == MODULE_TYPE_FALLBACK) _uninstallFallbackHandler(module, deInitData); else if (moduleType == MODULE_TYPE_HOOK) _uninstallHook(module, deInitData); else revert UnsupportedModuleType(moduleType); - emit ModuleUninstalled(moduleType, module); + _emitModuleUninstall(moduleType, module); } /** @@ -500,7 +505,6 @@ contract SafeERC7579 is } function initializeAccountWithRegistry( - ModuleInit[] calldata validators, ModuleInit[] calldata executors, ModuleInit[] calldata fallbacks, ModuleInit calldata hook, @@ -510,11 +514,10 @@ contract SafeERC7579 is payable { _configureRegistry(registryInit.registry, registryInit.attesters, registryInit.threshold); - _initModules(validators, executors, fallbacks, hook); + _initModules(executors, fallbacks, hook); } function initializeAccount( - ModuleInit[] calldata validators, ModuleInit[] calldata executors, ModuleInit[] calldata fallbacks, ModuleInit calldata hook @@ -522,38 +525,49 @@ contract SafeERC7579 is public payable { - _initModules(validators, executors, fallbacks, hook); + _initModules(executors, fallbacks, hook); + } + + function launchpadValidators(ModuleInit[] calldata validators) external payable override { + $validators.init({ account: msg.sender }); + uint256 length = validators.length; + for (uint256 i; i < length; i++) { + ModuleInit calldata validator = validators[i]; + $validators.push({ account: msg.sender, newEntry: validator.module }); + // @dev No events emitted here. Launchpad is expected to do this. + // at this point, the safeproxy singleton is not yet updated to the SafeSingleton + // calling execTransactionFromModule is not available yet. + } } function _initModules( - ModuleInit[] calldata validators, ModuleInit[] calldata executors, ModuleInit[] calldata fallbacks, ModuleInit calldata hook ) internal { + ModuleManagerStorage storage $mms = $moduleManager[msg.sender]; // this will revert if already initialized - _initModuleManager(); - uint256 length = validators.length; - for (uint256 i; i < length; i++) { - ModuleInit calldata validator = validators[i]; - _installValidator(validator.module, validator.initData); - } + // TODO: check that validator list is already initialized + $mms._executors.init(); - length = executors.length; + uint256 length = executors.length; for (uint256 i; i < length; i++) { ModuleInit calldata executor = executors[i]; _installExecutor(executor.module, executor.initData); + _emitModuleInstall(MODULE_TYPE_EXECUTOR, executor.module); } length = fallbacks.length; for (uint256 i; i < length; i++) { ModuleInit calldata _fallback = fallbacks[i]; _installFallbackHandler(_fallback.module, _fallback.initData); + _emitModuleInstall(MODULE_TYPE_FALLBACK, _fallback.module); } _installHook(hook.module, hook.initData); + _emitModuleInstall(MODULE_TYPE_HOOK, hook.module); emit Safe7579Initialized(msg.sender); } diff --git a/accounts/safe7579/src/core/EventManager.sol b/accounts/safe7579/src/core/EventManager.sol new file mode 100644 index 00000000..03e1a48e --- /dev/null +++ b/accounts/safe7579/src/core/EventManager.sol @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.25; + +import "./ExecutionHelper.sol"; + +contract EventEmitter { + event ModuleInstalled(uint256 moduleTypeId, address module); + event ModuleUninstalled(uint256 moduleTypeId, address module); + + function emitModuleInstalled(uint256 moduleTypeId, address module) external { + emit ModuleInstalled(moduleTypeId, module); + } + + function emitModulesInstalled(uint256 moduleTypeId, address[] calldata modules) external { + uint256 length = modules.length; + for (uint256 i; i < length; i++) { + emit ModuleInstalled(moduleTypeId, modules[i]); + } + } + + function emitModuleUninstalled(uint256 moduleTypeId, address module) external { + emit ModuleUninstalled(moduleTypeId, module); + } + + function emitModulesUninstalled(uint256 moduleTypeId, address[] calldata modules) external { + uint256 length = modules.length; + for (uint256 i; i < length; i++) { + emit ModuleUninstalled(moduleTypeId, modules[i]); + } + } +} + +contract EventManager is ExecutionHelper { + EventEmitter internal EVENT; + + constructor() { + EVENT = new EventEmitter(); + } + + function _emitModuleInstall(uint256 moduleTypeId, address module) internal { + bool success = ISafe(msg.sender).execTransactionFromModule( + address(EVENT), + 0, + abi.encodeCall(EventEmitter.emitModuleInstalled, (moduleTypeId, module)), + 1 + ); + if (!success) revert ExecutionFailed(); + } + + function _emitModuleUninstall(uint256 moduleTypeId, address module) internal { + bool success = ISafe(msg.sender).execTransactionFromModule( + address(EVENT), + 0, + abi.encodeCall(EventEmitter.emitModuleUninstalled, (moduleTypeId, module)), + 1 + ); + if (!success) revert ExecutionFailed(); + } +} diff --git a/accounts/safe7579/src/interfaces/ISafe7579Init.sol b/accounts/safe7579/src/interfaces/ISafe7579Init.sol index c54ea52d..4c9f4bbb 100644 --- a/accounts/safe7579/src/interfaces/ISafe7579Init.sol +++ b/accounts/safe7579/src/interfaces/ISafe7579Init.sol @@ -16,7 +16,6 @@ interface ISafe7579Init { } function initializeAccountWithRegistry( - ModuleInit[] calldata validators, ModuleInit[] calldata executors, ModuleInit[] calldata fallbacks, ModuleInit calldata hook, @@ -26,11 +25,12 @@ interface ISafe7579Init { payable; function initializeAccount( - ModuleInit[] calldata validators, ModuleInit[] calldata executors, ModuleInit[] calldata fallbacks, ModuleInit calldata hook ) external payable; + + function launchpadValidators(ModuleInit[] calldata validators) external payable; } diff --git a/accounts/safe7579/src/utils/Launchpadv2.sol b/accounts/safe7579/src/utils/Launchpadv2.sol index 570d5209..abb8e596 100644 --- a/accounts/safe7579/src/utils/Launchpadv2.sol +++ b/accounts/safe7579/src/utils/Launchpadv2.sol @@ -22,22 +22,21 @@ import { ISignatureValidator } from import "forge-std/console2.sol"; /** - * @title SafeOpLaunchpad - A contract for Safe initialization with custom unique signers that would - * violate ERC-4337 factory rules. - * @dev The is intended to be set as a Safe proxy's implementation for ERC-4337 user operation that - * deploys the account. */ -contract SafeSignerLaunchpad is IAccount, SafeStorage { +contract Safe7579Launchpad is IAccount, SafeStorage { struct InitData { address singleton; address[] owners; uint256 threshold; address setupTo; bytes setupData; - address safeFallbackHandler; + address safe7579; + ISafe7579Init.ModuleInit[] validators; bytes callData; } + event ModuleInstalled(uint256 moduleTypeId, address module); + bytes32 private constant DOMAIN_SEPARATOR_TYPEHASH = keccak256("EIP712Domain(uint256 chainId,address verifyingContract)"); @@ -86,7 +85,6 @@ contract SafeSignerLaunchpad is IAccount, SafeStorage { function initSafe7579WithRegistry( address safe7579, - ISafe7579Init.ModuleInit[] calldata validators, ISafe7579Init.ModuleInit[] calldata executors, ISafe7579Init.ModuleInit[] calldata fallbacks, ISafe7579Init.ModuleInit calldata hook, @@ -97,7 +95,6 @@ contract SafeSignerLaunchpad is IAccount, SafeStorage { { ISafe(address(this)).enableModule(safe7579); SafeERC7579(payable(safe7579)).initializeAccountWithRegistry( - validators, executors, fallbacks, hook, @@ -111,7 +108,6 @@ contract SafeSignerLaunchpad is IAccount, SafeStorage { function initSafe7579( address safe7579, - ISafe7579Init.ModuleInit[] calldata validators, ISafe7579Init.ModuleInit[] calldata executors, ISafe7579Init.ModuleInit[] calldata fallbacks, ISafe7579Init.ModuleInit calldata hook @@ -119,7 +115,7 @@ contract SafeSignerLaunchpad is IAccount, SafeStorage { public { ISafe(address(this)).enableModule(safe7579); - SafeERC7579(payable(safe7579)).initializeAccount(validators, executors, fallbacks, hook); + SafeERC7579(payable(safe7579)).initializeAccount(executors, fallbacks, hook); } modifier onlyProxy() { @@ -143,7 +139,6 @@ contract SafeSignerLaunchpad is IAccount, SafeStorage { onlyProxy { _setInitHash(initHash); - console2.log("this", address(this)); if (to != address(0)) { (bool success,) = to.delegatecall(preInit); require(success, "Pre-initialization failed"); @@ -162,16 +157,37 @@ contract SafeSignerLaunchpad is IAccount, SafeStorage { returns (uint256 validationData) { require( - this.executeUserOp.selector == bytes4(userOp.callData[:4]), - "invalid user operation data" + this.setupSafe.selector == bytes4(userOp.callData[:4]), "invalid user operation data" ); InitData memory initData = abi.decode(userOp.callData[4:], (InitData)); - require(hash(initData) == _initHash(), "invalid init hash"); - // TODO: is it a problem that we dont validate the signature with the validator here? + // get validator from nonce encoding + address validator; + uint256 nonce = userOp.nonce; + // solhint-disable-next-line no-inline-assembly + assembly { + validator := shr(96, nonce) + } + // initialize validator on behalf of the safe account + ISafe7579Init(initData.safe7579).launchpadValidators(initData.validators); + + bool userOpValidatorInstalled; + uint256 validatorsLength = initData.validators.length; + for (uint256 i; i < validatorsLength; i++) { + address validatorModule = initData.validators[i].module; + emit ModuleInstalled(1, validatorModule); + if (validatorModule == validator) userOpValidatorInstalled = true; + } + // if the validator in the userOp was not installed, it MUST not be used to validate + if (!userOpValidatorInstalled) return 1; + + // validate userOp with selected validation module + validationData = IValidator(validator).validateUserOp(userOp, userOpHash); + + // pay back gas to EntryPoint if (missingAccountFunds > 0) { // solhint-disable-next-line no-inline-assembly assembly ("memory-safe") { @@ -180,28 +196,22 @@ contract SafeSignerLaunchpad is IAccount, SafeStorage { } } - function executeUserOp( - PackedUserOperation calldata userOp, - bytes32 userOpHash - ) - external - onlySupportedEntryPoint - { - InitData memory initData = abi.decode(userOp.callData[4:], (InitData)); + function setupSafe(InitData calldata initData) external onlySupportedEntryPoint { // update singleton to Safe account impl SafeStorage.singleton = initData.singleton; - ISafe(address(this)).setup( - initData.owners, - initData.threshold, - initData.setupTo, - initData.setupData, - initData.safeFallbackHandler, - address(0), - 0, - payable(address(0)) - ); - + ISafe(address(this)).setup({ + _owners: initData.owners, + _threshold: initData.threshold, + to: initData.setupTo, + data: initData.setupData, + fallbackHandler: initData.safe7579, + paymentToken: address(0), + payment: 0, + paymentReceiver: payable(address(0)) + }); + + // encoded in here can be the initializeAccount() call (bool success, bytes memory returnData) = address(this).delegatecall(initData.callData); if (!success) { // solhint-disable-next-line no-inline-assembly @@ -210,21 +220,8 @@ contract SafeSignerLaunchpad is IAccount, SafeStorage { } } + // reset initHash _setInitHash(0); - - // validate user operation - address validator; - uint256 nonce = userOp.nonce; - - // solhint-disable-next-line no-inline-assembly - assembly { - validator := shr(96, nonce) - } - - uint256 ret = IValidator(validator).validateUserOp(userOp, userOpHash); - // TODO: unpack properly - // consider comparing validUntil/validAfter to userOp.signature - if (ret != 0) revert(); } function _domainSeparator() internal view returns (bytes32) { diff --git a/accounts/safe7579/test/Launchpad.t.sol b/accounts/safe7579/test/Launchpad.t.sol index 235f7d22..9f421912 100644 --- a/accounts/safe7579/test/Launchpad.t.sol +++ b/accounts/safe7579/test/Launchpad.t.sol @@ -28,9 +28,7 @@ contract LaunchpadBase is Test { Safe singleton; Safe safe; SafeProxyFactory safeProxyFactory; - TestUniqueSigner uniqueSigner; - UniqueSignerFactory uniqueSignerFactory; - SafeSignerLaunchpad launchpad; + Safe7579Launchpad launchpad; MockValidator defaultValidator; MockExecutor defaultExecutor; @@ -58,10 +56,7 @@ contract LaunchpadBase is Test { safeProxyFactory = new SafeProxyFactory(); registry = new MockRegistry(); safe7579 = new SafeERC7579(); - launchpad = new SafeSignerLaunchpad(address(entrypoint), registry); - uniqueSignerFactory = new UniqueSignerFactory(); - uint256 key = 1; - uniqueSigner = new TestUniqueSigner(key); + launchpad = new Safe7579Launchpad(address(entrypoint), registry); // Set up Modules defaultValidator = new MockValidator(); @@ -79,37 +74,36 @@ contract LaunchpadBase is Test { ISafe7579Init.ModuleInit memory hook = ISafe7579Init.ModuleInit({ module: address(0), initData: bytes("") }); - SafeSignerLaunchpad.InitData memory initData = SafeSignerLaunchpad.InitData({ + Safe7579Launchpad.InitData memory initData = Safe7579Launchpad.InitData({ singleton: address(singleton), owners: Solarray.addresses(signer1.addr), threshold: 1, setupTo: address(launchpad), setupData: abi.encodeCall( - SafeSignerLaunchpad.initSafe7579WithRegistry, + Safe7579Launchpad.initSafe7579WithRegistry, ( address(safe7579), - validators, executors, fallbacks, hook, Solarray.addresses(makeAddr("attester1"), makeAddr("attester2")), 2 ) - ), - safeFallbackHandler: address(safe7579), + ), + safe7579: address(safe7579), + validators: validators, callData: "" }); bytes32 initHash = launchpad.hash(initData); bytes memory factoryInitializer = - abi.encodeCall(SafeSignerLaunchpad.preValidationSetup, (initHash, address(0), "")); + abi.encodeCall(Safe7579Launchpad.preValidationSetup, (initHash, address(0), "")); PackedUserOperation memory userOp = getDefaultUserOp(address(safe), address(defaultValidator)); { - userOp.callData = - abi.encodePacked(SafeSignerLaunchpad.executeUserOp.selector, abi.encode(initData)); + userOp.callData = abi.encodeCall(Safe7579Launchpad.setupSafe, (initData)); userOp.initCode = _initCode(factoryInitializer, salt); } From cf083a1900adcd499ae29057dca1f7f4e2b4cd2b Mon Sep 17 00:00:00 2001 From: zeroknots Date: Wed, 10 Apr 2024 12:31:05 +0700 Subject: [PATCH 34/64] chore: updating docs --- accounts/safe7579/README.md | 52 ++++++++++++++++----- accounts/safe7579/src/utils/Launchpadv2.sol | 1 + 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/accounts/safe7579/README.md b/accounts/safe7579/README.md index 1535a2ef..feb4a787 100644 --- a/accounts/safe7579/README.md +++ b/accounts/safe7579/README.md @@ -1,5 +1,5 @@ sequenceDiagram -participant Sender +participant Bundler participant Entrypoint participant SenderCreator participant SafeProxyFactory @@ -7,9 +7,13 @@ participant SafeProxy participant SafeSingleton participant Launchpad participant Safe7579 +participant Registry +participant EventEmitter +participant ValidatorModule +participant Executor rect rgb(255,179,186) -Sender->>Entrypoint: handleUserOps +Bundler->>Entrypoint: handleUserOps Entrypoint->>SenderCreator: create this initcode SenderCreator->>+SafeProxyFactory: createProxyWithNonce(launchpad, intializer, salt) SafeProxyFactory-->>SafeProxy: create2 @@ -17,8 +21,6 @@ SafeProxy-->Launchpad: singleton = launchpad SafeProxyFactory->>+SafeProxy: preValidationSetup (initHash, to, preInit) SafeProxy-->>+Launchpad: preValidationSetup (initHash, to, preInit) [delegatecall] Note over Launchpad: sstore initHash -Launchpad ->> Registry: set Attesters [call] -Note right of Registry: store attesters SafeProxy-->>SafeProxyFactory: created SafeProxyFactory-->>Entrypoint: created sender end @@ -27,22 +29,48 @@ rect rgb(255,179,186) Entrypoint->>+SafeProxy: validateUserOp SafeProxy-->>Launchpad: validateUserOp [delegatecall] Note right of Launchpad: only initializeThenUserOp.selector -Note over Launchpad: restore and check inithash (sload) -Launchpad-->>SafeProxy: packedValid -SafeProxy->>-Entrypoint: packedValid +Note over Launchpad: require inithash (sload) +Launchpad->>Safe7579: launchpadValidators() [call] +Note over Safe7579: write validator(s) to storage + +loop +Launchpad ->> ValidatorModule: onInstall() +Note over Launchpad: emit ModuleInstalled (as SafeProxy) + +end +Note over Launchpad: get validator module selection from userOp.nonce +Launchpad ->> ValidatorModule: validateUserOp(userOp, userOpHash) +ValidatorModule ->> Launchpad: packedValidationData +Launchpad-->>SafeProxy: packedValidationData +SafeProxy->>-Entrypoint: packedValidationData end rect rgb(186,225,255) -Entrypoint->>+SafeProxy: initializeThenUserOp -SafeProxy-->>Launchpad: initializeThenUserOp [delegatecall] +Entrypoint->>+SafeProxy: setupSafe +SafeProxy-->>Launchpad: setupSafe [delegatecall] Note over SafeProxy, Launchpad: sstore safe.singleton == SafeSingleton Launchpad->>SafeProxy: safe.setup() [call] SafeProxy->>SafeSingleton: safe.setup() [delegatecall] Note over SafeSingleton: setup function in Safe has a delegatecall -SafeSingleton-->>Launchpad: initSafe7579 [delegatecall] +SafeSingleton-->>Launchpad: initSafe7579WithRegistry [delegatecall] Launchpad->>SafeProxy: this.enableModule(safe7579) SafeProxy-->>SafeSingleton: enableModule (safe7579) [delegatecall] -Launchpad->>Safe7579: initializeAccount +SafeSingleton->>Safe7579: initializeAccountWithRegistry Note over Safe7579: msg.sender: SafeProxy -Safe7579->SafeProxy: exec done +alt SetupRegistry +Safe7579-->SafeProxy: exec set attesters on registry +SafeProxy-->>SafeSingleton: exec set attesters on registry +SafeSingleton->>Registry: set attesters (attesters[], threshold) +end +loop installation of modules +Safe7579->>Registry: checkForAccount(SafeProxy, moduleaddr, moduleType) +Safe7579->>SafeProxy: exec call onInstall on module +SafeProxy-->>SafeSingleton: exec call onInstall on Module [delegatecall] +SafeSingleton->>Executor: onInstall() [call] +Safe7579->>SafeProxy: exec EventEmitter +SafeProxy-->>SafeSingleton: exec EventEmitter [delegatecall] +SafeSingleton-->>EventEmitter: emit ModuleInstalled() [delegatecall] +Note over EventEmitter: emit ModuleInstalled() as SafeProxy +end +Safe7579->>SafeProxy: exec done SafeProxy->-Entrypoint: exec done end diff --git a/accounts/safe7579/src/utils/Launchpadv2.sol b/accounts/safe7579/src/utils/Launchpadv2.sol index abb8e596..a317b391 100644 --- a/accounts/safe7579/src/utils/Launchpadv2.sol +++ b/accounts/safe7579/src/utils/Launchpadv2.sol @@ -178,6 +178,7 @@ contract Safe7579Launchpad is IAccount, SafeStorage { uint256 validatorsLength = initData.validators.length; for (uint256 i; i < validatorsLength; i++) { address validatorModule = initData.validators[i].module; + IValidator(validatorModule).onInstall(initData.validators[i].initData); emit ModuleInstalled(1, validatorModule); if (validatorModule == validator) userOpValidatorInstalled = true; } From d41b0fefe556335ad60e2995a2f42e9a8f2b43f1 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Wed, 10 Apr 2024 12:43:34 +0700 Subject: [PATCH 35/64] chore: refactoring initialization --- accounts/safe7579/src/SafeERC7579.sol | 90 +------------ .../safe7579/src/core/ExecutionHelper.sol | 14 +- accounts/safe7579/src/core/Initializer.sol | 125 ++++++++++++++++++ 3 files changed, 137 insertions(+), 92 deletions(-) create mode 100644 accounts/safe7579/src/core/Initializer.sol diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index 58a5fbfd..1b2524a2 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -25,6 +25,7 @@ import { import { AccessControl } from "./core/AccessControl.sol"; import { HookManager } from "./core/HookManager.sol"; import { EventManager } from "./core/EventManager.sol"; +import { Initializer } from "./core/Initializer.sol"; import "./core/ModuleManager.sol"; import { ISafeOp, SAFE_OP_TYPEHASH } from "./interfaces/ISafeOp.sol"; import { ISafe } from "./interfaces/ISafe.sol"; @@ -51,20 +52,15 @@ contract SafeERC7579 is IERC7579Account, ISafe7579Init, AccessControl, - IMSA, - HookManager, - EventManager + Initializer, + IMSA { - using SentinelList4337Lib for SentinelList4337Lib.SentinelList; - using SentinelListLib for SentinelListLib.SentinelList; using UserOperationLib for PackedUserOperation; using ModeLib for ModeCode; using ExecutionLib for bytes; error Unsupported(); - event Safe7579Initialized(address indexed safe); - bytes32 private constant DOMAIN_SEPARATOR_TYPEHASH = 0x47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a79469218; @@ -494,84 +490,6 @@ contract SafeERC7579 is return keccak256(abi.encode(DOMAIN_SEPARATOR_TYPEHASH, block.chainid, this)); } - function initializeAccount(bytes calldata callData) external payable override { - ModuleInit[] calldata validators; - assembly ("memory-safe") { - let dataPointer := add(callData.offset, calldataload(callData.offset)) - - validators.offset := add(dataPointer, 32) - validators.length := calldataload(dataPointer) - } - } - - function initializeAccountWithRegistry( - ModuleInit[] calldata executors, - ModuleInit[] calldata fallbacks, - ModuleInit calldata hook, - RegistryInit calldata registryInit - ) - public - payable - { - _configureRegistry(registryInit.registry, registryInit.attesters, registryInit.threshold); - _initModules(executors, fallbacks, hook); - } - - function initializeAccount( - ModuleInit[] calldata executors, - ModuleInit[] calldata fallbacks, - ModuleInit calldata hook - ) - public - payable - { - _initModules(executors, fallbacks, hook); - } - - function launchpadValidators(ModuleInit[] calldata validators) external payable override { - $validators.init({ account: msg.sender }); - uint256 length = validators.length; - for (uint256 i; i < length; i++) { - ModuleInit calldata validator = validators[i]; - $validators.push({ account: msg.sender, newEntry: validator.module }); - // @dev No events emitted here. Launchpad is expected to do this. - // at this point, the safeproxy singleton is not yet updated to the SafeSingleton - // calling execTransactionFromModule is not available yet. - } - } - - function _initModules( - ModuleInit[] calldata executors, - ModuleInit[] calldata fallbacks, - ModuleInit calldata hook - ) - internal - { - ModuleManagerStorage storage $mms = $moduleManager[msg.sender]; - // this will revert if already initialized - // TODO: check that validator list is already initialized - $mms._executors.init(); - - uint256 length = executors.length; - for (uint256 i; i < length; i++) { - ModuleInit calldata executor = executors[i]; - _installExecutor(executor.module, executor.initData); - _emitModuleInstall(MODULE_TYPE_EXECUTOR, executor.module); - } - - length = fallbacks.length; - for (uint256 i; i < length; i++) { - ModuleInit calldata _fallback = fallbacks[i]; - _installFallbackHandler(_fallback.module, _fallback.initData); - _emitModuleInstall(MODULE_TYPE_FALLBACK, _fallback.module); - } - - _installHook(hook.module, hook.initData); - _emitModuleInstall(MODULE_TYPE_HOOK, hook.module); - - emit Safe7579Initialized(msg.sender); - } - /** * Safe7579 is using validator selection encoding in the userop nonce. * to make it easier for SDKs / devs to integrate, this function can be @@ -591,6 +509,8 @@ contract SafeERC7579 is { _configureRegistry(registry, attesters, threshold); } + + function initializeAccount(bytes calldata callData) external payable { } } library EIP712 { diff --git a/accounts/safe7579/src/core/ExecutionHelper.sol b/accounts/safe7579/src/core/ExecutionHelper.sol index 4ec6d337..3bceedef 100644 --- a/accounts/safe7579/src/core/ExecutionHelper.sol +++ b/accounts/safe7579/src/core/ExecutionHelper.sol @@ -16,7 +16,7 @@ import { abstract contract ExecutionHelper { error ExecutionFailed(); - event TryExecutionFailed(uint256 numberInBatch); + event TryExecutionFailed(address safe, uint256 numberInBatch); SimulateTxAccessor private immutable SIMULATETX; @@ -149,7 +149,7 @@ abstract contract ExecutionHelper { internal { bool success = ISafe(safe).execTransactionFromModule(target, value, callData, 0); - if (!success) emit TryExecutionFailed(0); + if (!success) emit TryExecutionFailed(safe, 0); } /** @@ -173,7 +173,7 @@ abstract contract ExecutionHelper { bool success; (success, returnData) = ISafe(safe).execTransactionFromModuleReturnData(target, value, callData, 0); - if (!success) emit TryExecutionFailed(0); + if (!success) emit TryExecutionFailed(safe, 0); } /** @@ -190,7 +190,7 @@ abstract contract ExecutionHelper { bool success = ISafe(safe).execTransactionFromModule( execution.target, execution.value, execution.callData, 0 ); - if (!success) emit TryExecutionFailed(i); + if (!success) emit TryExecutionFailed(safe, i); } } @@ -202,7 +202,7 @@ abstract contract ExecutionHelper { internal { bool success = ISafe(safe).execTransactionFromModule(target, 0, callData, 1); - if (!success) emit TryExecutionFailed(0); + if (!success) emit TryExecutionFailed(safe, 0); } function _tryExecuteDelegateCallReturnData( @@ -216,7 +216,7 @@ abstract contract ExecutionHelper { bool success; (success, returnData) = ISafe(safe).execTransactionFromModuleReturnData(target, 0, callData, 1); - if (!success) emit TryExecutionFailed(0); + if (!success) emit TryExecutionFailed(safe, 0); } /** @@ -242,7 +242,7 @@ abstract contract ExecutionHelper { (success, returnDatas[i]) = ISafe(safe).execTransactionFromModuleReturnData( execution.target, execution.value, execution.callData, 0 ); - if (!success) emit TryExecutionFailed(i); + if (!success) emit TryExecutionFailed(safe, i); } } diff --git a/accounts/safe7579/src/core/Initializer.sol b/accounts/safe7579/src/core/Initializer.sol new file mode 100644 index 00000000..950b6ba3 --- /dev/null +++ b/accounts/safe7579/src/core/Initializer.sol @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import { EventManager } from "./EventManager.sol"; +import { ISafe7579Init } from "../interfaces/ISafe7579Init.sol"; +import "./ModuleManager.sol"; +import { HookManager } from "./HookManager.sol"; + +abstract contract Initializer is ISafe7579Init, HookManager, EventManager { + using SentinelList4337Lib for SentinelList4337Lib.SentinelList; + using SentinelListLib for SentinelListLib.SentinelList; + + event Safe7579Initialized(address indexed safe); + + function initializeAccountWithRegistry( + ModuleInit[] calldata executors, + ModuleInit[] calldata fallbacks, + ModuleInit calldata hook, + RegistryInit calldata registryInit + ) + public + payable + { + _configureRegistry(registryInit.registry, registryInit.attesters, registryInit.threshold); + _initModules(executors, fallbacks, hook); + } + + function initializeAccountWithRegistry( + ModuleInit[] calldata validators, + ModuleInit[] calldata executors, + ModuleInit[] calldata fallbacks, + ModuleInit calldata hook, + RegistryInit calldata registryInit + ) + public + payable + { + _configureRegistry(registryInit.registry, registryInit.attesters, registryInit.threshold); + _initModules(validators, executors, fallbacks, hook); + } + + function initializeAccount( + ModuleInit[] calldata executors, + ModuleInit[] calldata fallbacks, + ModuleInit calldata hook + ) + public + payable + { + _initModules(executors, fallbacks, hook); + } + + function initializeAccount( + ModuleInit[] calldata validators, + ModuleInit[] calldata executors, + ModuleInit[] calldata fallbacks, + ModuleInit calldata hook + ) + public + payable + { + _initModules(validators, executors, fallbacks, hook); + } + + function launchpadValidators(ModuleInit[] calldata validators) external payable override { + $validators.init({ account: msg.sender }); + uint256 length = validators.length; + for (uint256 i; i < length; i++) { + ModuleInit calldata validator = validators[i]; + $validators.push({ account: msg.sender, newEntry: validator.module }); + // @dev No events emitted here. Launchpad is expected to do this. + // at this point, the safeproxy singleton is not yet updated to the SafeSingleton + // calling execTransactionFromModule is not available yet. + } + } + + function _initModules( + ModuleInit[] calldata validators, + ModuleInit[] calldata executors, + ModuleInit[] calldata fallbacks, + ModuleInit calldata hook + ) + internal + { + $validators.init({ account: msg.sender }); + uint256 length = validators.length; + for (uint256 i; i < length; i++) { + ModuleInit calldata validator = validators[i]; + _installValidator(validator.module, validator.initData); + } + _initModules(executors, fallbacks, hook); + } + + function _initModules( + ModuleInit[] calldata executors, + ModuleInit[] calldata fallbacks, + ModuleInit calldata hook + ) + internal + { + ModuleManagerStorage storage $mms = $moduleManager[msg.sender]; + // this will revert if already initialized + // TODO: check that validator list is already initialized + $mms._executors.init(); + + uint256 length = executors.length; + for (uint256 i; i < length; i++) { + ModuleInit calldata executor = executors[i]; + _installExecutor(executor.module, executor.initData); + _emitModuleInstall(MODULE_TYPE_EXECUTOR, executor.module); + } + + length = fallbacks.length; + for (uint256 i; i < length; i++) { + ModuleInit calldata _fallback = fallbacks[i]; + _installFallbackHandler(_fallback.module, _fallback.initData); + _emitModuleInstall(MODULE_TYPE_FALLBACK, _fallback.module); + } + + _installHook(hook.module, hook.initData); + _emitModuleInstall(MODULE_TYPE_HOOK, hook.module); + + emit Safe7579Initialized(msg.sender); + } +} From 9e940da98e992a6c70757a54ef9328c79424d378 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Wed, 10 Apr 2024 13:07:49 +0700 Subject: [PATCH 36/64] refactor event emitions and initialization --- accounts/safe7579/src/SafeERC7579.sol | 13 --- accounts/safe7579/src/core/HookManager.sol | 2 + accounts/safe7579/src/core/Initializer.sol | 91 +++++++------------ accounts/safe7579/src/core/ModuleManager.sol | 25 ++--- .../safe7579/src/interfaces/ISafe7579Init.sol | 11 +-- accounts/safe7579/src/utils/Launchpadv2.sol | 26 ++---- accounts/safe7579/test/Launchpad.t.sol | 1 + 7 files changed, 61 insertions(+), 108 deletions(-) diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index 1b2524a2..2d920ed3 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -37,7 +37,6 @@ import { _packValidationData } from "@ERC4337/account-abstraction/contracts/core import { IEntryPoint } from "@ERC4337/account-abstraction/contracts/interfaces/IEntryPoint.sol"; import { ISafe7579Init } from "./interfaces/ISafe7579Init.sol"; import { IERC1271 } from "./interfaces/IERC1271.sol"; -import { IERC7484 } from "./interfaces/IERC7484.sol"; import "forge-std/console2.sol"; /** @@ -324,7 +323,6 @@ contract SafeERC7579 is else if (moduleType == MODULE_TYPE_FALLBACK) _installFallbackHandler(module, initData); else if (moduleType == MODULE_TYPE_HOOK) _installHook(module, initData); else revert UnsupportedModuleType(moduleType); - _emitModuleInstall(moduleType, module); } /** @@ -346,7 +344,6 @@ contract SafeERC7579 is else if (moduleType == MODULE_TYPE_FALLBACK) _uninstallFallbackHandler(module, deInitData); else if (moduleType == MODULE_TYPE_HOOK) _uninstallHook(module, deInitData); else revert UnsupportedModuleType(moduleType); - _emitModuleUninstall(moduleType, module); } /** @@ -500,16 +497,6 @@ contract SafeERC7579 is nonce = IEntryPoint(entryPoint()).getNonce(safe, key); } - function setRegistry( - IERC7484 registry, - address[] calldata attesters, - uint8 threshold - ) - external - { - _configureRegistry(registry, attesters, threshold); - } - function initializeAccount(bytes calldata callData) external payable { } } diff --git a/accounts/safe7579/src/core/HookManager.sol b/accounts/safe7579/src/core/HookManager.sol index 14c1d82e..e1c37f04 100644 --- a/accounts/safe7579/src/core/HookManager.sol +++ b/accounts/safe7579/src/core/HookManager.sol @@ -68,6 +68,7 @@ abstract contract HookManager is ModuleManager { value: 0, callData: abi.encodeCall(IModule.onInstall, (data)) }); + _emitModuleInstall(MODULE_TYPE_HOOK, hook); } function _uninstallHook(address hook, bytes calldata data) internal virtual { @@ -78,6 +79,7 @@ abstract contract HookManager is ModuleManager { value: 0, callData: abi.encodeCall(IModule.onUninstall, (data)) }); + _emitModuleUninstall(MODULE_TYPE_HOOK, hook); } function _isHookInstalled(address module) internal view returns (bool) { diff --git a/accounts/safe7579/src/core/Initializer.sol b/accounts/safe7579/src/core/Initializer.sol index 950b6ba3..50b8736c 100644 --- a/accounts/safe7579/src/core/Initializer.sol +++ b/accounts/safe7579/src/core/Initializer.sol @@ -1,31 +1,32 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.23; -import { EventManager } from "./EventManager.sol"; import { ISafe7579Init } from "../interfaces/ISafe7579Init.sol"; import "./ModuleManager.sol"; import { HookManager } from "./HookManager.sol"; +import { IERC7484 } from "../interfaces/IERC7484.sol"; -abstract contract Initializer is ISafe7579Init, HookManager, EventManager { +abstract contract Initializer is ISafe7579Init, HookManager { using SentinelList4337Lib for SentinelList4337Lib.SentinelList; using SentinelListLib for SentinelListLib.SentinelList; event Safe7579Initialized(address indexed safe); - function initializeAccountWithRegistry( - ModuleInit[] calldata executors, - ModuleInit[] calldata fallbacks, - ModuleInit calldata hook, - RegistryInit calldata registryInit - ) - public - payable - { - _configureRegistry(registryInit.registry, registryInit.attesters, registryInit.threshold); - _initModules(executors, fallbacks, hook); + error InvalidInitData(address safe); + + function launchpadValidators(ModuleInit[] calldata validators) external payable override { + $validators.init({ account: msg.sender }); + uint256 length = validators.length; + for (uint256 i; i < length; i++) { + ModuleInit calldata validator = validators[i]; + $validators.push({ account: msg.sender, newEntry: validator.module }); + // @dev No events emitted here. Launchpad is expected to do this. + // at this point, the safeproxy singleton is not yet updated to the SafeSingleton + // calling execTransactionFromModule is not available yet. + } } - function initializeAccountWithRegistry( + function initializeAccount( ModuleInit[] calldata validators, ModuleInit[] calldata executors, ModuleInit[] calldata fallbacks, @@ -36,44 +37,10 @@ abstract contract Initializer is ISafe7579Init, HookManager, EventManager { payable { _configureRegistry(registryInit.registry, registryInit.attesters, registryInit.threshold); + // this will revert if already initialized _initModules(validators, executors, fallbacks, hook); } - function initializeAccount( - ModuleInit[] calldata executors, - ModuleInit[] calldata fallbacks, - ModuleInit calldata hook - ) - public - payable - { - _initModules(executors, fallbacks, hook); - } - - function initializeAccount( - ModuleInit[] calldata validators, - ModuleInit[] calldata executors, - ModuleInit[] calldata fallbacks, - ModuleInit calldata hook - ) - public - payable - { - _initModules(validators, executors, fallbacks, hook); - } - - function launchpadValidators(ModuleInit[] calldata validators) external payable override { - $validators.init({ account: msg.sender }); - uint256 length = validators.length; - for (uint256 i; i < length; i++) { - ModuleInit calldata validator = validators[i]; - $validators.push({ account: msg.sender, newEntry: validator.module }); - // @dev No events emitted here. Launchpad is expected to do this. - // at this point, the safeproxy singleton is not yet updated to the SafeSingleton - // calling execTransactionFromModule is not available yet. - } - } - function _initModules( ModuleInit[] calldata validators, ModuleInit[] calldata executors, @@ -82,11 +49,15 @@ abstract contract Initializer is ISafe7579Init, HookManager, EventManager { ) internal { - $validators.init({ account: msg.sender }); uint256 length = validators.length; - for (uint256 i; i < length; i++) { - ModuleInit calldata validator = validators[i]; - _installValidator(validator.module, validator.initData); + if (!$validators.alreadyInitialized({ account: msg.sender })) { + $validators.init({ account: msg.sender }); + for (uint256 i; i < length; i++) { + ModuleInit calldata validator = validators[i]; + _installValidator(validator.module, validator.initData); + } + } else if (length != 0) { + revert InvalidInitData(msg.sender); } _initModules(executors, fallbacks, hook); } @@ -100,26 +71,32 @@ abstract contract Initializer is ISafe7579Init, HookManager, EventManager { { ModuleManagerStorage storage $mms = $moduleManager[msg.sender]; // this will revert if already initialized - // TODO: check that validator list is already initialized $mms._executors.init(); uint256 length = executors.length; for (uint256 i; i < length; i++) { ModuleInit calldata executor = executors[i]; _installExecutor(executor.module, executor.initData); - _emitModuleInstall(MODULE_TYPE_EXECUTOR, executor.module); } length = fallbacks.length; for (uint256 i; i < length; i++) { ModuleInit calldata _fallback = fallbacks[i]; _installFallbackHandler(_fallback.module, _fallback.initData); - _emitModuleInstall(MODULE_TYPE_FALLBACK, _fallback.module); } _installHook(hook.module, hook.initData); - _emitModuleInstall(MODULE_TYPE_HOOK, hook.module); emit Safe7579Initialized(msg.sender); } + + function setRegistry( + IERC7484 registry, + address[] calldata attesters, + uint8 threshold + ) + external + { + _configureRegistry(registry, attesters, threshold); + } } diff --git a/accounts/safe7579/src/core/ModuleManager.sol b/accounts/safe7579/src/core/ModuleManager.sol index 08f5d1f7..ed96065d 100644 --- a/accounts/safe7579/src/core/ModuleManager.sol +++ b/accounts/safe7579/src/core/ModuleManager.sol @@ -7,6 +7,7 @@ import { IModule } from "erc7579/interfaces/IERC7579Module.sol"; import { ExecutionHelper } from "./ExecutionHelper.sol"; import { RegistryAdapter } from "./RegistryAdapter.sol"; import { Receiver } from "erc7579/core/Receiver.sol"; +import { EventManager } from "./EventManager.sol"; import { AccessControl } from "./AccessControl.sol"; import { CallType, CALLTYPE_SINGLE, CALLTYPE_DELEGATECALL } from "erc7579/lib/ModeLib.sol"; @@ -36,7 +37,13 @@ struct ModuleManagerStorage { * Contract that implements ERC7579 Module compatibility for Safe accounts * @author zeroknots.eth | rhinestone.wtf */ -abstract contract ModuleManager is AccessControl, Receiver, ExecutionHelper, RegistryAdapter { +abstract contract ModuleManager is + AccessControl, + Receiver, + ExecutionHelper, + RegistryAdapter, + EventManager +{ using SentinelListLib for SentinelListLib.SentinelList; using SentinelList4337Lib for SentinelList4337Lib.SentinelList; @@ -59,16 +66,6 @@ abstract contract ModuleManager is AccessControl, Receiver, ExecutionHelper, Reg _; } - /** - * 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 //////////////////////////////////////////////////// @@ -91,6 +88,7 @@ abstract contract ModuleManager is AccessControl, Receiver, ExecutionHelper, Reg value: 0, callData: abi.encodeCall(IModule.onInstall, (data)) }); + _emitModuleInstall(MODULE_TYPE_VALIDATOR, validator); } /** @@ -107,6 +105,7 @@ abstract contract ModuleManager is AccessControl, Receiver, ExecutionHelper, Reg value: 0, callData: abi.encodeCall(IModule.onUninstall, (disableModuleData)) }); + _emitModuleUninstall(MODULE_TYPE_VALIDATOR, validator); } /** @@ -162,6 +161,7 @@ abstract contract ModuleManager is AccessControl, Receiver, ExecutionHelper, Reg value: 0, callData: abi.encodeCall(IModule.onInstall, (data)) }); + _emitModuleInstall(MODULE_TYPE_EXECUTOR, executor); } function _uninstallExecutor(address executor, bytes calldata data) internal { @@ -176,6 +176,7 @@ abstract contract ModuleManager is AccessControl, Receiver, ExecutionHelper, Reg value: 0, callData: abi.encodeCall(IModule.onUninstall, (disableModuleData)) }); + _emitModuleUninstall(MODULE_TYPE_EXECUTOR, executor); } function _isExecutorInstalled(address executor) internal view virtual returns (bool) { @@ -227,6 +228,7 @@ abstract contract ModuleManager is AccessControl, Receiver, ExecutionHelper, Reg value: 0, callData: abi.encodeCall(IModule.onInstall, (initData)) }); + _emitModuleInstall(MODULE_TYPE_FALLBACK, handler); } function _isFallbackHandlerInstalled(bytes4 functionSig) internal view virtual returns (bool) { @@ -246,6 +248,7 @@ abstract contract ModuleManager is AccessControl, Receiver, ExecutionHelper, Reg value: 0, callData: abi.encodeCall(IModule.onUninstall, (initData)) }); + _emitModuleUninstall(MODULE_TYPE_FALLBACK, handler); } function _isFallbackHandlerInstalled( diff --git a/accounts/safe7579/src/interfaces/ISafe7579Init.sol b/accounts/safe7579/src/interfaces/ISafe7579Init.sol index 4c9f4bbb..43bc29ee 100644 --- a/accounts/safe7579/src/interfaces/ISafe7579Init.sol +++ b/accounts/safe7579/src/interfaces/ISafe7579Init.sol @@ -15,7 +15,8 @@ interface ISafe7579Init { uint8 threshold; } - function initializeAccountWithRegistry( + function initializeAccount( + ModuleInit[] calldata validators, ModuleInit[] calldata executors, ModuleInit[] calldata fallbacks, ModuleInit calldata hook, @@ -24,13 +25,5 @@ interface ISafe7579Init { external payable; - function initializeAccount( - ModuleInit[] calldata executors, - ModuleInit[] calldata fallbacks, - ModuleInit calldata hook - ) - external - payable; - function launchpadValidators(ModuleInit[] calldata validators) external payable; } diff --git a/accounts/safe7579/src/utils/Launchpadv2.sol b/accounts/safe7579/src/utils/Launchpadv2.sol index a317b391..9e5cb28f 100644 --- a/accounts/safe7579/src/utils/Launchpadv2.sol +++ b/accounts/safe7579/src/utils/Launchpadv2.sol @@ -85,6 +85,7 @@ contract Safe7579Launchpad is IAccount, SafeStorage { function initSafe7579WithRegistry( address safe7579, + ISafe7579Init.ModuleInit[] calldata validators, ISafe7579Init.ModuleInit[] calldata executors, ISafe7579Init.ModuleInit[] calldata fallbacks, ISafe7579Init.ModuleInit calldata hook, @@ -94,28 +95,17 @@ contract Safe7579Launchpad is IAccount, SafeStorage { public { ISafe(address(this)).enableModule(safe7579); - SafeERC7579(payable(safe7579)).initializeAccountWithRegistry( - executors, - fallbacks, - hook, - ISafe7579Init.RegistryInit({ + SafeERC7579(payable(safe7579)).initializeAccount({ + validators: validators, + executors: executors, + fallbacks: fallbacks, + hook: hook, + registryInit: ISafe7579Init.RegistryInit({ registry: REGISTRY, attesters: attesters, threshold: threshold }) - ); - } - - function initSafe7579( - address safe7579, - ISafe7579Init.ModuleInit[] calldata executors, - ISafe7579Init.ModuleInit[] calldata fallbacks, - ISafe7579Init.ModuleInit calldata hook - ) - public - { - ISafe(address(this)).enableModule(safe7579); - SafeERC7579(payable(safe7579)).initializeAccount(executors, fallbacks, hook); + }); } modifier onlyProxy() { diff --git a/accounts/safe7579/test/Launchpad.t.sol b/accounts/safe7579/test/Launchpad.t.sol index 9f421912..4b98fe54 100644 --- a/accounts/safe7579/test/Launchpad.t.sol +++ b/accounts/safe7579/test/Launchpad.t.sol @@ -83,6 +83,7 @@ contract LaunchpadBase is Test { Safe7579Launchpad.initSafe7579WithRegistry, ( address(safe7579), + new ISafe7579Init.ModuleInit[](0), executors, fallbacks, hook, From 993d40f355c6188334c22b6d97cbc68b801201a6 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Wed, 10 Apr 2024 13:28:23 +0700 Subject: [PATCH 37/64] clean up --- accounts/safe7579/src/core/EventManager.sol | 38 +++++-------------- .../safe7579/src/core/ExecutionHelper.sol | 11 ++++++ accounts/safe7579/src/core/Initializer.sol | 18 ++++----- accounts/safe7579/src/utils/Launchpadv2.sol | 2 +- accounts/safe7579/test/Launchpad.t.sol | 2 +- examples/src/MultiFactor/MultiFactor.sol | 2 +- examples/test/coldstorage/ColdStorage.t.sol | 8 ++-- .../src/integrations/uniswap/v3/Uniswap.sol | 4 +- 8 files changed, 37 insertions(+), 48 deletions(-) diff --git a/accounts/safe7579/src/core/EventManager.sol b/accounts/safe7579/src/core/EventManager.sol index 03e1a48e..0c08fed7 100644 --- a/accounts/safe7579/src/core/EventManager.sol +++ b/accounts/safe7579/src/core/EventManager.sol @@ -11,23 +11,9 @@ contract EventEmitter { emit ModuleInstalled(moduleTypeId, module); } - function emitModulesInstalled(uint256 moduleTypeId, address[] calldata modules) external { - uint256 length = modules.length; - for (uint256 i; i < length; i++) { - emit ModuleInstalled(moduleTypeId, modules[i]); - } - } - function emitModuleUninstalled(uint256 moduleTypeId, address module) external { emit ModuleUninstalled(moduleTypeId, module); } - - function emitModulesUninstalled(uint256 moduleTypeId, address[] calldata modules) external { - uint256 length = modules.length; - for (uint256 i; i < length; i++) { - emit ModuleUninstalled(moduleTypeId, modules[i]); - } - } } contract EventManager is ExecutionHelper { @@ -38,22 +24,18 @@ contract EventManager is ExecutionHelper { } function _emitModuleInstall(uint256 moduleTypeId, address module) internal { - bool success = ISafe(msg.sender).execTransactionFromModule( - address(EVENT), - 0, - abi.encodeCall(EventEmitter.emitModuleInstalled, (moduleTypeId, module)), - 1 - ); - if (!success) revert ExecutionFailed(); + _executeDelegateCallMemory({ + safe: msg.sender, + target: address(EVENT), + callData: abi.encodeCall(EventEmitter.emitModuleInstalled, (moduleTypeId, module)) + }); } function _emitModuleUninstall(uint256 moduleTypeId, address module) internal { - bool success = ISafe(msg.sender).execTransactionFromModule( - address(EVENT), - 0, - abi.encodeCall(EventEmitter.emitModuleUninstalled, (moduleTypeId, module)), - 1 - ); - if (!success) revert ExecutionFailed(); + _executeDelegateCallMemory({ + safe: msg.sender, + target: address(EVENT), + callData: abi.encodeCall(EventEmitter.emitModuleUninstalled, (moduleTypeId, module)) + }); } } diff --git a/accounts/safe7579/src/core/ExecutionHelper.sol b/accounts/safe7579/src/core/ExecutionHelper.sol index 3bceedef..6a29a2b8 100644 --- a/accounts/safe7579/src/core/ExecutionHelper.sol +++ b/accounts/safe7579/src/core/ExecutionHelper.sol @@ -91,6 +91,17 @@ abstract contract ExecutionHelper { if (!success) revert ExecutionFailed(); } + function _executeDelegateCallMemory( + address safe, + address target, + bytes memory callData + ) + internal + { + bool success = ISafe(safe).execTransactionFromModule(target, 0, callData, 1); + if (!success) revert ExecutionFailed(); + } + function _executeDelegateCallReturnData( address safe, address target, diff --git a/accounts/safe7579/src/core/Initializer.sol b/accounts/safe7579/src/core/Initializer.sol index 50b8736c..533900b1 100644 --- a/accounts/safe7579/src/core/Initializer.sol +++ b/accounts/safe7579/src/core/Initializer.sol @@ -5,6 +5,7 @@ import { ISafe7579Init } from "../interfaces/ISafe7579Init.sol"; import "./ModuleManager.sol"; import { HookManager } from "./HookManager.sol"; import { IERC7484 } from "../interfaces/IERC7484.sol"; +import "forge-std/console2.sol"; abstract contract Initializer is ISafe7579Init, HookManager { using SentinelList4337Lib for SentinelList4337Lib.SentinelList; @@ -50,6 +51,10 @@ abstract contract Initializer is ISafe7579Init, HookManager { internal { uint256 length = validators.length; + // _initModules may be used via launchpad or directly by already deployed Safe accounts + // if this function is called by the launchpad, validators will be initialized via + // launchpadValidators() + // to avoid double initialization, we check if the validators are already initialized if (!$validators.alreadyInitialized({ account: msg.sender })) { $validators.init({ account: msg.sender }); for (uint256 i; i < length; i++) { @@ -59,21 +64,12 @@ abstract contract Initializer is ISafe7579Init, HookManager { } else if (length != 0) { revert InvalidInitData(msg.sender); } - _initModules(executors, fallbacks, hook); - } - function _initModules( - ModuleInit[] calldata executors, - ModuleInit[] calldata fallbacks, - ModuleInit calldata hook - ) - internal - { ModuleManagerStorage storage $mms = $moduleManager[msg.sender]; - // this will revert if already initialized + // this will revert if already initialized. $mms._executors.init(); - uint256 length = executors.length; + length = executors.length; for (uint256 i; i < length; i++) { ModuleInit calldata executor = executors[i]; _installExecutor(executor.module, executor.initData); diff --git a/accounts/safe7579/src/utils/Launchpadv2.sol b/accounts/safe7579/src/utils/Launchpadv2.sol index 9e5cb28f..dec6b6f5 100644 --- a/accounts/safe7579/src/utils/Launchpadv2.sol +++ b/accounts/safe7579/src/utils/Launchpadv2.sol @@ -83,7 +83,7 @@ contract Safe7579Launchpad is IAccount, SafeStorage { REGISTRY = registry; } - function initSafe7579WithRegistry( + function initSafe7579( address safe7579, ISafe7579Init.ModuleInit[] calldata validators, ISafe7579Init.ModuleInit[] calldata executors, diff --git a/accounts/safe7579/test/Launchpad.t.sol b/accounts/safe7579/test/Launchpad.t.sol index 4b98fe54..9df2b87d 100644 --- a/accounts/safe7579/test/Launchpad.t.sol +++ b/accounts/safe7579/test/Launchpad.t.sol @@ -80,7 +80,7 @@ contract LaunchpadBase is Test { threshold: 1, setupTo: address(launchpad), setupData: abi.encodeCall( - Safe7579Launchpad.initSafe7579WithRegistry, + Safe7579Launchpad.initSafe7579, ( address(safe7579), new ISafe7579Init.ModuleInit[](0), diff --git a/examples/src/MultiFactor/MultiFactor.sol b/examples/src/MultiFactor/MultiFactor.sol index 62f8c3f3..16a29258 100644 --- a/examples/src/MultiFactor/MultiFactor.sol +++ b/examples/src/MultiFactor/MultiFactor.sol @@ -213,7 +213,7 @@ contract MultiFactor is ERC7579ValidatorBase, ECDSAFactor { value: 0, callData: abi.encodeCall( ECDSAFactor.setECDSAFactor, (abi.decode(datas[i], (FactorConfig))) - ) + ) }); } // only allow the installation of subvalidators, if the validator module is not diff --git a/examples/test/coldstorage/ColdStorage.t.sol b/examples/test/coldstorage/ColdStorage.t.sol index 457daa7f..ecebf196 100644 --- a/examples/test/coldstorage/ColdStorage.t.sol +++ b/examples/test/coldstorage/ColdStorage.t.sol @@ -200,7 +200,7 @@ contract ColdStorageTest is RhinestoneModuleKit, Test { ColdStorageExecutor.executeOnSubAccount.selector, address(coldStorage.account), subAccountCallData - ), + ), txValidator: address(ownableValidator) }); @@ -223,7 +223,7 @@ contract ColdStorageTest is RhinestoneModuleKit, Test { ColdStorageExecutor.executeOnSubAccount.selector, address(coldStorage.account), subAccountCallData - ), + ), txValidator: address(ownableValidator) }); bytes memory signature = signHash(owner.key, userOpData.userOpHash); @@ -242,7 +242,7 @@ contract ColdStorageTest is RhinestoneModuleKit, Test { value: 0, callData: abi.encodeWithSelector( MockERC20.transfer.selector, address(mainAccount.account), amountToWithdraw - ) + ) }); _requestWithdraw(action, 0); @@ -279,7 +279,7 @@ contract ColdStorageTest is RhinestoneModuleKit, Test { value: 0, callData: abi.encodeWithSelector( MockERC20.transfer.selector, address(mainAccount.account), 100 - ) + ) }); _requestWithdraw(newAction, 0); diff --git a/packages/modulekit/src/integrations/uniswap/v3/Uniswap.sol b/packages/modulekit/src/integrations/uniswap/v3/Uniswap.sol index 8064e292..d07dd6f7 100644 --- a/packages/modulekit/src/integrations/uniswap/v3/Uniswap.sol +++ b/packages/modulekit/src/integrations/uniswap/v3/Uniswap.sol @@ -56,7 +56,7 @@ library UniswapV3Integration { sqrtPriceLimitX96: sqrtPriceLimitX96 }) ) - ) + ) }); } @@ -88,7 +88,7 @@ library UniswapV3Integration { sqrtPriceLimitX96: 0 }) ) - ) + ) }); } } From cdb25339c5896dea743e3960df2aa6ba3d59bebb Mon Sep 17 00:00:00 2001 From: zeroknots Date: Wed, 10 Apr 2024 13:47:13 +0700 Subject: [PATCH 38/64] feat: implement execution after initialization --- accounts/safe7579/src/utils/Launchpadv2.sol | 15 ++++++++++----- accounts/safe7579/test/Launchpad.t.sol | 19 ++++++++++++++++++- accounts/safe7579/test/SafeERC7579.t.sol | 2 -- accounts/safe7579/test/mocks/MockTarget.sol | 3 +++ 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/accounts/safe7579/src/utils/Launchpadv2.sol b/accounts/safe7579/src/utils/Launchpadv2.sol index dec6b6f5..3b866672 100644 --- a/accounts/safe7579/src/utils/Launchpadv2.sol +++ b/accounts/safe7579/src/utils/Launchpadv2.sol @@ -202,17 +202,22 @@ contract Safe7579Launchpad is IAccount, SafeStorage { paymentReceiver: payable(address(0)) }); - // encoded in here can be the initializeAccount() call - (bool success, bytes memory returnData) = address(this).delegatecall(initData.callData); + // reset initHash + _setInitHash(0); + // call function on safe7579 as safe. attach address(this) + // to comply with 2771 access control + (bool success, bytes memory returnData) = address(initData.safe7579).call( + abi.encodePacked( + initData.callData, // encode arbitrary execution here. i.e. IERC7579.execute() + address(this) // ERC2771 access control + ) + ); if (!success) { // solhint-disable-next-line no-inline-assembly assembly ("memory-safe") { revert(add(returnData, 0x20), mload(returnData)) } } - - // reset initHash - _setInitHash(0); } function _domainSeparator() internal view returns (bytes32) { diff --git a/accounts/safe7579/test/Launchpad.t.sol b/accounts/safe7579/test/Launchpad.t.sol index 9df2b87d..00acc2b3 100644 --- a/accounts/safe7579/test/Launchpad.t.sol +++ b/accounts/safe7579/test/Launchpad.t.sol @@ -8,6 +8,9 @@ import { MockValidator } from "./mocks/MockValidator.sol"; import { MockRegistry } from "./mocks/MockRegistry.sol"; import { MockExecutor } from "./mocks/MockExecutor.sol"; import { MockFallback } from "./mocks/MockFallback.sol"; +import { ExecutionLib } from "erc7579/lib/ExecutionLib.sol"; +import { ModeLib } from "erc7579/lib/ModeLib.sol"; +import { IERC7579Account, Execution } from "erc7579/interfaces/IERC7579Account.sol"; import { MockTarget } from "./mocks/MockTarget.sol"; import { Safe } from "@safe-global/safe-contracts/contracts/Safe.sol"; @@ -32,6 +35,7 @@ contract LaunchpadBase is Test { MockValidator defaultValidator; MockExecutor defaultExecutor; + MockTarget target; Account signer1 = makeAccount("signer1"); Account signer2 = makeAccount("signer2"); @@ -61,6 +65,7 @@ contract LaunchpadBase is Test { // Set up Modules defaultValidator = new MockValidator(); defaultExecutor = new MockExecutor(); + target = new MockTarget(); bytes32 salt; @@ -93,7 +98,17 @@ contract LaunchpadBase is Test { ), safe7579: address(safe7579), validators: validators, - callData: "" + callData: abi.encodeCall( + IERC7579Account.execute, + ( + ModeLib.encodeSimpleSingle(), + ExecutionLib.encodeSingle({ + target: address(target), + value: 0, + callData: abi.encodeCall(MockTarget.set, (1337)) + }) + ) + ) }); bytes32 initHash = launchpad.hash(initData); @@ -129,6 +144,8 @@ contract LaunchpadBase is Test { entrypoint.handleOps(userOps, payable(address(0x69))); safe = Safe(payable(predict)); + + assertEq(target.value(), 1337); } function _initCode( diff --git a/accounts/safe7579/test/SafeERC7579.t.sol b/accounts/safe7579/test/SafeERC7579.t.sol index bc5f1ea5..28f44995 100644 --- a/accounts/safe7579/test/SafeERC7579.t.sol +++ b/accounts/safe7579/test/SafeERC7579.t.sol @@ -9,8 +9,6 @@ import "./Launchpad.t.sol"; import "forge-std/console2.sol"; contract Safe7579Test is LaunchpadBase { - MockTarget target; - function setUp() public override { super.setUp(); target = new MockTarget(); diff --git a/accounts/safe7579/test/mocks/MockTarget.sol b/accounts/safe7579/test/mocks/MockTarget.sol index 06c2cbe3..f56fb925 100644 --- a/accounts/safe7579/test/mocks/MockTarget.sol +++ b/accounts/safe7579/test/mocks/MockTarget.sol @@ -4,7 +4,10 @@ pragma solidity ^0.8.23; contract MockTarget { uint256 public value; + event Access(address sender); + function set(uint256 _value) public returns (uint256) { + emit Access(msg.sender); value = _value; return _value; } From ab258b151cbef2719d8daa377aea09f24707f644 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Wed, 10 Apr 2024 13:56:44 +0700 Subject: [PATCH 39/64] clean up --- accounts/safe7579/src/core/Initializer.sol | 1 - accounts/safe7579/src/utils/Launchpadv2.sol | 6 ++++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/accounts/safe7579/src/core/Initializer.sol b/accounts/safe7579/src/core/Initializer.sol index 533900b1..e171102e 100644 --- a/accounts/safe7579/src/core/Initializer.sol +++ b/accounts/safe7579/src/core/Initializer.sol @@ -5,7 +5,6 @@ import { ISafe7579Init } from "../interfaces/ISafe7579Init.sol"; import "./ModuleManager.sol"; import { HookManager } from "./HookManager.sol"; import { IERC7484 } from "../interfaces/IERC7484.sol"; -import "forge-std/console2.sol"; abstract contract Initializer is ISafe7579Init, HookManager { using SentinelList4337Lib for SentinelList4337Lib.SentinelList; diff --git a/accounts/safe7579/src/utils/Launchpadv2.sol b/accounts/safe7579/src/utils/Launchpadv2.sol index 3b866672..cd427e69 100644 --- a/accounts/safe7579/src/utils/Launchpadv2.sol +++ b/accounts/safe7579/src/utils/Launchpadv2.sol @@ -83,6 +83,11 @@ contract Safe7579Launchpad is IAccount, SafeStorage { REGISTRY = registry; } + modifier onlyDelegatecall() { + require(msg.sender == address(this), "Only delegatecall"); + _; + } + function initSafe7579( address safe7579, ISafe7579Init.ModuleInit[] calldata validators, @@ -93,6 +98,7 @@ contract Safe7579Launchpad is IAccount, SafeStorage { uint8 threshold ) public + onlyDelegatecall { ISafe(address(this)).enableModule(safe7579); SafeERC7579(payable(safe7579)).initializeAccount({ From 00c411e5b58acc465099ad51d7164dfba193fc1c Mon Sep 17 00:00:00 2001 From: zeroknots Date: Wed, 10 Apr 2024 14:12:49 +0700 Subject: [PATCH 40/64] bug: excluding initData.calldata from inithash --- accounts/safe7579/src/utils/Launchpadv2.sol | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/accounts/safe7579/src/utils/Launchpadv2.sol b/accounts/safe7579/src/utils/Launchpadv2.sol index cd427e69..5055d339 100644 --- a/accounts/safe7579/src/utils/Launchpadv2.sol +++ b/accounts/safe7579/src/utils/Launchpadv2.sol @@ -320,6 +320,16 @@ contract Safe7579Launchpad is IAccount, SafeStorage { } function hash(InitData memory data) public returns (bytes32) { - return keccak256(abi.encode(data)); + return keccak256( + abi.encode( + data.singleton, + data.owners, + data.threshold, + data.setupTo, + data.setupData, + data.safe7579, + data.validators + ) + ); } } From 049cd401ebabebc58c34b82d0cfe071ef0977f01 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Thu, 11 Apr 2024 09:09:02 +0700 Subject: [PATCH 41/64] =?UTF-8?q?=F0=9F=93=9D=20Adding=20inline=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit wip foo wip wip 📝 More docs adding docs fix wip wip --- accounts/safe7579/README.md | 64 +++++- accounts/safe7579/script/Deploy.s.sol | 1 - accounts/safe7579/src/SafeERC7579.sol | 13 +- accounts/safe7579/src/core/EventManager.sol | 2 +- accounts/safe7579/src/core/HookManager.sol | 3 +- accounts/safe7579/src/core/Initializer.sol | 33 ++- accounts/safe7579/src/core/ModuleManager.sol | 2 - .../safe7579/src/core/RegistryAdapter.sol | 4 +- .../utils/{Launchpadv2.sol => Launchpad.sol} | 214 +++++++++--------- accounts/safe7579/src/utils/SignerFactory.sol | 134 ----------- accounts/safe7579/test/Launchpad.t.sol | 4 +- 11 files changed, 210 insertions(+), 264 deletions(-) delete mode 100644 accounts/safe7579/script/Deploy.s.sol rename accounts/safe7579/src/utils/{Launchpadv2.sol => Launchpad.sol} (59%) delete mode 100644 accounts/safe7579/src/utils/SignerFactory.sol diff --git a/accounts/safe7579/README.md b/accounts/safe7579/README.md index feb4a787..240934cc 100644 --- a/accounts/safe7579/README.md +++ b/accounts/safe7579/README.md @@ -1,3 +1,38 @@ +## How Safe7579 works + +Safe7579 provides full ERC4337 and ERC7579 compliance to Safe accounts by serving as the Safe's FallbackHandler and an enabled module. This setup allows Safe accounts to utilize all ERC7579 modules. A launchpad is developed to facilitate the setup of new safes with Safe7579 using the EntryPoint factory. + +## How does the Launchpad work + +1. **Creation by Factory:** + + - Bundler informs Entrypoint to handleUserOps. + - Entrypoint calls SenderCreator to call SafeProxyFactory + - SenderCreator requests SafeProxy creation from SafeProxyFactory using createProxyWithNonce. + - SafeProxyFactory creates a new SafeProxy using create2. + - SafeProxy is created with a singleton address set to Launchpad (!) + - InitHash is stored in the SafeProxy storage + +2. **Validation Phase:** + + - Entrypoint validates user operations in SafeProxy via validateUserOp. + - SafeProxy delegates validation to Launchpad. + - Launchpad ensures the presence of initHash from phase 1 and calls Safe7579.launchpadValidators. + - ValidatorModule gets installed by Launchpad + - ValidatorModule validates user operations and returns packedValidationData. + - Launchpad returns packedValidationData to SafeProxy, SafeProxy returns to Entrypoint. + +3. **Execution Phase:** + - Entrypoint triggers launchpad.setupSafe in SafeProxy. + - SafeProxy delegates the setup to Launchpad + - LaunchPad upgradres SafeStorage.singleton to SafeSingleton + - LaunchPad calls SafeProxy.setup() to initialize SafeSingleton + - Setup function in SafeProxy.setup() delegatecalls to lauchpad.initSafe7579 + - initSafe7579() initilazies Safe7579 with executors, fallbacks, hooks, IERC7484 registry + +This detailed sequence outlines the creation, validation, and execution phases in the system's operation. + +```mermaid sequenceDiagram participant Bundler participant Entrypoint @@ -12,7 +47,7 @@ participant EventEmitter participant ValidatorModule participant Executor -rect rgb(255,179,186) +alt Creation by Factory Bundler->>Entrypoint: handleUserOps Entrypoint->>SenderCreator: create this initcode SenderCreator->>+SafeProxyFactory: createProxyWithNonce(launchpad, intializer, salt) @@ -25,7 +60,7 @@ SafeProxy-->>SafeProxyFactory: created SafeProxyFactory-->>Entrypoint: created sender end -rect rgb(255,179,186) +alt Validation Phase Entrypoint->>+SafeProxy: validateUserOp SafeProxy-->>Launchpad: validateUserOp [delegatecall] Note right of Launchpad: only initializeThenUserOp.selector @@ -44,7 +79,8 @@ ValidatorModule ->> Launchpad: packedValidationData Launchpad-->>SafeProxy: packedValidationData SafeProxy->>-Entrypoint: packedValidationData end -rect rgb(186,225,255) + +alt Execution Phase Entrypoint->>+SafeProxy: setupSafe SafeProxy-->>Launchpad: setupSafe [delegatecall] Note over SafeProxy, Launchpad: sstore safe.singleton == SafeSingleton @@ -74,3 +110,25 @@ end Safe7579->>SafeProxy: exec done SafeProxy->-Entrypoint: exec done end +``` + +## Authors / Credits✨ + +Thanks to the following people who have contributed to this project: + + + + + + + + + + + + + +

zeroknots (rhinestone)

💻

Konrad (rhinestone)

📝

Nicholas Rodrigues Lordello +

📝
+ +Special Thanks to the Safe Team for their support and guidance in the development of Safe7579. diff --git a/accounts/safe7579/script/Deploy.s.sol b/accounts/safe7579/script/Deploy.s.sol deleted file mode 100644 index 8b137891..00000000 --- a/accounts/safe7579/script/Deploy.s.sol +++ /dev/null @@ -1 +0,0 @@ - diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index 2d920ed3..bef248b1 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -23,10 +23,7 @@ import { MODULE_TYPE_FALLBACK } from "erc7579/interfaces/IERC7579Module.sol"; import { AccessControl } from "./core/AccessControl.sol"; -import { HookManager } from "./core/HookManager.sol"; -import { EventManager } from "./core/EventManager.sol"; import { Initializer } from "./core/Initializer.sol"; -import "./core/ModuleManager.sol"; import { ISafeOp, SAFE_OP_TYPEHASH } from "./interfaces/ISafeOp.sol"; import { ISafe } from "./interfaces/ISafe.sol"; import { @@ -38,14 +35,11 @@ import { IEntryPoint } from "@ERC4337/account-abstraction/contracts/interfaces/I import { ISafe7579Init } from "./interfaces/ISafe7579Init.sol"; import { IERC1271 } from "./interfaces/IERC1271.sol"; -import "forge-std/console2.sol"; /** * @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 + * creates full ERC7579 compliance to Safe accounts + * @author rhinestone | zeroknots.eth, Konrad Kopp (@kopy-kat) */ - contract SafeERC7579 is ISafeOp, IERC7579Account, @@ -84,6 +78,8 @@ contract SafeERC7579 is { CallType callType; ExecType execType; + + // solhint-disable-next-line no-inline-assembly assembly { callType := mode execType := shl(8, mode) @@ -143,6 +139,7 @@ contract SafeERC7579 is { CallType callType; ExecType execType; + // solhint-disable-next-line no-inline-assembly assembly { callType := mode execType := shl(8, mode) diff --git a/accounts/safe7579/src/core/EventManager.sol b/accounts/safe7579/src/core/EventManager.sol index 0c08fed7..aaa96e90 100644 --- a/accounts/safe7579/src/core/EventManager.sol +++ b/accounts/safe7579/src/core/EventManager.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.25; -import "./ExecutionHelper.sol"; +import { ExecutionHelper } from "./ExecutionHelper.sol"; contract EventEmitter { event ModuleInstalled(uint256 moduleTypeId, address module); diff --git a/accounts/safe7579/src/core/HookManager.sol b/accounts/safe7579/src/core/HookManager.sol index e1c37f04..6b69c228 100644 --- a/accounts/safe7579/src/core/HookManager.sol +++ b/accounts/safe7579/src/core/HookManager.sol @@ -1,8 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.23; -import { ModuleManager, MODULE_TYPE_HOOK } from "./ModuleManager.sol"; +import { ModuleManager } from "./ModuleManager.sol"; import { IHook, IModule } from "erc7579/interfaces/IERC7579Module.sol"; +import { MODULE_TYPE_HOOK } from "erc7579/interfaces/IERC7579Module.sol"; /** * @title reference implementation of HookManager diff --git a/accounts/safe7579/src/core/Initializer.sol b/accounts/safe7579/src/core/Initializer.sol index e171102e..07dfea30 100644 --- a/accounts/safe7579/src/core/Initializer.sol +++ b/accounts/safe7579/src/core/Initializer.sol @@ -2,10 +2,15 @@ pragma solidity ^0.8.23; import { ISafe7579Init } from "../interfaces/ISafe7579Init.sol"; -import "./ModuleManager.sol"; import { HookManager } from "./HookManager.sol"; +import { ModuleManagerStorage } from "./ModuleManager.sol"; import { IERC7484 } from "../interfaces/IERC7484.sol"; +import { SentinelList4337Lib } from "sentinellist/SentinelList4337.sol"; +import { SentinelListLib } from "sentinellist/SentinelList.sol"; +/** + * Functions that can be used to initialze Safe7579 for a Safe Account + */ abstract contract Initializer is ISafe7579Init, HookManager { using SentinelList4337Lib for SentinelList4337Lib.SentinelList; using SentinelListLib for SentinelListLib.SentinelList; @@ -14,6 +19,14 @@ abstract contract Initializer is ISafe7579Init, HookManager { error InvalidInitData(address safe); + /** + * This function is intended to be called by Launchpad.validateUserOp() + * @dev it will initialize the SentinelList4337 list for validators, and sstore all + * validators + * @dev Since this function has to be 4337 compliant (storage access), only validator storage is acccess + * @dev Note: this function DOES NOT call onInstall() on the validator modules or emit + * ModuleInstalled events. this has to be done by the launchpad + */ function launchpadValidators(ModuleInit[] calldata validators) external payable override { $validators.init({ account: msg.sender }); uint256 length = validators.length; @@ -26,6 +39,20 @@ abstract contract Initializer is ISafe7579Init, HookManager { } } + /** + * This function can be called by the Launchpad.initSafe7579() or by already existing Safes that + * want to use Safe7579 + * if this is called by the Launchpad, it is expected that launchpadValidators() was called + * previously, and the param validators is empty + * @param validators validator modules and initData + * @param executors executor modules and initData + * @param executors executor modules and initData + * @param fallbacks fallback modules and initData + * @param hook hook module and initData + * @param registryInit (OPTIONAL) registry, attesters and threshold for IERC7484 Registry + * If not provided, the registry will be set to the zero address, and no + * registry checks will be performed + */ function initializeAccount( ModuleInit[] calldata validators, ModuleInit[] calldata executors, @@ -58,6 +85,7 @@ abstract contract Initializer is ISafe7579Init, HookManager { $validators.init({ account: msg.sender }); for (uint256 i; i < length; i++) { ModuleInit calldata validator = validators[i]; + // enable module on Safe7579, initialize module via Safe, emit events _installValidator(validator.module, validator.initData); } } else if (length != 0) { @@ -71,12 +99,14 @@ abstract contract Initializer is ISafe7579Init, HookManager { length = executors.length; for (uint256 i; i < length; i++) { ModuleInit calldata executor = executors[i]; + // enable module on Safe7579, initialize module via Safe, emit events _installExecutor(executor.module, executor.initData); } length = fallbacks.length; for (uint256 i; i < length; i++) { ModuleInit calldata _fallback = fallbacks[i]; + // enable module on Safe7579, initialize module via Safe, emit events _installFallbackHandler(_fallback.module, _fallback.initData); } @@ -91,6 +121,7 @@ abstract contract Initializer is ISafe7579Init, HookManager { uint8 threshold ) external + onlyEntryPointOrSelf { _configureRegistry(registry, attesters, threshold); } diff --git a/accounts/safe7579/src/core/ModuleManager.sol b/accounts/safe7579/src/core/ModuleManager.sol index ed96065d..05379e35 100644 --- a/accounts/safe7579/src/core/ModuleManager.sol +++ b/accounts/safe7579/src/core/ModuleManager.sol @@ -12,9 +12,7 @@ import { AccessControl } from "./AccessControl.sol"; import { CallType, CALLTYPE_SINGLE, CALLTYPE_DELEGATECALL } from "erc7579/lib/ModeLib.sol"; import { - IValidator, MODULE_TYPE_VALIDATOR, - MODULE_TYPE_HOOK, MODULE_TYPE_EXECUTOR, MODULE_TYPE_FALLBACK } from "erc7579/interfaces/IERC7579Module.sol"; diff --git a/accounts/safe7579/src/core/RegistryAdapter.sol b/accounts/safe7579/src/core/RegistryAdapter.sol index 4e386e93..e6e9b961 100644 --- a/accounts/safe7579/src/core/RegistryAdapter.sol +++ b/accounts/safe7579/src/core/RegistryAdapter.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.23; -import "../interfaces/IERC7484.sol"; -import "./ExecutionHelper.sol"; +import { IERC7484 } from "../interfaces/IERC7484.sol"; +import { ExecutionHelper } from "./ExecutionHelper.sol"; abstract contract RegistryAdapter is ExecutionHelper { event ERC7484RegistryConfigured(address indexed smartAccount, address indexed registry); diff --git a/accounts/safe7579/src/utils/Launchpadv2.sol b/accounts/safe7579/src/utils/Launchpad.sol similarity index 59% rename from accounts/safe7579/src/utils/Launchpadv2.sol rename to accounts/safe7579/src/utils/Launchpad.sol index 5055d339..86d61ed1 100644 --- a/accounts/safe7579/src/utils/Launchpadv2.sol +++ b/accounts/safe7579/src/utils/Launchpad.sol @@ -2,13 +2,7 @@ pragma solidity ^0.8.22; import { IAccount, PackedUserOperation } from "account-abstraction/interfaces/IAccount.sol"; -import { - _packValidationData, - _parseValidationData, - ValidationData -} from "account-abstraction/core/Helpers.sol"; import { ISafe } from "../interfaces/ISafe.sol"; -import { IUniqueSignerFactory } from "./SignerFactory.sol"; import { ISafe7579Init } from "../interfaces/ISafe7579Init.sol"; import { IERC7484 } from "../interfaces/IERC7484.sol"; import { SafeERC7579 } from "../SafeERC7579.sol"; @@ -16,14 +10,27 @@ import { SafeERC7579 } from "../SafeERC7579.sol"; import { IValidator } from "erc7579/interfaces/IERC7579Module.sol"; import { SafeStorage } from "@safe-global/safe-contracts/contracts/libraries/SafeStorage.sol"; -import { ISignatureValidator } from - "@safe-global/safe-contracts/contracts/interfaces/ISignatureValidator.sol"; - -import "forge-std/console2.sol"; /** + * Launchpad to deploy a Safe account and connect the Safe7579 adapter. + * credits for the idea: nlordell (Safe) + * this launchpad is based on Safe 4337 Signer Launchpad: + * https://github.com/safe-global/safe-modules/pull/184/files + * @author rhinestone | zeroknots.eth */ contract Safe7579Launchpad is IAccount, SafeStorage { + event ModuleInstalled(uint256 moduleTypeId, address module); + + bytes32 private constant DOMAIN_SEPARATOR_TYPEHASH = + keccak256("EIP712Domain(uint256 chainId,address verifyingContract)"); + + // keccak256("Safe7579Launchpad.initHash") - 1 + uint256 private constant INIT_HASH_SLOT = + 0x982e06ee6a56dfc0f1ac189a5d23506361ca0a3ce45a9c7b8d33d65d43746a24; + + /** + * @notice The keccak256 hash of the EIP-712 InitData struct, representing the structure + */ struct InitData { address singleton; address[] owners; @@ -35,40 +42,9 @@ contract Safe7579Launchpad is IAccount, SafeStorage { bytes callData; } - event ModuleInstalled(uint256 moduleTypeId, address module); - - bytes32 private constant DOMAIN_SEPARATOR_TYPEHASH = - keccak256("EIP712Domain(uint256 chainId,address verifyingContract)"); - - // keccak256("SafeSignerLaunchpad.initHash") - 1 - uint256 private constant INIT_HASH_SLOT = - 0x1d2f0b9dbb6ed3f829c9614e6c5d2ea2285238801394dc57e8500e0e306d8f80; - - /** - * @notice The keccak256 hash of the EIP-712 SafeInit struct, representing the structure of a - * ERC-4337 compatible deferred Safe initialization. - * {address} singleton - The singleton to evolve into during the setup. - * {address} signerFactory - The unique signer factory to use for creating an owner. - * {bytes} signerData - The signer data to use the owner. - * {address} setupTo - The contract to delegatecall during setup. - * {bytes} setupData - The calldata for the setup delegatecall. - * {address} fallbackHandler - The fallback handler to initialize the Safe with. - */ + // solhint-disable max-line-length bytes32 private constant SAFE_INIT_TYPEHASH = keccak256( - "SafeInit(address singleton,address signerFactory,bytes signerData,address setupTo,bytes setupData,address fallbackHandler)" - ); - - /** - * @notice The keccak256 hash of the EIP-712 SafeInitOp struct, representing the user operation - * to execute alongside initialization. - * {bytes32} userOpHash - The user operation hash being executed. - * {uint48} validAfter - A timestamp representing from when the user operation is valid. - * {uint48} validUntil - A timestamp representing until when the user operation is valid, or 0 - * to indicated "forever". - * {address} entryPoint - The address of the entry point that will execute the user operation. - */ - bytes32 private constant SAFE_INIT_OP_TYPEHASH = keccak256( - "SafeInitOp(bytes32 userOpHash,uint48 validAfter,uint48 validUntil,address entryPoint)" + "InitData(address singleton,address[] owners,uint256 threshold,address setupTo,bytes setupData,address safe7579,ISafe7579Init.ModuleInit[] validators,bytes callData)" ); address private immutable SELF; @@ -88,9 +64,25 @@ contract Safe7579Launchpad is IAccount, SafeStorage { _; } + modifier onlyProxy() { + require(singleton == SELF, "Not called from proxy"); + _; + } + + modifier onlySupportedEntryPoint() { + require(msg.sender == SUPPORTED_ENTRYPOINT, "Unsupported entry point"); + _; + } + + receive() external payable { } + + /** + * This function is intended to be delegatecalled by the ISafe.setup function. It configures the + * Safe7579 for the user for all module types except validators, which were initialized in the + * validateUserOp function. + */ function initSafe7579( address safe7579, - ISafe7579Init.ModuleInit[] calldata validators, ISafe7579Init.ModuleInit[] calldata executors, ISafe7579Init.ModuleInit[] calldata fallbacks, ISafe7579Init.ModuleInit calldata hook, @@ -102,7 +94,7 @@ contract Safe7579Launchpad is IAccount, SafeStorage { { ISafe(address(this)).enableModule(safe7579); SafeERC7579(payable(safe7579)).initializeAccount({ - validators: validators, + validators: new ISafe7579Init.ModuleInit[](0), executors: executors, fallbacks: fallbacks, hook: hook, @@ -114,18 +106,14 @@ contract Safe7579Launchpad is IAccount, SafeStorage { }); } - modifier onlyProxy() { - require(singleton == SELF, "Not called from proxy"); - _; - } - - modifier onlySupportedEntryPoint() { - require(msg.sender == SUPPORTED_ENTRYPOINT, "Unsupported entry point"); - _; - } - - receive() external payable { } - + /** + * SafeProxyFactory will create a SafeProxy and using this contract as the singleton + * implementation and call this function to initialize the account. + * will write initHash into SafeProxy storage + * @param initHash will be calculated offchain using this.hash(InitData) + * @param to optional parameter for a delegatecall + * @param preInit optional parameter for a delegatecall + */ function preValidationSetup( bytes32 initHash, address to, @@ -134,13 +122,35 @@ contract Safe7579Launchpad is IAccount, SafeStorage { external onlyProxy { + // sstore inithash _setInitHash(initHash); + + // if a delegatecall target is provided, SafeProxy will execute a delegatecall if (to != address(0)) { (bool success,) = to.delegatecall(preInit); require(success, "Pre-initialization failed"); } } + /** + * Upon creation of SafeProxy by SafeProxyFactory, EntryPoint invokes this function to verify + * the transaction. It ensures that only this.setupSafe() can be called by EntryPoint during + * execution. The function validates the hash of InitData in userOp.callData against the hash + * stored in preValidationSetup. This function abides by ERC4337 storage restrictions, allowing + * Safe7579 adapter initialization only in Validation Modules compliant with 4337. It installs + * validators from InitData onto the Safe7579 adapter for the account. When called by EP, the + * SafeProxy singleton address remains unupgraded to SafeSingleton, preventing + * execTransactionFromModule by Safe7579 Adapter. Initialization of Validator Modules is + * achieved through a direct call to onInstall(). This delegatecalled function initializes the + * Validator Module with the correct msg.sender. Once all validator modules are set up, they can + * be used to validate the userOp. Parameters include userOp (EntryPoint v0.7 userOp), + * userOpHash, and missingAccountFunds representing the gas payment required. + * + * @param userOp EntryPoint v0.7 userOp. + * @param userOpHash hash of userOp + * @param missingAccountFunds amount of gas that has to be paid + * @return validationData 4337 packed validation data returned by the validator module + */ function validateUserOp( PackedUserOperation calldata userOp, bytes32 userOpHash, @@ -148,7 +158,7 @@ contract Safe7579Launchpad is IAccount, SafeStorage { ) external override - onlyProxy + onlyProxy // ensure SafeProxy called this onlySupportedEntryPoint returns (uint256 validationData) { @@ -157,6 +167,7 @@ contract Safe7579Launchpad is IAccount, SafeStorage { ); InitData memory initData = abi.decode(userOp.callData[4:], (InitData)); + // read stored initHash from SafeProxy storage. only proceed if the InitData hash matches require(hash(initData) == _initHash(), "invalid init hash"); // get validator from nonce encoding @@ -170,18 +181,23 @@ contract Safe7579Launchpad is IAccount, SafeStorage { // initialize validator on behalf of the safe account ISafe7579Init(initData.safe7579).launchpadValidators(initData.validators); + // Call onInstall on each validator module to set up the validators. + // Since this function is delegatecalled by the SafeProxy, the Validator Module is called + // with msg.sender == SafeProxy. bool userOpValidatorInstalled; uint256 validatorsLength = initData.validators.length; for (uint256 i; i < validatorsLength; i++) { address validatorModule = initData.validators[i].module; IValidator(validatorModule).onInstall(initData.validators[i].initData); emit ModuleInstalled(1, validatorModule); + if (validatorModule == validator) userOpValidatorInstalled = true; } - // if the validator in the userOp was not installed, it MUST not be used to validate + // Ensure that the validator module selected in the userOp was + // part of the validators in InitData if (!userOpValidatorInstalled) return 1; - // validate userOp with selected validation module + // validate userOp with selected validation module. validationData = IValidator(validator).validateUserOp(userOp, userOpHash); // pay back gas to EntryPoint @@ -193,10 +209,25 @@ contract Safe7579Launchpad is IAccount, SafeStorage { } } + /** + * During the execution phase of ERC4337, this function upgrades the SafeProxy to the actual + * SafeSingleton implementation. Subsequently, it invokes the ISafe.setup() function to + * initialize the Safe Account. The setup() function should ensure the completion of Safe7579 + * Adapter initialization with InitData.setupTo as address(this) and InitData.setupData encoding + * the call to this.initSafe7579(). SafeProxy.setup() delegatecalls this function to install + * executors, fallbacks, hooks, and registry configurations on the Safe7579 adapter. As this + * occurs in the ERC4337 execution phase, storage restrictions are not applicable. + * + * @param initData initData to initialize the Safe and Safe7579 Adapter + */ function setupSafe(InitData calldata initData) external onlySupportedEntryPoint { - // update singleton to Safe account impl + // update singleton to Safe account implementation + // from now on, ISafe can be used to interact with the SafeProxy SafeStorage.singleton = initData.singleton; + // setup SafeAccount + // setupTo should be this launchpad + // setupData should be a call to this.initSafe7579() ISafe(address(this)).setup({ _owners: initData.owners, _threshold: initData.threshold, @@ -210,8 +241,9 @@ contract Safe7579Launchpad is IAccount, SafeStorage { // reset initHash _setInitHash(0); - // call function on safe7579 as safe. attach address(this) - // to comply with 2771 access control + // in order to allow launchpad users to perform 7579 account operations like execute(), in + // the safe transaction context of the launchpad setup, any call can be encoded in + // initData.callData (bool success, bytes memory returnData) = address(initData.safe7579).call( abi.encodePacked( initData.callData, // encode arbitrary execution here. i.e. IERC7579.execute() @@ -230,27 +262,7 @@ contract Safe7579Launchpad is IAccount, SafeStorage { return keccak256(abi.encode(DOMAIN_SEPARATOR_TYPEHASH, block.chainid, SELF)); } - function _getOperationData( - bytes32 userOpHash, - uint48 validAfter, - uint48 validUntil - ) - public - view - returns (bytes memory operationData) - { - operationData = abi.encodePacked( - bytes1(0x19), - bytes1(0x01), - _domainSeparator(), - keccak256( - abi.encode( - SAFE_INIT_OP_TYPEHASH, userOpHash, validAfter, validUntil, SUPPORTED_ENTRYPOINT - ) - ) - ); - } - + // sload inithash from SafeProxy storage function _initHash() public view returns (bytes32 value) { // solhint-disable-next-line no-inline-assembly assembly ("memory-safe") { @@ -258,6 +270,7 @@ contract Safe7579Launchpad is IAccount, SafeStorage { } } + // store inithash in SafeProxy storage function _setInitHash(bytes32 value) internal { // solhint-disable-next-line no-inline-assembly assembly ("memory-safe") { @@ -265,29 +278,11 @@ contract Safe7579Launchpad is IAccount, SafeStorage { } } - function _isContract(address account) internal view returns (bool) { - uint256 size; - /* solhint-disable no-inline-assembly */ - /// @solidity memory-safe-assembly - assembly { - size := extcodesize(account) - } - /* solhint-enable no-inline-assembly */ - return size > 0; - } - - function getOperationHash( - bytes32 userOpHash, - uint48 validAfter, - uint48 validUntil - ) - public - view - returns (bytes32 operationHash) - { - operationHash = keccak256(_getOperationData(userOpHash, validAfter, validUntil)); - } - + /** + * Helper function that can be used offchain to predict the counterfactual Safe address. + * @dev factoryInitializer is expected to be: + * abi.encodeCall(Safe7579Launchpad.preValidationSetup, (initHash, to, callData)); + */ function predictSafeAddress( address singleton, address safeProxyFactory, @@ -319,7 +314,10 @@ contract Safe7579Launchpad is IAccount, SafeStorage { ); } - function hash(InitData memory data) public returns (bytes32) { + /** + * Create unique InitData hash. Using all params but excluding data.callData from hash + */ + function hash(InitData memory data) public pure returns (bytes32) { return keccak256( abi.encode( data.singleton, diff --git a/accounts/safe7579/src/utils/SignerFactory.sol b/accounts/safe7579/src/utils/SignerFactory.sol deleted file mode 100644 index 050643a4..00000000 --- a/accounts/safe7579/src/utils/SignerFactory.sol +++ /dev/null @@ -1,134 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.23; - -import { ISignatureValidator } from - "@safe-global/safe-contracts/contracts/interfaces/ISignatureValidator.sol"; - -interface IUniqueSignerFactory { - /** - * @notice Gets the unique signer address for the specified data. - * @dev The unique signer address must be unique for some given data. The signer is not - * guaranteed to be created yet. - * @param data The signer specific data. - * @return signer The signer address. - */ - function getSigner(bytes memory data) external view returns (address signer); - - /** - * @notice Create a new unique signer for the specified data. - * @dev The unique signer address must be unique for some given data. This must not revert if - * the unique owner already exists. - * @param data The signer specific data. - * @return signer The signer address. - */ - function createSigner(bytes memory data) external returns (address signer); - - /** - * @notice Verifies a signature for the specified address without deploying it. - * @dev This must be equivalent to first deploying the signer with the factory, and then - * verifying the signature - * with it directly: `factory.createSigner(signerData).isValidSignature(data, signature)` - * @param data The data whose signature should be verified. - * @param signature The signature bytes. - * @param signerData The signer data to verify signature for. - * @return magicValue Returns `ISignatureValidator.isValidSignature.selector` when the signature - * is valid. Reverting or returning any other value implies an invalid signature. - */ - function isValidSignatureForSigner( - bytes calldata data, - bytes calldata signature, - bytes calldata signerData - ) - external - view - returns (bytes4 magicValue); -} - -function checkSignature( - bytes memory data, - uint256 signature, - uint256 key -) - pure - returns (bytes4 magicValue) -{ - uint256 message = uint256(keccak256(data)); - - // A very silly signing scheme where the `message = signature ^ key` - if (message == signature ^ key) { - magicValue = ISignatureValidator.isValidSignature.selector; - } -} - -contract UniqueSignerFactory is IUniqueSignerFactory { - function getSigner(bytes calldata data) public view returns (address signer) { - uint256 key = abi.decode(data, (uint256)); - signer = _getSigner(key); - } - - function createSigner(bytes calldata data) external returns (address signer) { - uint256 key = abi.decode(data, (uint256)); - signer = _getSigner(key); - if (_hasNoCode(signer)) { - TestUniqueSigner created = new TestUniqueSigner{ salt: bytes32(0) }(key); - require(address(created) == signer); - } - } - - function isValidSignatureForSigner( - bytes memory data, - bytes memory signatureData, - bytes memory signerData - ) - external - pure - override - returns (bytes4 magicValue) - { - uint256 key = abi.decode(signerData, (uint256)); - uint256 signature = abi.decode(signatureData, (uint256)); - magicValue = checkSignature(data, signature, key); - } - - function _getSigner(uint256 key) internal view returns (address) { - bytes32 codeHash = keccak256(abi.encodePacked(type(TestUniqueSigner).creationCode, key)); - return address( - uint160( - uint256(keccak256(abi.encodePacked(hex"ff", address(this), bytes32(0), codeHash))) - ) - ); - } - - function _hasNoCode(address account) internal view returns (bool) { - uint256 size; - /* solhint-disable no-inline-assembly */ - /// @solidity memory-safe-assembly - assembly { - size := extcodesize(account) - } - /* solhint-enable no-inline-assembly */ - return size == 0; - } -} - -contract TestUniqueSigner is ISignatureValidator { - uint256 public immutable KEY; - - constructor(uint256 key) { - KEY = key; - } - - function isValidSignature( - bytes memory data, - bytes memory signatureData - ) - public - view - virtual - override - returns (bytes4 magicValue) - { - uint256 signature = abi.decode(signatureData, (uint256)); - magicValue = checkSignature(data, signature, KEY); - } -} diff --git a/accounts/safe7579/test/Launchpad.t.sol b/accounts/safe7579/test/Launchpad.t.sol index 00acc2b3..d4430948 100644 --- a/accounts/safe7579/test/Launchpad.t.sol +++ b/accounts/safe7579/test/Launchpad.t.sol @@ -19,8 +19,7 @@ import { SafeProxyFactory } from "@safe-global/safe-contracts/contracts/proxies/SafeProxyFactory.sol"; import { LibClone } from "solady/utils/LibClone.sol"; -import "src/utils/Launchpadv2.sol"; -import "src/utils/SignerFactory.sol"; +import "src/utils/Launchpad.sol"; import "src/interfaces/ISafe7579Init.sol"; import { Solarray } from "solarray/Solarray.sol"; @@ -88,7 +87,6 @@ contract LaunchpadBase is Test { Safe7579Launchpad.initSafe7579, ( address(safe7579), - new ISafe7579Init.ModuleInit[](0), executors, fallbacks, hook, From acf362d4dd3b1e335d0cee31e9e890c4b71a3cce Mon Sep 17 00:00:00 2001 From: zeroknots Date: Thu, 11 Apr 2024 11:24:03 +0700 Subject: [PATCH 42/64] fix bug in 1271 --- accounts/safe7579/src/SafeERC7579.sol | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index bef248b1..4df96fbf 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.23; import { IERC7579Account, Execution } from "erc7579/interfaces/IERC7579Account.sol"; import { IMSA } from "erc7579/interfaces/IMSA.sol"; +import "./lib/ExecOnSafeLib.sol"; import { CallType, ExecType, @@ -48,6 +49,7 @@ contract SafeERC7579 is Initializer, IMSA { + using ExecOnSafeLib for ISafe; using UserOperationLib for PackedUserOperation; using ModeLib for ModeCode; using ExecutionLib for bytes; @@ -73,7 +75,6 @@ contract SafeERC7579 is external payable override - withHook // ! this modifier has side effects / external calls onlyEntryPointOrSelf { CallType callType; @@ -88,11 +89,11 @@ contract SafeERC7579 is if (execType == EXECTYPE_DEFAULT) { if (callType == CALLTYPE_BATCH) { Execution[] calldata executions = executionCalldata.decodeBatch(); - _execute(msg.sender, executions); + ISafe(msg.sender).hookedExec(executions); } else if (callType == CALLTYPE_SINGLE) { (address target, uint256 value, bytes calldata callData) = executionCalldata.decodeSingle(); - _execute(msg.sender, target, value, callData); + _execute({ safe: msg.sender, target: target, value: value, callData: callData }); } else if (callType == CALLTYPE_DELEGATECALL) { address target = address(bytes20(executionCalldata[:20])); bytes calldata callData = executionCalldata[20:]; @@ -134,7 +135,6 @@ contract SafeERC7579 is override onlyExecutorModule withRegistry(msg.sender, MODULE_TYPE_EXECUTOR) - withHook // ! this modifier has side effects / external calls returns (bytes[] memory returnData) { CallType callType; @@ -298,7 +298,7 @@ contract SafeERC7579 is // use 7579 validation module magicValue = - IValidator(validationModule).isValidSignatureWithSender(msg.sender, hash, data[20:]); + IValidator(validationModule).isValidSignatureWithSender(_msgSender(), hash, data[20:]); } /** From 97ef9335c097b1307f71d5c8cae7ca4b4d388d25 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Tue, 16 Apr 2024 11:19:36 +0700 Subject: [PATCH 43/64] working --- accounts/safe7579/package.json | 18 +- accounts/safe7579/src/SafeERC7579.sol | 133 ++-- accounts/safe7579/src/core/DCUtil.sol | 29 + accounts/safe7579/src/core/EventManager.sol | 41 -- ...tionHelper.sol => ExecutionHelper.sol.bak} | 0 accounts/safe7579/src/core/HookManager.sol | 74 +-- accounts/safe7579/src/core/Initializer.sol | 1 + accounts/safe7579/src/core/ModuleManager.sol | 57 +- .../safe7579/src/core/RegistryAdapter.sol | 17 +- accounts/safe7579/src/lib/ExecOnSafeLib.sol | 310 +++++++++ .../safe7579/src/utils/DelegatecallTarget.sol | 79 +++ accounts/safe7579/test/SafeERC7579.t.sol | 22 +- .../src/modules/ERC7579HookDestruct.sol | 14 +- pnpm-lock.yaml | 601 +++++++++++------- 14 files changed, 924 insertions(+), 472 deletions(-) create mode 100644 accounts/safe7579/src/core/DCUtil.sol delete mode 100644 accounts/safe7579/src/core/EventManager.sol rename accounts/safe7579/src/core/{ExecutionHelper.sol => ExecutionHelper.sol.bak} (100%) create mode 100644 accounts/safe7579/src/lib/ExecOnSafeLib.sol create mode 100644 accounts/safe7579/src/utils/DelegatecallTarget.sol diff --git a/accounts/safe7579/package.json b/accounts/safe7579/package.json index ef1a54f9..9795b556 100644 --- a/accounts/safe7579/package.json +++ b/accounts/safe7579/package.json @@ -11,23 +11,23 @@ "url": "https://github.com/rhinestonewtf/modulekit/issues" }, "devDependencies": { + "@ERC4337/account-abstraction": "github:kopy-kat/account-abstraction#develop", + "@ERC4337/account-abstraction-v0.6": "github:eth-infinitism/account-abstraction#v0.6.0", + "@openzeppelin/contracts": "5.0.1", + "@prb/math": "^4.0.2", "@rhinestone/modulekit": "workspace:*", "@rhinestone/sessionkeymanager": "workspace:*", "@safe-global/safe-contracts": "^1.4.1", - "@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", + "ds-test": "github:dapphub/ds-test", "erc4337-validation": "github:rhinestonewtf/erc4337-validation", - "@prb/math": "^4.0.2", + "erc7579": "github:erc7579/erc7579-implementation", "forge-std": "github:foundry-rs/forge-std", - "ds-test": "github:dapphub/ds-test", + "prettier": "^2.8.8", "sentinellist": "github:zeroknots/sentinellist", - "erc7579": "github:erc7579/erc7579-implementation", "solady": "github:vectorized/solady", "solarray": "github:sablier-labs/solarray", - "solmate": "github:transmissions11/solmate", - "solhint": "^4.1.1", - "prettier": "^2.8.8" + "solhint": "^4.5.4", + "solmate": "github:transmissions11/solmate" }, "files": [ "artifacts", diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index 4df96fbf..d25bceaf 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -65,20 +65,16 @@ contract SafeERC7579 is // keccak256("safeSignature(bytes32,bytes32,bytes,bytes)"); bytes4 private constant SAFE_SIGNATURE_MAGIC_VALUE = 0x5fd7e97d; - /** - * @inheritdoc IERC7579Account - */ - function execute( + function _execute( ModeCode mode, bytes calldata executionCalldata ) - external - payable - override - onlyEntryPointOrSelf + internal + returns (bytes[] memory returnData) { CallType callType; ExecType execType; + address hook = getActiveHook(); // solhint-disable-next-line no-inline-assembly assembly { @@ -87,35 +83,9 @@ contract SafeERC7579 is } if (execType == EXECTYPE_DEFAULT) { - if (callType == CALLTYPE_BATCH) { - Execution[] calldata executions = executionCalldata.decodeBatch(); - ISafe(msg.sender).hookedExec(executions); - } else if (callType == CALLTYPE_SINGLE) { - (address target, uint256 value, bytes calldata callData) = - executionCalldata.decodeSingle(); - _execute({ safe: msg.sender, target: target, value: value, callData: callData }); - } else if (callType == CALLTYPE_DELEGATECALL) { - address target = address(bytes20(executionCalldata[:20])); - bytes calldata callData = executionCalldata[20:]; - _executeDelegateCall(msg.sender, target, callData); - } else { - revert UnsupportedCallType(callType); - } + returnData = HookedExecOnSafeLib.hookedExec(executionCalldata, callType, hook); } else if (execType == EXECTYPE_TRY) { - if (callType == CALLTYPE_BATCH) { - Execution[] calldata executions = executionCalldata.decodeBatch(); - _tryExecute(msg.sender, executions); - } else if (callType == CALLTYPE_SINGLE) { - (address target, uint256 value, bytes calldata callData) = - executionCalldata.decodeSingle(); - _tryExecute(msg.sender, target, value, callData); - } else if (callType == CALLTYPE_DELEGATECALL) { - address target = address(bytes20(executionCalldata[:20])); - bytes calldata callData = executionCalldata[20:]; - _tryExecuteDelegateCall(msg.sender, target, callData); - } else { - revert UnsupportedCallType(callType); - } + returnData = HookedExecOnSafeLib.hookedTryExec(executionCalldata, callType, hook); } // account reverts when using unsupported execution type else { @@ -123,6 +93,21 @@ contract SafeERC7579 is } } + /** + * @inheritdoc IERC7579Account + */ + function execute( + ModeCode mode, + bytes calldata executionCalldata + ) + external + payable + override + onlyEntryPointOrSelf + { + _execute(mode, executionCalldata); + } + /** * @inheritdoc IERC7579Account */ @@ -137,54 +122,17 @@ contract SafeERC7579 is withRegistry(msg.sender, MODULE_TYPE_EXECUTOR) returns (bytes[] memory returnData) { - CallType callType; - ExecType execType; - // solhint-disable-next-line no-inline-assembly - assembly { - callType := mode - execType := shl(8, mode) - } - if (execType == EXECTYPE_DEFAULT) { - if (callType == CALLTYPE_BATCH) { - Execution[] calldata executions = executionCalldata.decodeBatch(); - returnData = _executeReturnData(msg.sender, executions); - } else if (callType == CALLTYPE_SINGLE) { - (address target, uint256 value, bytes calldata callData) = - executionCalldata.decodeSingle(); - returnData = new bytes[](1); - returnData[0] = _executeReturnData(msg.sender, target, value, callData); - } else if (callType == CALLTYPE_DELEGATECALL) { - address target = address(bytes20(executionCalldata[:20])); - bytes calldata callData = executionCalldata[20:]; - returnData = new bytes[](1); - returnData[0] = _executeDelegateCallReturnData(msg.sender, target, callData); - } else { - revert UnsupportedCallType(callType); - } - } else if (execType == EXECTYPE_TRY) { - if (callType == CALLTYPE_BATCH) { - Execution[] calldata executions = executionCalldata.decodeBatch(); - returnData = _tryExecuteReturnData(msg.sender, executions); - } else if (callType == CALLTYPE_SINGLE) { - (address target, uint256 value, bytes calldata callData) = - executionCalldata.decodeSingle(); - returnData = new bytes[](1); - returnData[0] = _tryExecuteReturnData(msg.sender, target, value, callData); - } else if (callType == CALLTYPE_DELEGATECALL) { - address target = address(bytes20(executionCalldata[:20])); - bytes calldata callData = executionCalldata[20:]; - returnData = new bytes[](1); - returnData[0] = _tryExecuteDelegateCallReturnData(msg.sender, target, callData); - } else { - revert UnsupportedCallType(callType); - } - } - // account reverts when using unsupported execution type - else { - revert UnsupportedExecType(execType); - } + return _execute(mode, executionCalldata); } + function executeUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash + ) + external + payable + { } + /** * ERC4337 v0.7 validation function * @dev expects that a ERC7579 validator module is encoded within the UserOp nonce. @@ -198,6 +146,7 @@ contract SafeERC7579 is ) external payable + onlyEntryPointOrSelf returns (uint256 validSignature) { address validator; @@ -213,23 +162,17 @@ contract SafeERC7579 is return _validateSignatures(userOp); } else { // bubble up the return value of the validator module - bytes memory retData = _executeReturnData( - msg.sender, - validator, - 0, - abi.encodeCall(IValidator.validateUserOp, (userOp, userOpHash)) - ); + bytes memory retData = ISafe(msg.sender).execReturn({ + target: validator, + value: 0, + callData: abi.encodeCall(IValidator.validateUserOp, (userOp, userOpHash)) + }); validSignature = abi.decode(retData, (uint256)); } // pay prefund if (missingAccountFunds != 0) { - _execute({ - safe: userOp.getSender(), - target: entryPoint(), - value: missingAccountFunds, - callData: "" - }); + ISafe(msg.sender).exec({ target: entryPoint(), value: missingAccountFunds, callData: "" }); } } @@ -312,7 +255,6 @@ contract SafeERC7579 is external payable override - withHook onlyEntryPointOrSelf { if (moduleType == MODULE_TYPE_VALIDATOR) _installValidator(module, initData); @@ -333,7 +275,6 @@ contract SafeERC7579 is external payable override - withHook onlyEntryPointOrSelf { if (moduleType == MODULE_TYPE_VALIDATOR) _uninstallValidator(module, deInitData); diff --git a/accounts/safe7579/src/core/DCUtil.sol b/accounts/safe7579/src/core/DCUtil.sol new file mode 100644 index 00000000..2937f6ee --- /dev/null +++ b/accounts/safe7579/src/core/DCUtil.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.25; + +import { DelegateCallTarget as DCTarget, EventEmitter } from "../utils/DelegatecallTarget.sol"; +import { ISafe, ExecOnSafeLib } from "../lib/ExecOnSafeLib.sol"; + +contract DelegateCallUtil { + using ExecOnSafeLib for ISafe; + + DCTarget internal DCTARGET; + + constructor() { + DCTARGET = new DCTarget(); + } + + function _emitModuleInstall(uint256 moduleTypeId, address module) internal { + ISafe(msg.sender).execDelegateCall({ + target: address(DCTARGET), + callData: abi.encodeCall(EventEmitter.emitModuleInstalled, (moduleTypeId, module)) + }); + } + + function _emitModuleUninstall(uint256 moduleTypeId, address module) internal { + ISafe(msg.sender).execDelegateCall({ + target: address(DCTARGET), + callData: abi.encodeCall(EventEmitter.emitModuleUninstalled, (moduleTypeId, module)) + }); + } +} diff --git a/accounts/safe7579/src/core/EventManager.sol b/accounts/safe7579/src/core/EventManager.sol deleted file mode 100644 index aaa96e90..00000000 --- a/accounts/safe7579/src/core/EventManager.sol +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.25; - -import { ExecutionHelper } from "./ExecutionHelper.sol"; - -contract EventEmitter { - event ModuleInstalled(uint256 moduleTypeId, address module); - event ModuleUninstalled(uint256 moduleTypeId, address module); - - function emitModuleInstalled(uint256 moduleTypeId, address module) external { - emit ModuleInstalled(moduleTypeId, module); - } - - function emitModuleUninstalled(uint256 moduleTypeId, address module) external { - emit ModuleUninstalled(moduleTypeId, module); - } -} - -contract EventManager is ExecutionHelper { - EventEmitter internal EVENT; - - constructor() { - EVENT = new EventEmitter(); - } - - function _emitModuleInstall(uint256 moduleTypeId, address module) internal { - _executeDelegateCallMemory({ - safe: msg.sender, - target: address(EVENT), - callData: abi.encodeCall(EventEmitter.emitModuleInstalled, (moduleTypeId, module)) - }); - } - - function _emitModuleUninstall(uint256 moduleTypeId, address module) internal { - _executeDelegateCallMemory({ - safe: msg.sender, - target: address(EVENT), - callData: abi.encodeCall(EventEmitter.emitModuleUninstalled, (moduleTypeId, module)) - }); - } -} diff --git a/accounts/safe7579/src/core/ExecutionHelper.sol b/accounts/safe7579/src/core/ExecutionHelper.sol.bak similarity index 100% rename from accounts/safe7579/src/core/ExecutionHelper.sol rename to accounts/safe7579/src/core/ExecutionHelper.sol.bak diff --git a/accounts/safe7579/src/core/HookManager.sol b/accounts/safe7579/src/core/HookManager.sol index 6b69c228..6d8df33a 100644 --- a/accounts/safe7579/src/core/HookManager.sol +++ b/accounts/safe7579/src/core/HookManager.sol @@ -4,51 +4,49 @@ pragma solidity ^0.8.23; import { ModuleManager } from "./ModuleManager.sol"; import { IHook, IModule } from "erc7579/interfaces/IERC7579Module.sol"; import { MODULE_TYPE_HOOK } from "erc7579/interfaces/IERC7579Module.sol"; +import { ISafe, ExecOnSafeLib } from "../lib/ExecOnSafeLib.sol"; /** * @title reference implementation of HookManager * @author zeroknots.eth | rhinestone.wtf */ abstract contract HookManager is ModuleManager { + using ExecOnSafeLib for ISafe; + 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 _preHook(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.value, msg.data)) + // }), + // (bytes) + // ); + // } + // + // function _postHook( + // address hook, + // bool executionSuccess, + // bytes memory executionReturnValue, + // bytes memory hookPreContext + // ) + // internal + // { + // _execute({ + // safe: msg.sender, + // target: hook, + // value: 0, + // callData: abi.encodeCall( + // IHook.postCheck, (hookPreContext, executionSuccess, executionReturnValue) + // ) + // }); + // } function _installHook( address hook, @@ -63,8 +61,7 @@ abstract contract HookManager is ModuleManager { revert HookAlreadyInstalled(currentHook); } $hookManager[msg.sender] = hook; - _execute({ - safe: msg.sender, + ISafe(msg.sender).exec({ target: hook, value: 0, callData: abi.encodeCall(IModule.onInstall, (data)) @@ -74,8 +71,7 @@ abstract contract HookManager is ModuleManager { function _uninstallHook(address hook, bytes calldata data) internal virtual { $hookManager[msg.sender] = address(0); - _execute({ - safe: msg.sender, + ISafe(msg.sender).exec({ target: hook, value: 0, callData: abi.encodeCall(IModule.onUninstall, (data)) @@ -87,7 +83,7 @@ abstract contract HookManager is ModuleManager { return $hookManager[msg.sender] == module; } - function getActiveHook() external view returns (address hook) { + function getActiveHook() public view returns (address hook) { return $hookManager[msg.sender]; } } diff --git a/accounts/safe7579/src/core/Initializer.sol b/accounts/safe7579/src/core/Initializer.sol index 07dfea30..c2963e29 100644 --- a/accounts/safe7579/src/core/Initializer.sol +++ b/accounts/safe7579/src/core/Initializer.sol @@ -28,6 +28,7 @@ abstract contract Initializer is ISafe7579Init, HookManager { * ModuleInstalled events. this has to be done by the launchpad */ function launchpadValidators(ModuleInit[] calldata validators) external payable override { + // this will revert if already initialized $validators.init({ account: msg.sender }); uint256 length = validators.length; for (uint256 i; i < length; i++) { diff --git a/accounts/safe7579/src/core/ModuleManager.sol b/accounts/safe7579/src/core/ModuleManager.sol index 05379e35..7d4ee730 100644 --- a/accounts/safe7579/src/core/ModuleManager.sol +++ b/accounts/safe7579/src/core/ModuleManager.sol @@ -4,11 +4,14 @@ 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 { ISafe, ExecOnSafeLib } from "../lib/ExecOnSafeLib.sol"; +import { SimulateTxAccessor } from "../utils/DelegatecallTarget.sol"; + +import { Enum } from "@safe-global/safe-contracts/contracts/common/Enum.sol"; import { RegistryAdapter } from "./RegistryAdapter.sol"; import { Receiver } from "erc7579/core/Receiver.sol"; -import { EventManager } from "./EventManager.sol"; import { AccessControl } from "./AccessControl.sol"; +import { DelegateCallUtil } from "./DCUtil.sol"; import { CallType, CALLTYPE_SINGLE, CALLTYPE_DELEGATECALL } from "erc7579/lib/ModeLib.sol"; import { @@ -35,13 +38,8 @@ struct ModuleManagerStorage { * Contract that implements ERC7579 Module compatibility for Safe accounts * @author zeroknots.eth | rhinestone.wtf */ -abstract contract ModuleManager is - AccessControl, - Receiver, - ExecutionHelper, - RegistryAdapter, - EventManager -{ +abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter, DelegateCallUtil { + using ExecOnSafeLib for *; using SentinelListLib for SentinelListLib.SentinelList; using SentinelList4337Lib for SentinelList4337Lib.SentinelList; @@ -80,8 +78,7 @@ abstract contract ModuleManager is $validators.push({ account: msg.sender, newEntry: validator }); // Initialize Validator Module via Safe - _execute({ - safe: msg.sender, + ISafe(msg.sender).exec({ target: validator, value: 0, callData: abi.encodeCall(IModule.onInstall, (data)) @@ -97,8 +94,7 @@ abstract contract ModuleManager is $validators.pop({ account: msg.sender, prevEntry: prev, popEntry: validator }); // De-Initialize Validator Module via Safe - _execute({ - safe: msg.sender, + ISafe(msg.sender).exec({ target: validator, value: 0, callData: abi.encodeCall(IModule.onUninstall, (disableModuleData)) @@ -153,8 +149,7 @@ abstract contract ModuleManager is SentinelListLib.SentinelList storage $executors = $moduleManager[msg.sender]._executors; $executors.push(executor); // Initialize Executor Module via Safe - _execute({ - safe: msg.sender, + ISafe(msg.sender).exec({ target: executor, value: 0, callData: abi.encodeCall(IModule.onInstall, (data)) @@ -168,8 +163,7 @@ abstract contract ModuleManager is $executors.pop(prev, executor); // De-Initialize Executor Module via Safe - _execute({ - safe: msg.sender, + ISafe(msg.sender).exec({ target: executor, value: 0, callData: abi.encodeCall(IModule.onUninstall, (disableModuleData)) @@ -220,8 +214,7 @@ abstract contract ModuleManager is $fallbacks.calltype = calltype; $fallbacks.handler = handler; - _execute({ - safe: msg.sender, + ISafe(msg.sender).exec({ target: handler, value: 0, callData: abi.encodeCall(IModule.onInstall, (initData)) @@ -240,8 +233,7 @@ abstract contract ModuleManager is ModuleManagerStorage storage $mms = $moduleManager[msg.sender]; $mms._fallbacks[functionSig].handler = address(0); // De-Initialize Fallback Module via Safe - _execute({ - safe: msg.sender, + ISafe(msg.sender).exec({ target: handler, value: 0, callData: abi.encodeCall(IModule.onUninstall, (initData)) @@ -279,17 +271,22 @@ abstract contract ModuleManager is if (handler == address(0)) revert NoFallbackHandler(msg.sig); if (calltype == CALLTYPE_STATIC) { - return _executeStaticReturnData( - msg.sender, handler, 0, abi.encodePacked(callData, _msgSender()) - ); + bytes memory ret = ISafe(msg.sender).execDelegateCallReturn({ + target: address(DCTARGET), + callData: abi.encodeCall( + SimulateTxAccessor.simulate, + (handler, 0, abi.encodePacked(callData, _msgSender()), Enum.Operation.Call) + ) + }); + (,, fallbackRet) = abi.decode(ret, (uint256, bool, bytes)); + return fallbackRet; } if (calltype == CALLTYPE_SINGLE) { - return - _executeReturnData(msg.sender, handler, 0, abi.encodePacked(callData, _msgSender())); - } - // TODO: do we actually want this? security questionable... - if (calltype == CALLTYPE_DELEGATECALL) { - return _executeDelegateCallReturnData(msg.sender, handler, callData); + return ISafe(msg.sender).execReturn({ + target: handler, + value: 0, + callData: abi.encodePacked(callData, _msgSender()) + }); } } } diff --git a/accounts/safe7579/src/core/RegistryAdapter.sol b/accounts/safe7579/src/core/RegistryAdapter.sol index e6e9b961..f9ab084c 100644 --- a/accounts/safe7579/src/core/RegistryAdapter.sol +++ b/accounts/safe7579/src/core/RegistryAdapter.sol @@ -2,9 +2,11 @@ pragma solidity ^0.8.23; import { IERC7484 } from "../interfaces/IERC7484.sol"; -import { ExecutionHelper } from "./ExecutionHelper.sol"; +import { ISafe, ExecOnSafeLib } from "../lib/ExecOnSafeLib.sol"; + +abstract contract RegistryAdapter { + using ExecOnSafeLib for *; -abstract contract RegistryAdapter is ExecutionHelper { event ERC7484RegistryConfigured(address indexed smartAccount, address indexed registry); mapping(address smartAccount => IERC7484 registry) internal $registry; @@ -25,11 +27,10 @@ abstract contract RegistryAdapter is ExecutionHelper { internal { $registry[msg.sender] = registry; - _execute( - msg.sender, - address(registry), - 0, - abi.encodeCall(IERC7484.trustAttesters, (threshold, attesters)) - ); + ISafe(msg.sender).exec({ + target: address(registry), + value: 0, + callData: abi.encodeCall(IERC7484.trustAttesters, (threshold, attesters)) + }); } } diff --git a/accounts/safe7579/src/lib/ExecOnSafeLib.sol b/accounts/safe7579/src/lib/ExecOnSafeLib.sol new file mode 100644 index 00000000..10f285b5 --- /dev/null +++ b/accounts/safe7579/src/lib/ExecOnSafeLib.sol @@ -0,0 +1,310 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import { Execution } from "erc7579/interfaces/IERC7579Account.sol"; +import { ExecutionLib } from "erc7579/lib/ExecutionLib.sol"; +import { ISafe } from "../interfaces/ISafe.sol"; + +import { + CallType, + CALLTYPE_SINGLE, + CALLTYPE_BATCH, + CALLTYPE_DELEGATECALL +} from "erc7579/lib/ModeLib.sol"; + +error ExecutionFailed(); + +event TryExecutionFailed(ISafe safe, uint256 numberInBatch); + +error UnsupportedCallType(CallType calltype); + +library ExecOnSafeLib { + function exec(ISafe safe, address target, uint256 value, bytes memory callData) internal { + bool success = safe.execTransactionFromModule(target, value, callData, 0); + if (!success) revert ExecutionFailed(); + } + + function exec(ISafe safe, Execution[] calldata executions) internal { + uint256 length = executions.length; + for (uint256 i; i < length; i++) { + Execution calldata execution = executions[i]; + exec({ + safe: safe, + target: execution.target, + value: execution.value, + callData: execution.callData + }); + } + } + + function execDelegateCall(ISafe safe, address target, bytes memory callData) internal { + bool success = safe.execTransactionFromModule(target, 0, callData, 1); + if (!success) revert ExecutionFailed(); + } + + function execReturn( + ISafe safe, + address target, + uint256 value, + bytes memory callData + ) + internal + returns (bytes memory returnData) + { + bool success; + (success, returnData) = safe.execTransactionFromModuleReturnData(target, value, callData, 0); + if (!success) revert ExecutionFailed(); + } + + function execReturn( + ISafe 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] = execReturn({ + safe: safe, + target: execution.target, + value: execution.value, + callData: execution.callData + }); + } + } + + function execDelegateCallReturn( + ISafe safe, + address target, + bytes memory callData + ) + internal + returns (bytes memory returnData) + { + bool success; + (success, returnData) = safe.execTransactionFromModuleReturnData(target, 0, callData, 1); + if (!success) revert ExecutionFailed(); + } +} + +library TryExecOnSafeLib { + /** + * Try 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 tryExec(ISafe safe, address target, uint256 value, bytes memory callData) internal { + bool success = safe.execTransactionFromModule(target, value, callData, 0); + if (!success) emit TryExecutionFailed(safe, 0); + } + + /** + * Try 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 success boolean if the call was successful + * @return returnData data returned from the call + */ + function tryExecReturn( + ISafe safe, + address target, + uint256 value, + bytes memory callData + ) + internal + returns (bool success, bytes memory returnData) + { + (success, returnData) = safe.execTransactionFromModuleReturnData(target, value, callData, 0); + if (!success) emit TryExecutionFailed(safe, 0); + } + + /** + * Try 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 tryExec(ISafe safe, Execution[] calldata executions) internal returns (bool success) { + uint256 length = executions.length; + success = true; + for (uint256 i; i < length; i++) { + Execution calldata execution = executions[i]; + + bool _success = safe.execTransactionFromModule( + execution.target, execution.value, execution.callData, 0 + ); + if (_success == false) { + emit TryExecutionFailed(safe, i); + if (success == true) success = false; + } + } + } + + function tryExecDelegateCall(ISafe safe, address target, bytes calldata callData) internal { + bool success = safe.execTransactionFromModule(target, 0, callData, 1); + if (!success) emit TryExecutionFailed(safe, 0); + } + + function tryExecDelegateCallReturn( + ISafe safe, + address target, + bytes calldata callData + ) + internal + returns (bool success, bytes memory returnData) + { + (success, returnData) = safe.execTransactionFromModuleReturnData(target, 0, callData, 1); + if (!success) emit TryExecutionFailed(safe, 0); + } + + /** + * 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 success boolean if the call was successful + * @return returnDatas array returned datas from the batched calls + */ + function tryExecReturn( + ISafe safe, + Execution[] calldata executions + ) + internal + returns (bool success, bytes[] memory returnDatas) + { + uint256 length = executions.length; + returnDatas = new bytes[](length); + for (uint256 i; i < length; i++) { + Execution calldata execution = executions[i]; + + bool _success = safe.execTransactionFromModule( + execution.target, execution.value, execution.callData, 0 + ); + if (_success == false) { + emit TryExecutionFailed(safe, i); + if (success == true) success = false; + } + } + } +} + +import { IHook } from "erc7579/interfaces/IERC7579Module.sol"; + +library HookedExecOnSafeLib { + using ExecOnSafeLib for ISafe; + using TryExecOnSafeLib for ISafe; + using ExecutionLib for bytes; + + function preHook(ISafe safe, address withHook) private returns (bytes memory hookPreContext) { + hookPreContext = abi.decode( + safe.execReturn({ + target: withHook, + value: 0, + callData: abi.encodeCall(IHook.preCheck, (msg.sender, msg.value, msg.data)) + }), + (bytes) + ); + } + + function postHook( + ISafe safe, + address withHook, + bytes memory hookPreContext, + bool excutionSuccess, + bytes memory executionReturnValue + ) + private + { + safe.execReturn({ + target: withHook, + value: 0, + callData: abi.encodeCall( + IHook.postCheck, (hookPreContext, excutionSuccess, executionReturnValue) + ) + }); + } + + function hookedExec( + bytes calldata executionCalldata, + CallType callType, + address hook + ) + internal + returns (bytes[] memory retDatas) + { + ISafe safe = ISafe(msg.sender); + bool hookEnabled = hook != address(0); + bytes memory preHookContext; + if (hookEnabled) preHookContext = preHook(safe, hook); + + if (callType == CALLTYPE_BATCH) { + Execution[] calldata executions = executionCalldata.decodeBatch(); + retDatas = safe.execReturn(executions); + } else if (callType == CALLTYPE_SINGLE) { + (address target, uint256 value, bytes calldata callData) = + executionCalldata.decodeSingle(); + retDatas = new bytes[](1); + retDatas[0] = safe.execReturn(target, value, callData); + } else if (callType == CALLTYPE_DELEGATECALL) { + address target = address(bytes20(executionCalldata[:20])); + bytes calldata callData = executionCalldata[20:]; + retDatas = new bytes[](1); + retDatas[0] = safe.execDelegateCallReturn(target, callData); + } else { + revert UnsupportedCallType(callType); + } + if (hookEnabled) postHook(safe, hook, preHookContext, true, abi.encode(retDatas)); + } + + function hookedTryExec( + bytes calldata executionCalldata, + CallType callType, + address hook + ) + internal + returns (bytes[] memory retDatas) + { + bool success; + bool hookEnabled = hook != address(0); + ISafe safe = ISafe(msg.sender); + bytes memory preHookContext; + if (hookEnabled) preHookContext = preHook(safe, hook); + + if (callType == CALLTYPE_BATCH) { + Execution[] calldata executions = executionCalldata.decodeBatch(); + (success, retDatas) = safe.tryExecReturn(executions); + } else if (callType == CALLTYPE_SINGLE) { + (address target, uint256 value, bytes calldata callData) = + executionCalldata.decodeSingle(); + retDatas = new bytes[](1); + (success, retDatas[0]) = safe.tryExecReturn(target, value, callData); + } else if (callType == CALLTYPE_DELEGATECALL) { + address target = address(bytes20(executionCalldata[:20])); + bytes calldata callData = executionCalldata[20:]; + retDatas = new bytes[](1); + (success, retDatas[0]) = safe.tryExecDelegateCallReturn(target, callData); + } else { + revert UnsupportedCallType(callType); + } + if (hookEnabled) postHook(safe, hook, preHookContext, true, abi.encode(retDatas)); + } +} + +function _msgSender() pure returns (address sender) { + // The assembly code is more direct than the Solidity version using `abi.decode`. + /* solhint-disable no-inline-assembly */ + /// @solidity memory-safe-assembly + assembly { + sender := shr(96, calldataload(sub(calldatasize(), 20))) + } + /* solhint-enable no-inline-assembly */ +} diff --git a/accounts/safe7579/src/utils/DelegatecallTarget.sol b/accounts/safe7579/src/utils/DelegatecallTarget.sol new file mode 100644 index 00000000..8bc62148 --- /dev/null +++ b/accounts/safe7579/src/utils/DelegatecallTarget.sol @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import { Execution } from "erc7579/interfaces/IERC7579Account.sol"; +import { SimulateTxAccessor } from + "@safe-global/safe-contracts/contracts/accessors/SimulateTxAccessor.sol"; + +contract EventEmitter { + event ModuleInstalled(uint256 moduleTypeId, address module); + event ModuleUninstalled(uint256 moduleTypeId, address module); + + function emitModuleInstalled(uint256 moduleTypeId, address module) external { + emit ModuleInstalled(moduleTypeId, module); + } + + function emitModuleUninstalled(uint256 moduleTypeId, address module) external { + emit ModuleUninstalled(moduleTypeId, module); + } +} + +contract ExecMultiCall { + function execute(Execution[] calldata executions) external returns (bytes[] memory result) { + uint256 length = executions.length; + result = new bytes[](length); + + for (uint256 i; i < length; i++) { + Execution calldata _exec = executions[i]; + result[i] = _execute(_exec.target, _exec.value, _exec.callData); + } + } + + function _execute( + address target, + uint256 value, + bytes calldata callData + ) + internal + virtual + returns (bytes memory result) + { + /// @solidity memory-safe-assembly + assembly { + result := mload(0x40) + calldatacopy(result, callData.offset, callData.length) + if iszero(call(gas(), target, value, result, callData.length, codesize(), 0x00)) { + // Bubble up the revert if the call reverts. + returndatacopy(result, 0x00, returndatasize()) + revert(result, returndatasize()) + } + mstore(result, returndatasize()) // Store the length. + let o := add(result, 0x20) + returndatacopy(o, 0x00, returndatasize()) // Copy the returndata. + mstore(0x40, add(o, returndatasize())) // Allocate the memory. + } + } + + function _tryExecute( + address target, + uint256 value, + bytes calldata callData + ) + internal + virtual + returns (bool success, bytes memory result) + { + /// @solidity memory-safe-assembly + assembly { + result := mload(0x40) + calldatacopy(result, callData.offset, callData.length) + success := iszero(call(gas(), target, value, result, callData.length, codesize(), 0x00)) + mstore(result, returndatasize()) // Store the length. + let o := add(result, 0x20) + returndatacopy(o, 0x00, returndatasize()) // Copy the returndata. + mstore(0x40, add(o, returndatasize())) // Allocate the memory. + } + } +} + +contract DelegateCallTarget is EventEmitter, ExecMultiCall, SimulateTxAccessor { } diff --git a/accounts/safe7579/test/SafeERC7579.t.sol b/accounts/safe7579/test/SafeERC7579.t.sol index 28f44995..07123c27 100644 --- a/accounts/safe7579/test/SafeERC7579.t.sol +++ b/accounts/safe7579/test/SafeERC7579.t.sol @@ -125,16 +125,16 @@ contract Safe7579Test is LaunchpadBase { assertEq(msgSender, address(safe)); assertEq(context, address(this)); - vm.prank(address(safe)); - IERC7579Account(address(safe)).installModule( - 3, - address(_fallback), - abi.encode(MockFallback.target2.selector, CALLTYPE_DELEGATECALL, "") - ); - (uint256 _ret, address _this, address _msgSender) = - MockFallback(address(safe)).target2(1337); - - assertEq(_ret, 1337); - assertEq(_this, address(safe)); + // vm.prank(address(safe)); + // IERC7579Account(address(safe)).installModule( + // 3, + // address(_fallback), + // abi.encode(MockFallback.target2.selector, CALLTYPE_DELEGATECALL, "") + // ); + // (uint256 _ret, address _this, address _msgSender) = + // MockFallback(address(safe)).target2(1337); + // + // assertEq(_ret, 1337); + // assertEq(_this, address(safe)); } } diff --git a/packages/modulekit/src/modules/ERC7579HookDestruct.sol b/packages/modulekit/src/modules/ERC7579HookDestruct.sol index f50df6a6..4709bce2 100644 --- a/packages/modulekit/src/modules/ERC7579HookDestruct.sol +++ b/packages/modulekit/src/modules/ERC7579HookDestruct.sol @@ -25,6 +25,7 @@ abstract contract ERC7579HookDestruct is ERC7579HookBase { function preCheck( address msgSender, + uint256 msgValue, bytes calldata msgData ) external @@ -147,9 +148,16 @@ abstract contract ERC7579HookDestruct is ERC7579HookBase { // revert HookInvalidSelector(); // } - function postCheck(bytes calldata hookData) external override returns (bool success) { - if (hookData.length == 0) return true; - return onPostCheck(hookData); + function postCheck( + bytes calldata hookData, + bool executionSuccessful, + bytes calldata executionData + ) + external + override + { + if (hookData.length == 0) return; + onPostCheck(hookData); } /*////////////////////////////////////////////////////////////////////////// diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3f45b6d0..7f1da249 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -22,13 +22,13 @@ importers: version: 2.8.8 solhint: specifier: ^4.1.1 - version: 4.1.1(typescript@5.4.4) + version: 4.1.1(typescript@5.4.5) 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.22.2)(lodash@4.17.21)(typechain@5.2.0) + version: github.com/kopy-kat/account-abstraction/c5887153fbfe3ed09b2637cac39873f96d676f38(ethers@5.4.0)(hardhat@2.22.2)(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.22.2)(lodash@4.17.21)(typechain@5.2.0) @@ -52,28 +52,28 @@ importers: version: github.com/dapphub/ds-test/e282159d5170298eb2455a6c05280ab5a73a4ef0 erc4337-validation: specifier: github:rhinestonewtf/erc4337-validation - version: github.com/rhinestonewtf/erc4337-validation/19a97d86f8f29709664334078925b2a843be19e0 + version: github.com/rhinestonewtf/erc4337-validation/abaff656852e3a4b9790e458e17165adf00e3e54 erc7579: specifier: github:erc7579/erc7579-implementation - version: github.com/erc7579/erc7579-implementation/c28f305d96467200c44c1ee3af2a7bb184dc0420 + version: github.com/erc7579/erc7579-implementation/bb2d4ba2980daa79868c2532dc209bd6104356ca forge-std: specifier: github:foundry-rs/forge-std - version: github.com/foundry-rs/forge-std/1d0766bc5d814f117c7b1e643828f7d85024fb51 + version: github.com/foundry-rs/forge-std/e4aef94c1768803a16fe19f7ce8b65defd027cfd prettier: specifier: ^2.8.8 version: 2.8.8 sentinellist: specifier: github:zeroknots/sentinellist - version: github.com/zeroknots/sentinellist/6294bf412489c0f6d3b9c92ad0aceb08c5b8704b + version: github.com/zeroknots/sentinellist/05e0cf2a22279cf66a62cdc8a006df830348aa0e solady: specifier: github:vectorized/solady - version: github.com/vectorized/solady/72e47ca417d24a30801b2921584e8486462cfc7b + version: github.com/vectorized/solady/5d9817ee8665dbace6cc01ddf5f7b605cf06eb6b solarray: specifier: github:sablier-labs/solarray version: github.com/sablier-labs/solarray/6bf10cb34cdace52a3ba5fe437e78cc82df92684 solhint: - specifier: ^4.1.1 - version: 4.1.1(typescript@5.4.4) + specifier: ^4.5.4 + version: 4.5.4(typescript@5.4.5) solmate: specifier: github:transmissions11/solmate version: github.com/transmissions11/solmate/c892309933b25c03d32b1b0d674df7ae292ba925 @@ -130,7 +130,7 @@ importers: version: github.com/sablier-labs/solarray/6bf10cb34cdace52a3ba5fe437e78cc82df92684 solhint: specifier: ^4.1.1 - version: 4.1.1(typescript@5.4.4) + version: 4.1.1(typescript@5.4.5) solmate: specifier: github:transmissions11/solmate version: github.com/transmissions11/solmate/c892309933b25c03d32b1b0d674df7ae292ba925 @@ -166,7 +166,7 @@ importers: version: github.com/vectorized/solady/72e47ca417d24a30801b2921584e8486462cfc7b solhint: specifier: ^4.1.1 - version: 4.1.1(typescript@5.4.4) + version: 4.1.1(typescript@5.4.5) packages/modulekit: devDependencies: @@ -217,7 +217,7 @@ importers: version: github.com/sablier-labs/solarray/6bf10cb34cdace52a3ba5fe437e78cc82df92684 solhint: specifier: ^4.1.1 - version: 4.1.1(typescript@5.4.4) + version: 4.1.1(typescript@5.4.5) packages: @@ -261,15 +261,15 @@ packages: /@ethersproject/abi@5.4.0: resolution: {integrity: sha512-9gU2H+/yK1j2eVMdzm6xvHSnMxk8waIHQGYCZg5uvAyH0rsAzxkModzBSpbAkAuhKFEovC2S9hM4nPuLym8IZw==} 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 + '@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: @@ -289,13 +289,13 @@ packages: /@ethersproject/abstract-provider@5.4.0: resolution: {integrity: sha512-vPBR7HKUBY0lpdllIn7tLIzNN7DrVnhCLKSzY0l8WAwxz686m/aL7ASDzrVxV93GJtIub6N2t4dfZ29CkPOxgA==} 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 + '@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: @@ -313,11 +313,11 @@ packages: /@ethersproject/abstract-signer@5.4.0: resolution: {integrity: sha512-AieQAzt05HJZS2bMofpuxMEp81AHufA5D6M4ScKwtolj041nrfIbIi8ciNW7+F59VYxXq+V4c3d568Q6l2m8ew==} 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 + '@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: @@ -333,11 +333,11 @@ packages: /@ethersproject/address@5.4.0: resolution: {integrity: sha512-SD0VgOEkcACEG/C6xavlU1Hy3m5DGSXW3CUHkaaEHbAPPsgi0coP5oNPsxau8eTlZOk/bpa/hKeCNoK5IzVI2Q==} 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 + '@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: @@ -353,7 +353,7 @@ packages: /@ethersproject/base64@5.4.0: resolution: {integrity: sha512-CjQw6E17QDSSC5jiM9YpF7N1aSCHmYGMt9bWD8PWv6YPMxjsys2/Q8xLrROKI3IWJ7sFfZ8B3flKDTM5wlWuZQ==} dependencies: - '@ethersproject/bytes': 5.7.0 + '@ethersproject/bytes': 5.4.0 dev: true /@ethersproject/base64@5.7.0: @@ -365,8 +365,8 @@ packages: /@ethersproject/basex@5.4.0: resolution: {integrity: sha512-J07+QCVJ7np2bcpxydFVf/CuYo9mZ7T73Pe7KQY4c1lRlrixMeblauMxHXD0MPwFmUHZIILDNViVkykFBZylbg==} dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/properties': 5.7.0 + '@ethersproject/bytes': 5.4.0 + '@ethersproject/properties': 5.4.0 dev: true /@ethersproject/basex@5.7.0: @@ -379,8 +379,8 @@ packages: /@ethersproject/bignumber@5.4.0: resolution: {integrity: sha512-OXUu9f9hO3vGRIPxU40cignXZVaYyfx6j9NNMjebKdnaCL3anCLSSy8/b8d03vY6dh7duCC0kW72GEC4tZer2w==} dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.7.0 + '@ethersproject/bytes': 5.4.0 + '@ethersproject/logger': 5.4.0 bn.js: 4.12.0 dev: true @@ -395,7 +395,7 @@ packages: /@ethersproject/bytes@5.4.0: resolution: {integrity: sha512-H60ceqgTHbhzOj4uRc/83SCN9d+BSUnOkrr2intevqdtEMO1JFVZ1XL84OEZV+QjV36OaZYxtnt4lGmxcGsPfA==} dependencies: - '@ethersproject/logger': 5.7.0 + '@ethersproject/logger': 5.4.0 dev: true /@ethersproject/bytes@5.7.0: @@ -407,7 +407,7 @@ packages: /@ethersproject/constants@5.4.0: resolution: {integrity: sha512-tzjn6S7sj9+DIIeKTJLjK9WGN2Tj0P++Z8ONEIlZjyoTkBuODN+0VfhAyYksKi43l1Sx9tX2VlFfzjfmr5Wl3Q==} dependencies: - '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bignumber': 5.4.0 dev: true /@ethersproject/constants@5.7.0: @@ -419,16 +419,16 @@ packages: /@ethersproject/contracts@5.4.0: resolution: {integrity: sha512-hkO3L3IhS1Z3ZtHtaAG/T87nQ7KiPV+/qnvutag35I0IkiQ8G3ZpCQ9NNOpSCzn4pWSW4CfzmtE02FcqnLI+hw==} 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 + '@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: @@ -449,14 +449,14 @@ packages: /@ethersproject/hash@5.4.0: resolution: {integrity: sha512-xymAM9tmikKgbktOCjW60Z5sdouiIIurkZUr9oW5NOex5uwxrbsYG09kb5bMcNjlVeJD3yPivTNzViIs1GCbqA==} dependencies: - '@ethersproject/abstract-signer': 5.7.0 - '@ethersproject/address': 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 + '@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: @@ -476,18 +476,18 @@ packages: /@ethersproject/hdnode@5.4.0: resolution: {integrity: sha512-pKxdS0KAaeVGfZPp1KOiDLB0jba11tG6OP1u11QnYfb7pXn6IZx0xceqWRr6ygke8+Kw74IpOoSi7/DwANhy8Q==} 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 + '@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: @@ -510,17 +510,17 @@ packages: /@ethersproject/json-wallets@5.4.0: resolution: {integrity: sha512-igWcu3fx4aiczrzEHwG1xJZo9l1cFfQOWzTqwRw/xcvxTk58q4f9M7cjh51EKphMHvrJtcezJ1gf1q1AUOfEQQ==} 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 + '@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 @@ -546,7 +546,7 @@ packages: /@ethersproject/keccak256@5.4.0: resolution: {integrity: sha512-FBI1plWet+dPUvAzPAeHzRKiPpETQzqSUWR1wXJGHVWi4i8bOSrpC3NwpkPjgeXG7MnugVc1B42VbfnQikyC/A==} dependencies: - '@ethersproject/bytes': 5.7.0 + '@ethersproject/bytes': 5.4.0 js-sha3: 0.5.7 dev: true @@ -568,7 +568,7 @@ packages: /@ethersproject/networks@5.4.0: resolution: {integrity: sha512-5fywtKRDcnaVeA5SjxXH3DOQqe/IbeD/plwydi94SdPps1fbDUrnO6SzDExaruBZXxpxJcO9upG9UComsei4bg==} dependencies: - '@ethersproject/logger': 5.7.0 + '@ethersproject/logger': 5.4.0 dev: true /@ethersproject/networks@5.7.1: @@ -580,8 +580,8 @@ packages: /@ethersproject/pbkdf2@5.4.0: resolution: {integrity: sha512-x94aIv6tiA04g6BnazZSLoRXqyusawRyZWlUhKip2jvoLpzJuLb//KtMM6PEovE47pMbW+Qe1uw+68ameJjB7g==} dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/sha2': 5.7.0 + '@ethersproject/bytes': 5.4.0 + '@ethersproject/sha2': 5.4.0 dev: true /@ethersproject/pbkdf2@5.7.0: @@ -594,7 +594,7 @@ packages: /@ethersproject/properties@5.4.0: resolution: {integrity: sha512-7jczalGVRAJ+XSRvNA6D5sAwT4gavLq3OXPuV/74o3Rd2wuzSL035IMpIMgei4CYyBdialJMrTqkOnzccLHn4A==} dependencies: - '@ethersproject/logger': 5.7.0 + '@ethersproject/logger': 5.4.0 dev: true /@ethersproject/properties@5.7.0: @@ -606,23 +606,23 @@ packages: /@ethersproject/providers@5.4.0: resolution: {integrity: sha512-XRmI9syLnkNdLA8ikEeg0duxmwSWTTt9S+xabnTOyI51JPJyhQ0QUNT+wvmod218ebb7rLupHDPQ7UVe2/+Tjg==} dependencies: - '@ethersproject/abstract-provider': 5.7.0 - '@ethersproject/abstract-signer': 5.7.0 - '@ethersproject/address': 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 + '@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: @@ -661,8 +661,8 @@ packages: /@ethersproject/random@5.4.0: resolution: {integrity: sha512-pnpWNQlf0VAZDEOVp1rsYQosmv2o0ITS/PecNw+mS2/btF8eYdspkN0vIXrCMtkX09EAh9bdk8GoXmFXM1eAKw==} dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.7.0 + '@ethersproject/bytes': 5.4.0 + '@ethersproject/logger': 5.4.0 dev: true /@ethersproject/random@5.7.0: @@ -675,8 +675,8 @@ packages: /@ethersproject/rlp@5.4.0: resolution: {integrity: sha512-0I7MZKfi+T5+G8atId9QaQKHRvvasM/kqLyAH4XxBCBchAooH2EX5rL9kYZWwcm3awYV+XC7VF6nLhfeQFKVPg==} dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.7.0 + '@ethersproject/bytes': 5.4.0 + '@ethersproject/logger': 5.4.0 dev: true /@ethersproject/rlp@5.7.0: @@ -689,8 +689,8 @@ packages: /@ethersproject/sha2@5.4.0: resolution: {integrity: sha512-siheo36r1WD7Cy+bDdE1BJ8y0bDtqXCOxRMzPa4bV1TGt/eTUUt03BHoJNB6reWJD8A30E/pdJ8WFkq+/uz4Gg==} dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.7.0 + '@ethersproject/bytes': 5.4.0 + '@ethersproject/logger': 5.4.0 hash.js: 1.1.7 dev: true @@ -705,9 +705,9 @@ packages: /@ethersproject/signing-key@5.4.0: resolution: {integrity: sha512-q8POUeywx6AKg2/jX9qBYZIAmKSB4ubGXdQ88l40hmATj29JnG5pp331nAWwwxPn2Qao4JpWHNZsQN+bPiSW9A==} dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/properties': 5.7.0 + '@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 @@ -727,11 +727,11 @@ packages: /@ethersproject/solidity@5.4.0: resolution: {integrity: sha512-XFQTZ7wFSHOhHcV1DpcWj7VXECEiSrBuv7JErJvB9Uo+KfCdc3QtUZV+Vjh/AAaYgezUEKbCtE6Khjm44seevQ==} dependencies: - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/keccak256': 5.7.0 - '@ethersproject/sha2': 5.7.0 - '@ethersproject/strings': 5.7.0 + '@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: @@ -748,9 +748,9 @@ packages: /@ethersproject/strings@5.4.0: resolution: {integrity: sha512-k/9DkH5UGDhv7aReXLluFG5ExurwtIpUfnDNhQA29w896Dw3i4uDTz01Quaptbks1Uj9kI8wo9tmW73wcIEaWA==} dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/constants': 5.7.0 - '@ethersproject/logger': 5.7.0 + '@ethersproject/bytes': 5.4.0 + '@ethersproject/constants': 5.4.0 + '@ethersproject/logger': 5.4.0 dev: true /@ethersproject/strings@5.7.0: @@ -764,15 +764,15 @@ packages: /@ethersproject/transactions@5.4.0: resolution: {integrity: sha512-s3EjZZt7xa4BkLknJZ98QGoIza94rVjaEed0rzZ/jB9WrIuu/1+tjvYCWzVrystXtDswy7TPBeIepyXwSYa4WQ==} 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 + '@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: @@ -792,9 +792,9 @@ packages: /@ethersproject/units@5.4.0: resolution: {integrity: sha512-Z88krX40KCp+JqPCP5oPv5p750g+uU6gopDYRTBGcDvOASh6qhiEYCRatuM/suC4S2XW9Zz90QI35MfSrTIaFg==} dependencies: - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/constants': 5.7.0 - '@ethersproject/logger': 5.7.0 + '@ethersproject/bignumber': 5.4.0 + '@ethersproject/constants': 5.4.0 + '@ethersproject/logger': 5.4.0 dev: true /@ethersproject/units@5.7.0: @@ -808,21 +808,21 @@ packages: /@ethersproject/wallet@5.4.0: resolution: {integrity: sha512-wU29majLjM6AjCjpat21mPPviG+EpK7wY1+jzKD0fg3ui5fgedf2zEu1RDgpfIMsfn8fJHJuzM4zXZ2+hSHaSQ==} 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 + '@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: @@ -848,11 +848,11 @@ packages: /@ethersproject/web@5.4.0: resolution: {integrity: sha512-1bUusGmcoRLYgMn6c1BLk1tOKUIFuTg8j+6N8lYlbMpDesnle+i3pGSagGNvwjaiLo4Y5gBibwctpPRmjrh4Og==} 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 + '@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: @@ -868,11 +868,11 @@ packages: /@ethersproject/wordlists@5.4.0: resolution: {integrity: sha512-FemEkf6a+EBKEPxlzeVgUaVSodU7G0Na89jqKjmWMlDB0tomoU8RlEMgUvXyqtrg8N4cwpLh8nyRnm1Nay1isA==} 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 + '@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: @@ -957,8 +957,8 @@ packages: fastq: 1.17.1 dev: true - /@nomicfoundation/edr-darwin-arm64@0.3.3: - resolution: {integrity: sha512-E9VGsUD+1Ga4mn/5ooHsMi8JEfhZbKP6CXN/BhJ8kXbIC10NqTD1RuhCKGRtYq4vqH/3Nfq25Xg8E8RWOF4KBQ==} + /@nomicfoundation/edr-darwin-arm64@0.3.4: + resolution: {integrity: sha512-tjavrUFLWnkn0PI+jk0D83hP2jjbmeXT1QLd5NtIleyGrJ00ZWVl+sfuA2Lle3kzfOceoI2VTR0n1pZB4KJGbQ==} engines: {node: '>= 18'} cpu: [arm64] os: [darwin] @@ -966,8 +966,8 @@ packages: dev: true optional: true - /@nomicfoundation/edr-darwin-x64@0.3.3: - resolution: {integrity: sha512-vkZXZ1ydPg+Ijb2iyqENA+KCkxGTCUWG5itCSliiA0Li2YE7ujDMGhheEpFp1WVlZadviz0bfk1rZXbCqlirpg==} + /@nomicfoundation/edr-darwin-x64@0.3.4: + resolution: {integrity: sha512-dXO0vlIoBosp8gf5/ah3dESMymjwit0Daef1E4Ew3gZ8q3LAdku0RC+YEQJi9f0I3QNfdgIrBTzibRZUoP+kVA==} engines: {node: '>= 18'} cpu: [x64] os: [darwin] @@ -975,8 +975,8 @@ packages: dev: true optional: true - /@nomicfoundation/edr-linux-arm64-gnu@0.3.3: - resolution: {integrity: sha512-gdIg0Yj1qqS9wVuywc5B/+DqKylfUGB6/CQn/shMqwAfsAVAVpchkhy66PR+REEx7fh/GkNctxLlENXPeLzDiA==} + /@nomicfoundation/edr-linux-arm64-gnu@0.3.4: + resolution: {integrity: sha512-dv38qmFUaqkkeeA9S0JjerqruytTfHav7gbPLpZUAEXPlJGo49R0+HQxd45I0msbm6NAXbkmKEchTLApp1ohaA==} engines: {node: '>= 18'} cpu: [arm64] os: [linux] @@ -984,8 +984,8 @@ packages: dev: true optional: true - /@nomicfoundation/edr-linux-arm64-musl@0.3.3: - resolution: {integrity: sha512-AXZ08MFvhNeBZbOBNmz1SJ/DMrMOE2mHEJtaNnsctlxIunjxfrWww4q+WXB34jbr9iaVYYlPsaWe5sueuw6s3Q==} + /@nomicfoundation/edr-linux-arm64-musl@0.3.4: + resolution: {integrity: sha512-CfEsb6gdCMVIlRSpWYTxoongEKHB60V6alE/y8mkfjIo7tA95wyiuvCtyo3fpiia3wQV7XoMYgIJHObHiKLKtA==} engines: {node: '>= 18'} cpu: [arm64] os: [linux] @@ -993,8 +993,8 @@ packages: dev: true optional: true - /@nomicfoundation/edr-linux-x64-gnu@0.3.3: - resolution: {integrity: sha512-xElOs1U+E6lBLtv1mnJ+E8nr2MxZgKiLo8bZAgBboy9odYtmkDVwhMjtsFKSuZbGxFtsSyGRT4cXw3JAbtUDeA==} + /@nomicfoundation/edr-linux-x64-gnu@0.3.4: + resolution: {integrity: sha512-V0CpJA2lYWulgTR+zP11ftBAEwkpMAAki/AuMu3vd7HoPfjwIDzWDQR5KFU17qFmqAVz0ICRxsxDlvvBZ/PUxA==} engines: {node: '>= 18'} cpu: [x64] os: [linux] @@ -1002,8 +1002,8 @@ packages: dev: true optional: true - /@nomicfoundation/edr-linux-x64-musl@0.3.3: - resolution: {integrity: sha512-2Fe6gwm1RAGQ/PfMYiaSba2OrFp8zzYWh+am9lYObOFjV9D+A1zhIzfy0UC74glPks5eV8eY4pBPrVR042m2Nw==} + /@nomicfoundation/edr-linux-x64-musl@0.3.4: + resolution: {integrity: sha512-0sgTrwZajarukerU/QSb+oRdlQLnJdd7of8OlXq2wtpeTNTqemgCOwY2l2qImbWboMpVrYgcmGbINXNVPCmuJw==} engines: {node: '>= 18'} cpu: [x64] os: [linux] @@ -1011,8 +1011,8 @@ packages: dev: true optional: true - /@nomicfoundation/edr-win32-arm64-msvc@0.3.3: - resolution: {integrity: sha512-8NHyxIsFrl0ufSQ/ErqF2lKIa/gz1gaaa1a2vKkDEqvqCUcPhBTYhA5NHgTPhLETFTnCFr0z+YbctFCyjh4qrA==} + /@nomicfoundation/edr-win32-arm64-msvc@0.3.4: + resolution: {integrity: sha512-bOl3vhMtV0W9ozUMF5AZRBWw1183hhhx+e1YJdDLMaqNkBUFYi2CZbMYefDylq2OKQtOQ0gPLhZvn+z2D21Ztw==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] @@ -1020,8 +1020,8 @@ packages: dev: true optional: true - /@nomicfoundation/edr-win32-ia32-msvc@0.3.3: - resolution: {integrity: sha512-0F6hM0kGia4dQVb/kauho9JcP1ozWisY2/She+ISR5ceuhzmAwQJluM0g+0TYDME0LtxBxiMPq/yPiZMQeq31w==} + /@nomicfoundation/edr-win32-ia32-msvc@0.3.4: + resolution: {integrity: sha512-yKQCpAX0uB2dalsSwOkau3yfNXkwBJa/Ks2OPl9AjHqJ+E8AqvBEB9jRpfQrdPzElMsgZuN4mqE+wh+JxY+0Aw==} engines: {node: '>= 18'} cpu: [ia32] os: [win32] @@ -1029,8 +1029,8 @@ packages: dev: true optional: true - /@nomicfoundation/edr-win32-x64-msvc@0.3.3: - resolution: {integrity: sha512-d75q1uaMb6z9i+GQZoblbOfFBvlBnWc+5rB13UWRkCOJSnoYwyFWhGJx5GeM59gC7aIblc5VD9qOAhHuvM9N+w==} + /@nomicfoundation/edr-win32-x64-msvc@0.3.4: + resolution: {integrity: sha512-fResvsL/fSucep1K5W6iOs8lqqKKovHLsAmigMzAYVovqkyZKgCGVS/D8IVxA0nxuGCOlNxFnVmwWtph3pbKWA==} engines: {node: '>= 18'} cpu: [x64] os: [win32] @@ -1038,19 +1038,19 @@ packages: dev: true optional: true - /@nomicfoundation/edr@0.3.3: - resolution: {integrity: sha512-zP+e+3B1nEUx6bW5BPnIzCQbkhmYfdMBJdiVggTqqTfAA82sOkdOG7wsOMcz5qF3fYfx/irNRM1kgc9HVFIbpQ==} + /@nomicfoundation/edr@0.3.4: + resolution: {integrity: sha512-e4jzVeJ+VTKBFzNgKDbSVnGVbHYNZHIfMdgifQBugXPiIa6QEUzZqleh2+y4lhkXcCthnFyrTYe3jiEpUzr3cA==} engines: {node: '>= 18'} optionalDependencies: - '@nomicfoundation/edr-darwin-arm64': 0.3.3 - '@nomicfoundation/edr-darwin-x64': 0.3.3 - '@nomicfoundation/edr-linux-arm64-gnu': 0.3.3 - '@nomicfoundation/edr-linux-arm64-musl': 0.3.3 - '@nomicfoundation/edr-linux-x64-gnu': 0.3.3 - '@nomicfoundation/edr-linux-x64-musl': 0.3.3 - '@nomicfoundation/edr-win32-arm64-msvc': 0.3.3 - '@nomicfoundation/edr-win32-ia32-msvc': 0.3.3 - '@nomicfoundation/edr-win32-x64-msvc': 0.3.3 + '@nomicfoundation/edr-darwin-arm64': 0.3.4 + '@nomicfoundation/edr-darwin-x64': 0.3.4 + '@nomicfoundation/edr-linux-arm64-gnu': 0.3.4 + '@nomicfoundation/edr-linux-arm64-musl': 0.3.4 + '@nomicfoundation/edr-linux-x64-gnu': 0.3.4 + '@nomicfoundation/edr-linux-x64-musl': 0.3.4 + '@nomicfoundation/edr-win32-arm64-msvc': 0.3.4 + '@nomicfoundation/edr-win32-ia32-msvc': 0.3.4 + '@nomicfoundation/edr-win32-x64-msvc': 0.3.4 dev: true /@nomicfoundation/ethereumjs-common@4.0.4: @@ -1212,7 +1212,7 @@ packages: cbor: 5.2.0 debug: 4.3.4(supports-color@8.1.1) fs-extra: 7.0.1 - hardhat: 2.22.2(typescript@5.4.4) + hardhat: 2.22.2(typescript@5.4.5) node-fetch: 2.7.0 semver: 6.3.1 transitivePeerDependencies: @@ -1220,8 +1220,8 @@ packages: - supports-color dev: true - /@openzeppelin/contracts@4.9.5: - resolution: {integrity: sha512-ZK+W5mVhRppff9BE6YdR8CC52C8zAvsVAiWhEtQ5+oNxFE6h1WdeWo+FJSF8KKvtxxVYZ7MTP/5KoVpAU3aSWg==} + /@openzeppelin/contracts@4.9.6: + resolution: {integrity: sha512-xSmezSupL+y9VkHZJGDoCBpmnB2ogM13ccaYDWqJTfS3dbuHkgjuwDFUmaFauBCboQMGB/S5UqUl2y54X99BmA==} dev: true /@openzeppelin/contracts@5.0.1: @@ -1409,15 +1409,15 @@ packages: typechain: ^5.1.2 dependencies: fs-extra: 9.1.0 - hardhat: 2.22.2(typescript@5.4.4) + hardhat: 2.22.2(typescript@5.4.5) lodash: 4.17.21 - typechain: 5.2.0(typescript@5.4.4) + typechain: 5.2.0(typescript@5.4.5) dev: true /@types/bn.js@4.11.6: resolution: {integrity: sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==} dependencies: - '@types/node': 20.12.5 + '@types/node': 20.12.7 dev: true /@types/bn.js@5.1.5: @@ -1465,8 +1465,8 @@ packages: undici-types: 5.26.5 dev: true - /@types/node@20.12.5: - resolution: {integrity: sha512-BD+BjQ9LS/D8ST9p5uqBxghlN+S42iuNxjsUGjeZobe/ciXzk2qb1B6IXc6AnRLS+yFJRpN2IPEHMzwspfDJNw==} + /@types/node@20.12.7: + resolution: {integrity: sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==} dependencies: undici-types: 5.26.5 dev: true @@ -1481,8 +1481,8 @@ packages: resolution: {integrity: sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==} dev: true - /@types/qs@6.9.11: - resolution: {integrity: sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==} + /@types/qs@6.9.14: + resolution: {integrity: sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA==} dev: true /@types/secp256k1@4.0.6: @@ -1597,6 +1597,11 @@ packages: engines: {node: '>=16'} dev: true + /antlr4@4.13.1-patch-1: + resolution: {integrity: sha512-OjFLWWLzDMV9rdFhpvroCWR4ooktNg9/nvVYSA5z28wuVpU36QUNuioR1XLnQtcjVlf8npjyz593PxnU/f/Cow==} + engines: {node: '>=16'} + dev: true + /antlr4ts@0.5.0-alpha.4: resolution: {integrity: sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==} dev: true @@ -1976,7 +1981,7 @@ packages: engines: {node: '>= 0.6'} dev: true - /cosmiconfig@8.3.6(typescript@5.4.4): + /cosmiconfig@8.3.6(typescript@5.4.5): resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} engines: {node: '>=14'} peerDependencies: @@ -1989,7 +1994,7 @@ packages: js-yaml: 4.1.0 parse-json: 5.2.0 path-type: 4.0.0 - typescript: 5.4.4 + typescript: 5.4.5 dev: true /create-hash@1.2.0: @@ -2731,7 +2736,7 @@ packages: hardhat: ^2.0.0 dependencies: ethers: 5.4.0 - hardhat: 2.22.2(typescript@5.4.4) + hardhat: 2.22.2(typescript@5.4.5) dev: true /hardhat-deploy-ethers@0.3.0-beta.13(ethers@5.7.2)(hardhat@2.22.2): @@ -2741,7 +2746,7 @@ packages: hardhat: ^2.0.0 dependencies: ethers: 5.7.2 - hardhat: 2.22.2(typescript@5.4.4) + hardhat: 2.22.2(typescript@5.4.5) dev: true /hardhat-deploy@0.11.45: @@ -2758,7 +2763,7 @@ packages: '@ethersproject/solidity': 5.7.0 '@ethersproject/transactions': 5.7.0 '@ethersproject/wallet': 5.7.0 - '@types/qs': 6.9.11 + '@types/qs': 6.9.14 axios: 0.21.4(debug@4.3.4) chalk: 4.1.2 chokidar: 3.6.0 @@ -2769,7 +2774,7 @@ packages: fs-extra: 10.1.0 match-all: 1.2.6 murmur-128: 0.2.1 - qs: 6.11.2 + qs: 6.12.0 zksync-web3: 0.14.4(ethers@5.7.2) transitivePeerDependencies: - bufferutil @@ -2777,7 +2782,7 @@ packages: - utf-8-validate dev: true - /hardhat@2.22.2(typescript@5.4.4): + /hardhat@2.22.2(typescript@5.4.5): resolution: {integrity: sha512-0xZ7MdCZ5sJem4MrvpQWLR3R3zGDoHw5lsR+pBFimqwagimIOn3bWuZv69KA+veXClwI1s/zpqgwPwiFrd4Dxw==} hasBin: true peerDependencies: @@ -2791,7 +2796,7 @@ packages: dependencies: '@ethersproject/abi': 5.7.0 '@metamask/eth-sig-util': 4.0.1 - '@nomicfoundation/edr': 0.3.3 + '@nomicfoundation/edr': 0.3.4 '@nomicfoundation/ethereumjs-common': 4.0.4 '@nomicfoundation/ethereumjs-tx': 5.0.4 '@nomicfoundation/ethereumjs-util': 9.0.4 @@ -2829,7 +2834,7 @@ packages: source-map-support: 0.5.21 stacktrace-parser: 0.1.10 tsort: 0.0.1 - typescript: 5.4.4 + typescript: 5.4.5 undici: 5.28.4 uuid: 8.3.2 ws: 7.5.9 @@ -3640,11 +3645,11 @@ packages: engines: {node: '>=6'} dev: true - /qs@6.11.2: - resolution: {integrity: sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==} + /qs@6.12.0: + resolution: {integrity: sha512-trVZiI6RMOkO476zLGaBIzszOdFPnCCXHPG9kn0yuS1uz6xdVxPfZdB3vUig9pxPFDM9BRAgz/YUIVQ1/vuiUg==} engines: {node: '>=0.6'} dependencies: - side-channel: 1.0.5 + side-channel: 1.0.6 dev: true /queue-microtask@1.2.3: @@ -3780,7 +3785,7 @@ packages: resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} hasBin: true dependencies: - glob: 7.2.3 + glob: 7.2.0 dev: true /ripemd160@2.0.2: @@ -3907,8 +3912,8 @@ packages: rechoir: 0.6.2 dev: true - /side-channel@1.0.5: - resolution: {integrity: sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==} + /side-channel@1.0.6: + resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 @@ -3949,7 +3954,7 @@ packages: - debug dev: true - /solhint@4.1.1(typescript@5.4.4): + /solhint@4.1.1(typescript@5.4.5): resolution: {integrity: sha512-7G4iF8H5hKHc0tR+/uyZesSKtfppFIMvPSW+Ku6MSL25oVRuyFeqNhOsXHfkex64wYJyXs4fe+pvhB069I19Tw==} hasBin: true dependencies: @@ -3959,7 +3964,7 @@ packages: ast-parents: 0.0.1 chalk: 4.1.2 commander: 10.0.1 - cosmiconfig: 8.3.6(typescript@5.4.4) + cosmiconfig: 8.3.6(typescript@5.4.5) fast-diff: 1.3.0 glob: 8.1.0 ignore: 5.3.1 @@ -3977,6 +3982,62 @@ packages: - typescript dev: true + /solhint@4.5.4(typescript@5.4.5): + resolution: {integrity: sha512-Cu1XiJXub2q1eCr9kkJ9VPv1sGcmj3V7Zb76B0CoezDOB9bu3DxKIFFH7ggCl9fWpEPD6xBmRLfZrYijkVmujQ==} + hasBin: true + dependencies: + '@solidity-parser/parser': 0.18.0 + ajv: 6.12.6 + antlr4: 4.13.1-patch-1 + ast-parents: 0.0.1 + chalk: 4.1.2 + commander: 10.0.1 + cosmiconfig: 8.3.6(typescript@5.4.5) + 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.6.0 + strip-ansi: 6.0.1 + table: 6.8.2 + text-table: 0.2.0 + optionalDependencies: + prettier: 2.8.8 + transitivePeerDependencies: + - typescript + dev: true + + /solidity-coverage@0.8.12(hardhat@2.22.2): + resolution: {integrity: sha512-8cOB1PtjnjFRqOgwFiD8DaUsYJtVJ6+YdXQtSZDrLGf8cdhhh8xzTtGzVTGeBf15kTv0v7lYPJlV/az7zLEPJw==} + 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 + 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.22.2(typescript@5.4.5) + jsonschema: 1.4.1 + lodash: 4.17.21 + mocha: 10.4.0 + node-emoji: 1.11.0 + pify: 4.0.1 + recursive-readdir: 2.2.3 + sc-istanbul: 0.4.6 + semver: 7.6.0 + shelljs: 0.8.5 + web3-utils: 1.10.4 + dev: true + /solidity-coverage@0.8.8(hardhat@2.22.2): resolution: {integrity: sha512-7RN6/8YAFMQNeMdSulARtE0VC5JitBAUMwvkr10FkOK+nux5q+WykrgSZntkWrX/VHzRa096P4OOViO0T9Q9Cw==} hasBin: true @@ -3992,7 +4053,7 @@ packages: ghost-testrpc: 0.0.2 global-modules: 2.0.0 globby: 10.0.2 - hardhat: 2.22.2(typescript@5.4.4) + hardhat: 2.22.2(typescript@5.4.5) jsonschema: 1.4.1 lodash: 4.17.21 mocha: 10.3.0 @@ -4125,6 +4186,17 @@ packages: strip-ansi: 6.0.1 dev: true + /table@6.8.2: + resolution: {integrity: sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==} + 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'} @@ -4160,12 +4232,12 @@ packages: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} dev: true - /ts-essentials@7.0.3(typescript@5.4.4): + /ts-essentials@7.0.3(typescript@5.4.5): resolution: {integrity: sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==} peerDependencies: typescript: '>=3.7.0' dependencies: - typescript: 5.4.4 + typescript: 5.4.5 dev: true /tslib@1.14.1: @@ -4206,7 +4278,7 @@ packages: engines: {node: '>=8'} dev: true - /typechain@5.2.0(typescript@5.4.4): + /typechain@5.2.0(typescript@5.4.5): resolution: {integrity: sha512-0INirvQ+P+MwJOeMct+WLkUE4zov06QxC96D+i3uGFEHoiSkZN70MKDQsaj8zkL86wQwByJReI2e7fOUwECFuw==} hasBin: true peerDependencies: @@ -4221,8 +4293,8 @@ packages: lodash: 4.17.21 mkdirp: 1.0.4 prettier: 2.8.8 - ts-essentials: 7.0.3(typescript@5.4.4) - typescript: 5.4.4 + ts-essentials: 7.0.3(typescript@5.4.5) + typescript: 5.4.5 transitivePeerDependencies: - supports-color dev: true @@ -4233,8 +4305,8 @@ packages: hasBin: true dev: true - /typescript@5.4.4: - resolution: {integrity: sha512-dGE2Vv8cpVvw28v8HCPqyb08EzbBURxDpuhJvTrusShUfGnhHBafDsLdS1EhhxyL6BJQE+2cT3dDPAv+MQ6oLw==} + /typescript@5.4.5: + resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} engines: {node: '>=14.17'} hasBin: true dev: true @@ -4452,8 +4524,8 @@ packages: '@openzeppelin/contracts': 5.0.1 dev: true - github.com/erc7579/erc7579-implementation/c28f305d96467200c44c1ee3af2a7bb184dc0420: - resolution: {tarball: https://codeload.github.com/erc7579/erc7579-implementation/tar.gz/c28f305d96467200c44c1ee3af2a7bb184dc0420} + github.com/erc7579/erc7579-implementation/bb2d4ba2980daa79868c2532dc209bd6104356ca: + resolution: {tarball: https://codeload.github.com/erc7579/erc7579-implementation/tar.gz/bb2d4ba2980daa79868c2532dc209bd6104356ca} name: micro-msa version: 0.3.1 dependencies: @@ -4468,7 +4540,7 @@ packages: dependencies: '@gnosis.pm/safe-contracts': 1.3.0(ethers@5.4.0) '@nomiclabs/hardhat-etherscan': 2.1.8(hardhat@2.22.2) - '@openzeppelin/contracts': 4.9.5 + '@openzeppelin/contracts': 4.9.6 '@thehubbleproject/bls': 0.5.1 '@typechain/hardhat': 2.3.1(hardhat@2.22.2)(lodash@4.17.21)(typechain@5.2.0) '@types/mocha': 9.1.1 @@ -4476,9 +4548,9 @@ 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.22.2) - solidity-coverage: 0.8.8(hardhat@2.22.2) + solidity-coverage: 0.8.12(hardhat@2.22.2) source-map-support: 0.5.21 - table: 6.8.1 + table: 6.8.2 typescript: 4.9.5 transitivePeerDependencies: - bufferutil @@ -4499,7 +4571,7 @@ packages: dependencies: '@gnosis.pm/safe-contracts': 1.3.0(ethers@5.7.2) '@nomiclabs/hardhat-etherscan': 2.1.8(hardhat@2.22.2) - '@openzeppelin/contracts': 4.9.5 + '@openzeppelin/contracts': 4.9.6 '@thehubbleproject/bls': 0.5.1 '@typechain/hardhat': 2.3.1(hardhat@2.22.2)(lodash@4.17.21)(typechain@5.2.0) '@types/mocha': 9.1.1 @@ -4507,9 +4579,9 @@ packages: ethereumjs-wallet: 1.0.2 hardhat-deploy: 0.11.45 hardhat-deploy-ethers: 0.3.0-beta.13(ethers@5.7.2)(hardhat@2.22.2) - solidity-coverage: 0.8.8(hardhat@2.22.2) + solidity-coverage: 0.8.12(hardhat@2.22.2) source-map-support: 0.5.21 - table: 6.8.1 + table: 6.8.2 typescript: 4.9.5 transitivePeerDependencies: - bufferutil @@ -4528,6 +4600,12 @@ packages: version: 1.7.6 dev: true + github.com/foundry-rs/forge-std/e4aef94c1768803a16fe19f7ce8b65defd027cfd: + resolution: {tarball: https://codeload.github.com/foundry-rs/forge-std/tar.gz/e4aef94c1768803a16fe19f7ce8b65defd027cfd} + name: forge-std + version: 1.7.6 + dev: true + github.com/kopy-kat/account-abstraction/3c0127e9f7cb76e4a0fdb2d35cac51900f252bdc(ethers@5.4.0)(hardhat@2.22.2)(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 @@ -4592,13 +4670,54 @@ packages: - utf-8-validate dev: true + github.com/kopy-kat/account-abstraction/c5887153fbfe3ed09b2637cac39873f96d676f38(ethers@5.4.0)(hardhat@2.22.2)(lodash@4.17.21)(typechain@5.2.0): + resolution: {tarball: https://codeload.github.com/kopy-kat/account-abstraction/tar.gz/c5887153fbfe3ed09b2637cac39873f96d676f38} + id: github.com/kopy-kat/account-abstraction/c5887153fbfe3ed09b2637cac39873f96d676f38 + name: accountabstraction + version: 0.7.0 + dependencies: + '@nomiclabs/hardhat-etherscan': 2.1.8(hardhat@2.22.2) + '@openzeppelin/contracts': 5.0.1 + '@thehubbleproject/bls': 0.5.1 + '@typechain/hardhat': 2.3.1(hardhat@2.22.2)(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.4.0)(hardhat@2.22.2) + solidity-coverage: 0.8.12(hardhat@2.22.2) + source-map-support: 0.5.21 + table: 6.8.2 + typescript: 4.9.5 + transitivePeerDependencies: + - bufferutil + - encoding + - ethers + - hardhat + - lodash + - supports-color + - typechain + - utf-8-validate + dev: true + github.com/rhinestonewtf/erc4337-validation/19a97d86f8f29709664334078925b2a843be19e0: resolution: {tarball: https://codeload.github.com/rhinestonewtf/erc4337-validation/tar.gz/19a97d86f8f29709664334078925b2a843be19e0} name: erc4337-validation version: 0.0.1 dependencies: '@openzeppelin/contracts': 5.0.1 - solady: github.com/vectorized/solady/72e47ca417d24a30801b2921584e8486462cfc7b + solady: github.com/vectorized/solady/5d9817ee8665dbace6cc01ddf5f7b605cf06eb6b + dev: true + + github.com/rhinestonewtf/erc4337-validation/abaff656852e3a4b9790e458e17165adf00e3e54: + resolution: {tarball: https://codeload.github.com/rhinestonewtf/erc4337-validation/tar.gz/abaff656852e3a4b9790e458e17165adf00e3e54} + name: '@rhinestone/erc4337-validation' + version: 0.0.1-alpha.1 + dependencies: + '@openzeppelin/contracts': 5.0.1 + solady: github.com/vectorized/solady/5d9817ee8665dbace6cc01ddf5f7b605cf06eb6b dev: true github.com/sablier-labs/solarray/6bf10cb34cdace52a3ba5fe437e78cc82df92684: @@ -4613,12 +4732,24 @@ packages: version: 6.2.0 dev: true + github.com/vectorized/solady/5d9817ee8665dbace6cc01ddf5f7b605cf06eb6b: + resolution: {tarball: https://codeload.github.com/vectorized/solady/tar.gz/5d9817ee8665dbace6cc01ddf5f7b605cf06eb6b} + name: solady + version: 0.0.184 + dev: true + github.com/vectorized/solady/72e47ca417d24a30801b2921584e8486462cfc7b: resolution: {tarball: https://codeload.github.com/vectorized/solady/tar.gz/72e47ca417d24a30801b2921584e8486462cfc7b} name: solady version: 0.0.170 dev: true + github.com/zeroknots/sentinellist/05e0cf2a22279cf66a62cdc8a006df830348aa0e: + resolution: {tarball: https://codeload.github.com/zeroknots/sentinellist/tar.gz/05e0cf2a22279cf66a62cdc8a006df830348aa0e} + name: sentinellist + version: 1.0.1 + dev: true + github.com/zeroknots/sentinellist/6294bf412489c0f6d3b9c92ad0aceb08c5b8704b: resolution: {tarball: https://codeload.github.com/zeroknots/sentinellist/tar.gz/6294bf412489c0f6d3b9c92ad0aceb08c5b8704b} name: sentinellist From c95efad10ff17233c686a1636089ddfa27bfb543 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Wed, 17 Apr 2024 13:23:21 +0700 Subject: [PATCH 44/64] tests --- accounts/safe7579/.gas-snapshot | 32 +++++ accounts/safe7579/src/SafeERC7579.sol | 16 ++- accounts/safe7579/src/core/DCUtil.sol | 20 +-- accounts/safe7579/src/core/HookManager.sol | 60 +++------ accounts/safe7579/src/core/Initializer.sol | 15 ++- accounts/safe7579/src/core/ModuleManager.sol | 6 +- .../safe7579/src/interfaces/ISafe7579Init.sol | 2 +- accounts/safe7579/src/lib/ExecOnSafeLib.sol | 11 +- accounts/safe7579/src/utils/DCUtil.sol | 100 ++++++++++++++ accounts/safe7579/src/utils/Launchpad.sol | 4 +- .../safe7579/test/ERC7579Compliance.t.sol | 3 + .../test/ERC7579Compliance/Base.t.sol | 127 ++++++++++++++++++ .../test/ERC7579Compliance/ERC1271.t.sol | 41 ++++++ .../test/ERC7579Compliance/ERC1271.tree | 6 + .../test/ERC7579Compliance/ERC4337.t.sol | 79 +++++++++++ .../test/ERC7579Compliance/ERC4337.tree | 6 + .../ERC7579Compliance/Executions4337.t.sol | 65 +++++++++ .../ERC7579Compliance/Executions4337.tree | 9 ++ .../ERC7579Compliance/ExecutionsModule.t.sol | 67 +++++++++ .../ERC7579Compliance/ExecutionsModule.tree | 9 ++ .../test/ERC7579Compliance/Hooks.t.sol | 20 +++ .../test/ERC7579Compliance/Hooks.tree | 9 ++ .../ERC7579Compliance/ModuleManagement.t.sol | 65 +++++++++ .../ERC7579Compliance/ModuleManagement.tree | 4 + accounts/safe7579/test/Launchpad.t.sol | 5 +- accounts/safe7579/test/SafeERC7579.t.sol | 38 ------ accounts/safe7579/test/mocks/MockTarget.sol | 1 + 27 files changed, 703 insertions(+), 117 deletions(-) create mode 100644 accounts/safe7579/.gas-snapshot create mode 100644 accounts/safe7579/src/utils/DCUtil.sol create mode 100644 accounts/safe7579/test/ERC7579Compliance.t.sol create mode 100644 accounts/safe7579/test/ERC7579Compliance/Base.t.sol create mode 100644 accounts/safe7579/test/ERC7579Compliance/ERC1271.t.sol create mode 100644 accounts/safe7579/test/ERC7579Compliance/ERC1271.tree create mode 100644 accounts/safe7579/test/ERC7579Compliance/ERC4337.t.sol create mode 100644 accounts/safe7579/test/ERC7579Compliance/ERC4337.tree create mode 100644 accounts/safe7579/test/ERC7579Compliance/Executions4337.t.sol create mode 100644 accounts/safe7579/test/ERC7579Compliance/Executions4337.tree create mode 100644 accounts/safe7579/test/ERC7579Compliance/ExecutionsModule.t.sol create mode 100644 accounts/safe7579/test/ERC7579Compliance/ExecutionsModule.tree create mode 100644 accounts/safe7579/test/ERC7579Compliance/Hooks.t.sol create mode 100644 accounts/safe7579/test/ERC7579Compliance/Hooks.tree create mode 100644 accounts/safe7579/test/ERC7579Compliance/ModuleManagement.t.sol create mode 100644 accounts/safe7579/test/ERC7579Compliance/ModuleManagement.tree diff --git a/accounts/safe7579/.gas-snapshot b/accounts/safe7579/.gas-snapshot new file mode 100644 index 00000000..dc20dc0a --- /dev/null +++ b/accounts/safe7579/.gas-snapshot @@ -0,0 +1,32 @@ +BaseTest:test_checkVersion() (gas: 21951) +BaseTest:test_foo() (gas: 3049) +ERC1271Test:test_WhenForwardingERC1271(bytes4) (runs: 258, μ: 207522, ~: 215621) +ERC1271Test:test_checkVersion() (gas: 21973) +ERC1271Test:test_foo() (gas: 3094) +ERC4337Test:test_WhenCallingValidateFunction() (gas: 122) +ERC4337Test:test_WhenEncodingAnInvalidValidatorModule() (gas: 144) +ERC7579ComplianceTest:test_exec4337() (gas: 98) +Executions4337Test:test_WhenExecutingOnValidTarget() (gas: 201167) +Executions4337Test:test_WhenExecutingSingleOnInvalidTarget() (gas: 38154) +Executions4337Test:test_WhenTryExecutingOnValidTarget() (gas: 66317) +Executions4337Test:test_checkVersion() (gas: 21984) +Executions4337Test:test_foo() (gas: 3127) +ExecutionsModuleTest:test_WhenExecutingOnValidTarget() (gas: 211917) +ExecutionsModuleTest:test_WhenExecutingSingleOnInvalidTarget() (gas: 45375) +ExecutionsModuleTest:test_WhenTryExecutingOnValidTarget() (gas: 76680) +ExecutionsModuleTest:test_checkVersion() (gas: 22013) +ExecutionsModuleTest:test_foo() (gas: 3094) +HookTest:test_WhenExecutingVia4337() (gas: 166) +HookTest:test_WhenExecutingViaModule() (gas: 122) +HookTest:test_WhenHookReverts() (gas: 144) +HookTest:test_WhenInstallingModule() (gas: 188) +LaunchpadBase:test_foo() (gas: 3071) +ModuleManagementTest:test_WhenInstallingModules() (gas: 232018) +ModuleManagementTest:test_checkVersion() (gas: 21973) +ModuleManagementTest:test_foo() (gas: 3094) +Safe7579Test:test_execBatch() (gas: 169250) +Safe7579Test:test_execBatchFromExecutor() (gas: 91544) +Safe7579Test:test_execSingle() (gas: 156580) +Safe7579Test:test_execViaExecutor() (gas: 73709) +Safe7579Test:test_fallback() (gas: 265186) +Safe7579Test:test_foo() (gas: 3071) \ No newline at end of file diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index d25bceaf..30d3a31d 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -36,6 +36,8 @@ import { IEntryPoint } from "@ERC4337/account-abstraction/contracts/interfaces/I import { ISafe7579Init } from "./interfaces/ISafe7579Init.sol"; import { IERC1271 } from "./interfaces/IERC1271.sol"; +import "forge-std/console2.sol"; + /** * @title ERC7579 Adapter for Safe accounts. * creates full ERC7579 compliance to Safe accounts @@ -53,6 +55,7 @@ contract SafeERC7579 is using UserOperationLib for PackedUserOperation; using ModeLib for ModeCode; using ExecutionLib for bytes; + using HookedExecOnSafeLib for ISafe; error Unsupported(); @@ -74,7 +77,7 @@ contract SafeERC7579 is { CallType callType; ExecType execType; - address hook = getActiveHook(); + address hook = getActiveHook(msg.sig); // solhint-disable-next-line no-inline-assembly assembly { @@ -257,11 +260,16 @@ contract SafeERC7579 is override onlyEntryPointOrSelf { + // address hook = getActiveHook(); + address hook = address(0); + bytes memory hookPreContext = ISafe(msg.sender).preHook(hook); + if (moduleType == MODULE_TYPE_VALIDATOR) _installValidator(module, initData); else if (moduleType == MODULE_TYPE_EXECUTOR) _installExecutor(module, initData); else if (moduleType == MODULE_TYPE_FALLBACK) _installFallbackHandler(module, initData); else if (moduleType == MODULE_TYPE_HOOK) _installHook(module, initData); else revert UnsupportedModuleType(moduleType); + ISafe(msg.sender).postHook(hook, hookPreContext, true, ""); } /** @@ -326,7 +334,7 @@ contract SafeERC7579 is } else if (moduleType == MODULE_TYPE_FALLBACK) { return _isFallbackHandlerInstalled(module, additionalContext); } else if (moduleType == MODULE_TYPE_HOOK) { - return _isHookInstalled(module); + return _isHookInstalled(module, additionalContext); } else { return false; } @@ -336,8 +344,8 @@ contract SafeERC7579 is * @inheritdoc IERC7579Account */ function accountId() external view override returns (string memory accountImplementationId) { - string memory safeVersion = ISafe(_msgSender()).VERSION(); - return string(abi.encodePacked(safeVersion, "erc7579.v0.0.0")); + string memory safeVersion = ISafe(msg.sender).VERSION(); + return string(abi.encodePacked("safe-", safeVersion, ".erc7579.v0.0.1")); } /** diff --git a/accounts/safe7579/src/core/DCUtil.sol b/accounts/safe7579/src/core/DCUtil.sol index 2937f6ee..a12df061 100644 --- a/accounts/safe7579/src/core/DCUtil.sol +++ b/accounts/safe7579/src/core/DCUtil.sol @@ -1,29 +1,15 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.25; -import { DelegateCallTarget as DCTarget, EventEmitter } from "../utils/DelegatecallTarget.sol"; +import { Safe7579DCUtil } from "../utils/DCUtil.sol"; import { ISafe, ExecOnSafeLib } from "../lib/ExecOnSafeLib.sol"; contract DelegateCallUtil { using ExecOnSafeLib for ISafe; - DCTarget internal DCTARGET; + address internal UTIL; constructor() { - DCTARGET = new DCTarget(); - } - - function _emitModuleInstall(uint256 moduleTypeId, address module) internal { - ISafe(msg.sender).execDelegateCall({ - target: address(DCTARGET), - callData: abi.encodeCall(EventEmitter.emitModuleInstalled, (moduleTypeId, module)) - }); - } - - function _emitModuleUninstall(uint256 moduleTypeId, address module) internal { - ISafe(msg.sender).execDelegateCall({ - target: address(DCTARGET), - callData: abi.encodeCall(EventEmitter.emitModuleUninstalled, (moduleTypeId, module)) - }); + UTIL = address(new Safe7579DCUtil()); } } diff --git a/accounts/safe7579/src/core/HookManager.sol b/accounts/safe7579/src/core/HookManager.sol index 6d8df33a..14c6b873 100644 --- a/accounts/safe7579/src/core/HookManager.sol +++ b/accounts/safe7579/src/core/HookManager.sol @@ -13,41 +13,11 @@ import { ISafe, ExecOnSafeLib } from "../lib/ExecOnSafeLib.sol"; abstract contract HookManager is ModuleManager { using ExecOnSafeLib for ISafe; - mapping(address smartAccount => address hook) internal $hookManager; + mapping(address smartAccount => mapping(bytes4 => address hook)) internal $hookManager; error HookPostCheckFailed(); error HookAlreadyInstalled(address currentHook); - // function _preHook(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.value, msg.data)) - // }), - // (bytes) - // ); - // } - // - // function _postHook( - // address hook, - // bool executionSuccess, - // bytes memory executionReturnValue, - // bytes memory hookPreContext - // ) - // internal - // { - // _execute({ - // safe: msg.sender, - // target: hook, - // value: 0, - // callData: abi.encodeCall( - // IHook.postCheck, (hookPreContext, executionSuccess, executionReturnValue) - // ) - // }); - // } - function _installHook( address hook, bytes calldata data @@ -56,34 +26,44 @@ abstract contract HookManager is ModuleManager { virtual withRegistry(hook, MODULE_TYPE_HOOK) { - address currentHook = $hookManager[msg.sender]; + (bytes4 selector, bytes memory initData) = abi.decode(data, (bytes4, bytes)); + address currentHook = $hookManager[msg.sender][selector]; if (currentHook != address(0)) { revert HookAlreadyInstalled(currentHook); } - $hookManager[msg.sender] = hook; + $hookManager[msg.sender][selector] = hook; ISafe(msg.sender).exec({ target: hook, value: 0, - callData: abi.encodeCall(IModule.onInstall, (data)) + callData: abi.encodeCall(IModule.onInstall, (initData)) }); _emitModuleInstall(MODULE_TYPE_HOOK, hook); } function _uninstallHook(address hook, bytes calldata data) internal virtual { - $hookManager[msg.sender] = address(0); + (bytes4 selector, bytes memory initData) = abi.decode(data, (bytes4, bytes)); + delete $hookManager[msg.sender][selector]; ISafe(msg.sender).exec({ target: hook, value: 0, - callData: abi.encodeCall(IModule.onUninstall, (data)) + callData: abi.encodeCall(IModule.onUninstall, (initData)) }); _emitModuleUninstall(MODULE_TYPE_HOOK, hook); } - function _isHookInstalled(address module) internal view returns (bool) { - return $hookManager[msg.sender] == module; + function _isHookInstalled( + address module, + bytes calldata context + ) + internal + view + returns (bool) + { + bytes4 selector = abi.decode(context, (bytes4)); + return $hookManager[msg.sender][selector] == module; } - function getActiveHook() public view returns (address hook) { - return $hookManager[msg.sender]; + function getActiveHook(bytes4 selector) public view returns (address hook) { + return $hookManager[msg.sender][selector]; } } diff --git a/accounts/safe7579/src/core/Initializer.sol b/accounts/safe7579/src/core/Initializer.sol index c2963e29..e22e8658 100644 --- a/accounts/safe7579/src/core/Initializer.sol +++ b/accounts/safe7579/src/core/Initializer.sol @@ -49,7 +49,7 @@ abstract contract Initializer is ISafe7579Init, HookManager { * @param executors executor modules and initData * @param executors executor modules and initData * @param fallbacks fallback modules and initData - * @param hook hook module and initData + * @param hooks hook module and initData * @param registryInit (OPTIONAL) registry, attesters and threshold for IERC7484 Registry * If not provided, the registry will be set to the zero address, and no * registry checks will be performed @@ -58,7 +58,7 @@ abstract contract Initializer is ISafe7579Init, HookManager { ModuleInit[] calldata validators, ModuleInit[] calldata executors, ModuleInit[] calldata fallbacks, - ModuleInit calldata hook, + ModuleInit[] calldata hooks, RegistryInit calldata registryInit ) public @@ -66,14 +66,14 @@ abstract contract Initializer is ISafe7579Init, HookManager { { _configureRegistry(registryInit.registry, registryInit.attesters, registryInit.threshold); // this will revert if already initialized - _initModules(validators, executors, fallbacks, hook); + _initModules(validators, executors, fallbacks, hooks); } function _initModules( ModuleInit[] calldata validators, ModuleInit[] calldata executors, ModuleInit[] calldata fallbacks, - ModuleInit calldata hook + ModuleInit[] calldata hooks ) internal { @@ -111,7 +111,12 @@ abstract contract Initializer is ISafe7579Init, HookManager { _installFallbackHandler(_fallback.module, _fallback.initData); } - _installHook(hook.module, hook.initData); + length = hooks.length; + for (uint256 i; i < length; i++) { + ModuleInit calldata hook = hooks[i]; + // enable module on Safe7579, initialize module via Safe, emit events + _installHook(hook.module, hook.initData); + } emit Safe7579Initialized(msg.sender); } diff --git a/accounts/safe7579/src/core/ModuleManager.sol b/accounts/safe7579/src/core/ModuleManager.sol index 7d4ee730..b07709e1 100644 --- a/accounts/safe7579/src/core/ModuleManager.sol +++ b/accounts/safe7579/src/core/ModuleManager.sol @@ -227,8 +227,8 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter, Del return $fallback.handler != address(0); } - function _uninstallFallbackHandler(address handler, bytes calldata initData) internal virtual { - (bytes4 functionSig) = abi.decode(initData, (bytes4)); + function _uninstallFallbackHandler(address handler, bytes calldata context) internal virtual { + (bytes4 functionSig, bytes memory initData) = abi.decode(context, (bytes4, bytes)); ModuleManagerStorage storage $mms = $moduleManager[msg.sender]; $mms._fallbacks[functionSig].handler = address(0); @@ -252,6 +252,8 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter, Del { bytes4 functionSig = abi.decode(additionalContext, (bytes4)); + // TODO: check that no onInstall / onUninstall is called + FallbackHandler storage $fallback = $moduleManager[msg.sender]._fallbacks[functionSig]; return $fallback.handler == _handler; } diff --git a/accounts/safe7579/src/interfaces/ISafe7579Init.sol b/accounts/safe7579/src/interfaces/ISafe7579Init.sol index 43bc29ee..2efa5eda 100644 --- a/accounts/safe7579/src/interfaces/ISafe7579Init.sol +++ b/accounts/safe7579/src/interfaces/ISafe7579Init.sol @@ -19,7 +19,7 @@ interface ISafe7579Init { ModuleInit[] calldata validators, ModuleInit[] calldata executors, ModuleInit[] calldata fallbacks, - ModuleInit calldata hook, + ModuleInit[] calldata hooks, RegistryInit calldata registryInit ) external diff --git a/accounts/safe7579/src/lib/ExecOnSafeLib.sol b/accounts/safe7579/src/lib/ExecOnSafeLib.sol index 10f285b5..77358939 100644 --- a/accounts/safe7579/src/lib/ExecOnSafeLib.sol +++ b/accounts/safe7579/src/lib/ExecOnSafeLib.sol @@ -204,7 +204,8 @@ library HookedExecOnSafeLib { using TryExecOnSafeLib for ISafe; using ExecutionLib for bytes; - function preHook(ISafe safe, address withHook) private returns (bytes memory hookPreContext) { + function preHook(ISafe safe, address withHook) internal returns (bytes memory hookPreContext) { + if (withHook == address(0)) return ""; hookPreContext = abi.decode( safe.execReturn({ target: withHook, @@ -222,8 +223,9 @@ library HookedExecOnSafeLib { bool excutionSuccess, bytes memory executionReturnValue ) - private + internal { + if (withHook == address(0)) return; safe.execReturn({ target: withHook, value: 0, @@ -274,10 +276,9 @@ library HookedExecOnSafeLib { returns (bytes[] memory retDatas) { bool success; - bool hookEnabled = hook != address(0); ISafe safe = ISafe(msg.sender); bytes memory preHookContext; - if (hookEnabled) preHookContext = preHook(safe, hook); + preHookContext = preHook(safe, hook); if (callType == CALLTYPE_BATCH) { Execution[] calldata executions = executionCalldata.decodeBatch(); @@ -295,7 +296,7 @@ library HookedExecOnSafeLib { } else { revert UnsupportedCallType(callType); } - if (hookEnabled) postHook(safe, hook, preHookContext, true, abi.encode(retDatas)); + postHook(safe, hook, preHookContext, true, abi.encode(retDatas)); } } diff --git a/accounts/safe7579/src/utils/DCUtil.sol b/accounts/safe7579/src/utils/DCUtil.sol new file mode 100644 index 00000000..e94b6bff --- /dev/null +++ b/accounts/safe7579/src/utils/DCUtil.sol @@ -0,0 +1,100 @@ +import { Execution } from "erc7579/interfaces/IERC7579Account.sol"; +import { IModule as IERC7579Module } from "erc7579/interfaces/IERC7579Module.sol"; + +contract ModuleInstallUtil { + event ModuleInstalled(uint256 moduleTypeId, address module); + event ModuleUninstalled(uint256 moduleTypeId, address module); + + function installModule( + uint256 moduleTypeId, + IERC7579Module module, + bytes calldata initData + ) + external + { + module.onInstall(initData); + emit ModuleInstalled(moduleTypeId, address(module)); + } + + function unInstallModule( + uint256 moduleTypeId, + IERC7579Module module, + bytes calldata initData + ) + external + { + module.onUninstall(initData); + emit ModuleUninstalled(moduleTypeId, address(module)); + } +} + +contract BatchedExecUtil { + function tryExecute(Execution[] calldata executions) external returns (bytes[] memory result) { + uint256 length = executions.length; + result = new bytes[](length); + + for (uint256 i; i < length; i++) { + Execution calldata _exec = executions[i]; + bool success; + (success, result[i]) = _tryExecute(_exec.target, _exec.value, _exec.callData); + } + } + + function execute(Execution[] calldata executions) external returns (bytes[] memory result) { + uint256 length = executions.length; + result = new bytes[](length); + + for (uint256 i; i < length; i++) { + Execution calldata _exec = executions[i]; + result[i] = _execute(_exec.target, _exec.value, _exec.callData); + } + } + + function _execute( + address target, + uint256 value, + bytes calldata callData + ) + internal + virtual + returns (bytes memory result) + { + /// @solidity memory-safe-assembly + assembly { + result := mload(0x40) + calldatacopy(result, callData.offset, callData.length) + if iszero(call(gas(), target, value, result, callData.length, codesize(), 0x00)) { + // Bubble up the revert if the call reverts. + returndatacopy(result, 0x00, returndatasize()) + revert(result, returndatasize()) + } + mstore(result, returndatasize()) // Store the length. + let o := add(result, 0x20) + returndatacopy(o, 0x00, returndatasize()) // Copy the returndata. + mstore(0x40, add(o, returndatasize())) // Allocate the memory. + } + } + + function _tryExecute( + address target, + uint256 value, + bytes calldata callData + ) + internal + virtual + returns (bool success, bytes memory result) + { + /// @solidity memory-safe-assembly + assembly { + result := mload(0x40) + calldatacopy(result, callData.offset, callData.length) + success := iszero(call(gas(), target, value, result, callData.length, codesize(), 0x00)) + mstore(result, returndatasize()) // Store the length. + let o := add(result, 0x20) + returndatacopy(o, 0x00, returndatasize()) // Copy the returndata. + mstore(0x40, add(o, returndatasize())) // Allocate the memory. + } + } +} + +contract Safe7579DCUtil is ModuleInstallUtil, BatchedExecUtil { } diff --git a/accounts/safe7579/src/utils/Launchpad.sol b/accounts/safe7579/src/utils/Launchpad.sol index 86d61ed1..1d89d73d 100644 --- a/accounts/safe7579/src/utils/Launchpad.sol +++ b/accounts/safe7579/src/utils/Launchpad.sol @@ -85,7 +85,7 @@ contract Safe7579Launchpad is IAccount, SafeStorage { address safe7579, ISafe7579Init.ModuleInit[] calldata executors, ISafe7579Init.ModuleInit[] calldata fallbacks, - ISafe7579Init.ModuleInit calldata hook, + ISafe7579Init.ModuleInit[] calldata hooks, address[] calldata attesters, uint8 threshold ) @@ -97,7 +97,7 @@ contract Safe7579Launchpad is IAccount, SafeStorage { validators: new ISafe7579Init.ModuleInit[](0), executors: executors, fallbacks: fallbacks, - hook: hook, + hooks: hooks, registryInit: ISafe7579Init.RegistryInit({ registry: REGISTRY, attesters: attesters, diff --git a/accounts/safe7579/test/ERC7579Compliance.t.sol b/accounts/safe7579/test/ERC7579Compliance.t.sol new file mode 100644 index 00000000..c966023d --- /dev/null +++ b/accounts/safe7579/test/ERC7579Compliance.t.sol @@ -0,0 +1,3 @@ +contract ERC7579ComplianceTest { + function test_exec4337() public { } +} diff --git a/accounts/safe7579/test/ERC7579Compliance/Base.t.sol b/accounts/safe7579/test/ERC7579Compliance/Base.t.sol new file mode 100644 index 00000000..c2956053 --- /dev/null +++ b/accounts/safe7579/test/ERC7579Compliance/Base.t.sol @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import "../Launchpad.t.sol"; +import "erc7579/interfaces/IERC7579Account.sol"; +import "erc7579/interfaces/IERC7579Module.sol"; + +contract MockModule is IModule { + bool initialized; + + function onInstall(bytes calldata data) public virtual { } + + function onUninstall(bytes calldata data) external virtual { } + + function isModuleType(uint256 moduleTypeId) external view returns (bool) { + return true; + } + + function isInitialized(address smartAccount) external view returns (bool) { + return initialized; + } + + function validateUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash + ) + external + virtual + returns (uint256) + { + return 1; + } + + function isValidSignatureWithSender( + address sender, + bytes32 hash, + bytes calldata data + ) + external + view + virtual + returns (bytes4) + { + return IERC7579Account.isValidSignature.selector; + } + + function preCheck( + address msgSender, + uint256 msgValue, + bytes calldata msgData + ) + external + returns (bytes memory hookData) + { } + + function postCheck( + bytes calldata hookData, + bool executionSuccess, + bytes calldata executionReturnValue + ) + external + { } +} + +contract BaseTest is LaunchpadBase, MockModule { + IERC7579Account account; + + address SELF; + + modifier asEntryPoint() { + vm.startPrank(address(entrypoint)); + _; + vm.stopPrank(); + } + + function setUp() public virtual override { + super.setUp(); + target = new MockTarget(); + + initFirstExec(); + account = IERC7579Account(address(safe)); + SELF = address(this); + } + + function installUnitTestAsModule() public asEntryPoint { + account.installModule(1, SELF, ""); + account.installModule(2, SELF, ""); + // account.installModule(3, SELF, ""); + // account.installModule(4, SELF,""); + } + + function initFirstExec() 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) + ) + ); + + PackedUserOperation memory userOp = + getDefaultUserOp(address(safe), address(defaultValidator)); + userOp.initCode = userOpInitCode; + 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_checkVersion() public { + string memory version = account.accountId(); + + string memory versionExpected = "safe-1.4.1.erc7579.v0.0.1"; + assertEq(version, versionExpected); + } +} diff --git a/accounts/safe7579/test/ERC7579Compliance/ERC1271.t.sol b/accounts/safe7579/test/ERC7579Compliance/ERC1271.t.sol new file mode 100644 index 00000000..fe3de84d --- /dev/null +++ b/accounts/safe7579/test/ERC7579Compliance/ERC1271.t.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.0; + +import "./Base.t.sol"; + +contract ERC1271Test is BaseTest { + address _sender; + bytes32 _hash; + bytes _data; + bytes4 _erc1271Selector; + + function isValidSignatureWithSender( + address sender, + bytes32 hash, + bytes calldata data + ) + external + view + virtual + override + returns (bytes4) + { + // It should forward the correct msgSender + assertEq(sender, _sender); + assertEq(hash, _hash); + // It should slice the correct signature + assertEq(data, _data); + return _erc1271Selector; + } + + function test_WhenForwardingERC1271(bytes4 selector) external { + installUnitTestAsModule(); + // It should select the correct validator + _erc1271Selector = selector; + _hash = bytes32("foo"); + _data = abi.encodePacked(hex"4141414141"); + _sender = SELF; + bytes4 ret = account.isValidSignature(_hash, abi.encodePacked(SELF, _data)); + assertEq(ret, _erc1271Selector); + } +} diff --git a/accounts/safe7579/test/ERC7579Compliance/ERC1271.tree b/accounts/safe7579/test/ERC7579Compliance/ERC1271.tree new file mode 100644 index 00000000..fdef76dd --- /dev/null +++ b/accounts/safe7579/test/ERC7579Compliance/ERC1271.tree @@ -0,0 +1,6 @@ +ERC1271Test +└── When forwarding ERC1271 + └── It should select the correct validator + └── It should forward the correct msgSender + └── It should slice the correct signature + └── It should implement fallback to safe signature checks diff --git a/accounts/safe7579/test/ERC7579Compliance/ERC4337.t.sol b/accounts/safe7579/test/ERC7579Compliance/ERC4337.t.sol new file mode 100644 index 00000000..9cc22d37 --- /dev/null +++ b/accounts/safe7579/test/ERC7579Compliance/ERC4337.t.sol @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.0; + +import "./Base.t.sol"; + +interface IERC4337 { + function validateUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash, + uint256 missingAccountFunds + ) + external + payable + returns (uint256 validSignature); +} + +contract ERC4337Test is BaseTest { + bytes _calldata; + uint256 _ret; + bytes32 _userOpHash; + + function setUp() public virtual override { + super.setUp(); + installUnitTestAsModule(); + } + + function validateUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash + ) + external + override + returns (uint256) + { + assertEq(userOp.callData, _calldata); + assertEq(userOpHash, _userOpHash); + return _ret; + } + + function test_WhenCallingValidateFunction( + bytes32 userOpHash, + uint256 ret + ) + external + asEntryPoint + { + // It should select the correct validator module + _ret = ret; + _calldata = hex"41414141"; + _userOpHash = userOpHash; + + PackedUserOperation memory userOp = getDefaultUserOp(address(safe), address(SELF)); + userOp.callData = _calldata; + + uint256 rett = IERC4337(address(account)).validateUserOp(userOp, userOpHash, 100); + + assertEq(rett, ret); + } + + function test_WhenEncodingAnInvalidValidatorModule( + bytes32 userOpHash, + uint256 ret + ) + external + asEntryPoint + { + // It should fallback to safe signature checks + _ret = ret; + _calldata = hex"41414141"; + _userOpHash = userOpHash; + + PackedUserOperation memory userOp = getDefaultUserOp(address(safe), address(0)); + userOp.callData = _calldata; + userOp.signature = abi.encodePacked(uint48(0), uint48(type(uint48).max), hex"41414141"); + + // TODO: check return + uint256 rett = IERC4337(address(account)).validateUserOp(userOp, userOpHash, 100); + } +} diff --git a/accounts/safe7579/test/ERC7579Compliance/ERC4337.tree b/accounts/safe7579/test/ERC7579Compliance/ERC4337.tree new file mode 100644 index 00000000..d7e2fb56 --- /dev/null +++ b/accounts/safe7579/test/ERC7579Compliance/ERC4337.tree @@ -0,0 +1,6 @@ +ERC4337Test +├── When calling validate function +│ ├── It should select the correct validator module +│ └── It should use the return value set by the validator module +└── When encoding an invalid validator module + └── It should fallback to safe signature checks diff --git a/accounts/safe7579/test/ERC7579Compliance/Executions4337.t.sol b/accounts/safe7579/test/ERC7579Compliance/Executions4337.t.sol new file mode 100644 index 00000000..715c7b3c --- /dev/null +++ b/accounts/safe7579/test/ERC7579Compliance/Executions4337.t.sol @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.0; + +import "./Base.t.sol"; +import "erc7579/lib/ModeLib.sol"; + +contract Executions4337Test is BaseTest { + function setUp() public virtual override { + super.setUp(); + installUnitTestAsModule(); + } + + function test_WhenExecutingOnValidTarget() external asEntryPoint { + bytes memory setValueOnTarget = abi.encodeCall(MockTarget.set, 1337); + // It should pass + account.execute( + ModeLib.encodeSimpleSingle(), + ExecutionLib.encodeSingle(address(target), uint256(0), setValueOnTarget) + ); + assertEq(target.value(), 1337); + + setValueOnTarget = abi.encodeCall(MockTarget.set, 1336); + Execution[] memory executions = new Execution[](2); + MockTarget target2 = new MockTarget(); + executions[0] = + Execution({ target: address(target2), value: 0, callData: setValueOnTarget }); + executions[1] = Execution({ target: address(target), value: 0, callData: setValueOnTarget }); + account.execute(ModeLib.encodeSimpleBatch(), ExecutionLib.encodeBatch(executions)); + assertEq(target2.value(), 1336); + assertEq(target.value(), 1336); + } + + function test_WhenExecutingSingleOnInvalidTarget() external asEntryPoint { + // It should revert + vm.expectRevert(); + account.execute( + ModeLib.encodeSimpleSingle(), + ExecutionLib.encodeSingle(address(target), uint256(0), hex"4141414141414141") + ); + } + + function test_WhenTryExecutingOnValidTarget() external asEntryPoint { + bytes memory setValueOnTarget = abi.encodeCall(MockTarget.set, 1337); + // It should pass + account.execute( + ModeLib.encode( + CALLTYPE_SINGLE, EXECTYPE_TRY, MODE_DEFAULT, ModePayload.wrap(bytes22(0)) + ), + ExecutionLib.encodeSingle(address(target), uint256(0), hex"41414141") + ); + + setValueOnTarget = abi.encodeCall(MockTarget.set, 1338); + Execution[] memory executions = new Execution[](2); + // this one will fail + executions[0] = Execution({ target: address(target), value: 0, callData: hex"41414141" }); + // this one will execute + executions[1] = Execution({ target: address(target), value: 0, callData: setValueOnTarget }); + account.execute( + ModeLib.encode(CALLTYPE_BATCH, EXECTYPE_TRY, MODE_DEFAULT, ModePayload.wrap(bytes22(0))), + ExecutionLib.encodeBatch(executions) + ); + + assertEq(target.value(), 1338); + } +} diff --git a/accounts/safe7579/test/ERC7579Compliance/Executions4337.tree b/accounts/safe7579/test/ERC7579Compliance/Executions4337.tree new file mode 100644 index 00000000..f3b2d3e5 --- /dev/null +++ b/accounts/safe7579/test/ERC7579Compliance/Executions4337.tree @@ -0,0 +1,9 @@ +Executions4337Test +├── When executing on valid target // implement single, batch and delegatecall +│ └── It should pass +├── When executing single on invalid target //implement single, batch and delegatecall +│ └── It should revert +├── When try executing on valid target // implement single, batch and delegatecall +│ └── It should pass +└── When try executing single on invalid target //implement single, batch and delegatecall + └── It should emit at the correct index diff --git a/accounts/safe7579/test/ERC7579Compliance/ExecutionsModule.t.sol b/accounts/safe7579/test/ERC7579Compliance/ExecutionsModule.t.sol new file mode 100644 index 00000000..9e8e484e --- /dev/null +++ b/accounts/safe7579/test/ERC7579Compliance/ExecutionsModule.t.sol @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.0; + +import "./Base.t.sol"; +import "erc7579/lib/ModeLib.sol"; + +contract ExecutionsModuleTest is BaseTest { + function setUp() public virtual override { + super.setUp(); + installUnitTestAsModule(); + } + + function test_WhenExecutingOnValidTarget() external { + bytes memory setValueOnTarget = abi.encodeCall(MockTarget.set, 1337); + // It should pass + account.executeFromExecutor( + ModeLib.encodeSimpleSingle(), + ExecutionLib.encodeSingle(address(target), uint256(0), setValueOnTarget) + ); + assertEq(target.value(), 1337); + + setValueOnTarget = abi.encodeCall(MockTarget.set, 1336); + Execution[] memory executions = new Execution[](2); + MockTarget target2 = new MockTarget(); + executions[0] = + Execution({ target: address(target2), value: 0, callData: setValueOnTarget }); + executions[1] = Execution({ target: address(target), value: 0, callData: setValueOnTarget }); + account.executeFromExecutor( + ModeLib.encodeSimpleBatch(), ExecutionLib.encodeBatch(executions) + ); + assertEq(target2.value(), 1336); + assertEq(target.value(), 1336); + } + + function test_WhenExecutingSingleOnInvalidTarget() external { + // It should revert + vm.expectRevert(); + account.executeFromExecutor( + ModeLib.encodeSimpleSingle(), + ExecutionLib.encodeSingle(address(target), uint256(0), hex"4141414141414141") + ); + } + + function test_WhenTryExecutingOnValidTarget() external { + bytes memory setValueOnTarget = abi.encodeCall(MockTarget.set, 1337); + // It should pass + account.executeFromExecutor( + ModeLib.encode( + CALLTYPE_SINGLE, EXECTYPE_TRY, MODE_DEFAULT, ModePayload.wrap(bytes22(0)) + ), + ExecutionLib.encodeSingle(address(target), uint256(0), hex"41414141") + ); + + setValueOnTarget = abi.encodeCall(MockTarget.set, 1338); + Execution[] memory executions = new Execution[](2); + // this one will fail + executions[0] = Execution({ target: address(target), value: 0, callData: hex"41414141" }); + // this one will execute + executions[1] = Execution({ target: address(target), value: 0, callData: setValueOnTarget }); + account.executeFromExecutor( + ModeLib.encode(CALLTYPE_BATCH, EXECTYPE_TRY, MODE_DEFAULT, ModePayload.wrap(bytes22(0))), + ExecutionLib.encodeBatch(executions) + ); + + assertEq(target.value(), 1338); + } +} diff --git a/accounts/safe7579/test/ERC7579Compliance/ExecutionsModule.tree b/accounts/safe7579/test/ERC7579Compliance/ExecutionsModule.tree new file mode 100644 index 00000000..eaaa0212 --- /dev/null +++ b/accounts/safe7579/test/ERC7579Compliance/ExecutionsModule.tree @@ -0,0 +1,9 @@ +ExecutionsModuleTest +├── When executing on valid target // implement single, batch and delegatecall +│ └── It should pass +├── When executing single on invalid target //implement single, batch and delegatecall +│ └── It should revert +├── When try executing on valid target // implement single, batch and delegatecall +│ └── It should pass +└── When try executing single on invalid target //implement single, batch and delegatecall + └── It should emit at the correct index diff --git a/accounts/safe7579/test/ERC7579Compliance/Hooks.t.sol b/accounts/safe7579/test/ERC7579Compliance/Hooks.t.sol new file mode 100644 index 00000000..82edc201 --- /dev/null +++ b/accounts/safe7579/test/ERC7579Compliance/Hooks.t.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.0; + +contract HookTest { + function test_WhenExecutingVia4337() external { + // It should execute hook + } + + function test_WhenExecutingViaModule() external { + // It should execute hook + } + + function test_WhenInstallingModule() external { + // It should execute hook + } + + function test_WhenHookReverts() external { + // It should revert execution + } +} diff --git a/accounts/safe7579/test/ERC7579Compliance/Hooks.tree b/accounts/safe7579/test/ERC7579Compliance/Hooks.tree new file mode 100644 index 00000000..5d967a6f --- /dev/null +++ b/accounts/safe7579/test/ERC7579Compliance/Hooks.tree @@ -0,0 +1,9 @@ +HookTest +├── When executing via 4337 // test all execution types +│ └── It should execute hook +├── When executing via module // test all execution types +│ └── It should execute hook +├── When installing module +│ └── It should execute hook +└── When hook reverts + └── It should revert execution diff --git a/accounts/safe7579/test/ERC7579Compliance/ModuleManagement.t.sol b/accounts/safe7579/test/ERC7579Compliance/ModuleManagement.t.sol new file mode 100644 index 00000000..a6a64dd9 --- /dev/null +++ b/accounts/safe7579/test/ERC7579Compliance/ModuleManagement.t.sol @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.0; + +import "./Base.t.sol"; +import "erc7579/lib/ModeLib.sol"; +import { EventEmitter } from "src/utils/DelegatecallTarget.sol"; + +contract ModuleManagementTest is BaseTest { + bytes _data; + + function setUp() public virtual override { + super.setUp(); + } + + function onInstall(bytes calldata data) public override { + assertEq(_data, data); + assertEq(msg.sender, address(account)); + } + + function onUninstall(bytes calldata data) public override { + assertEq(_data, data); + assertEq(msg.sender, address(account)); + } + + function test_WhenInstallingExecutors() external asEntryPoint { + _data = hex"4141414141414141"; + assertFalse(account.isModuleInstalled(2, SELF, "")); + account.installModule(2, SELF, _data); + assertTrue(account.isModuleInstalled(2, SELF, "")); + account.uninstallModule(2, SELF, abi.encode(address(1), _data)); + assertFalse(account.isModuleInstalled(2, SELF, "")); + } + + function test_WhenInstallingValidators() external asEntryPoint { + // It should call onInstall on module + _data = hex"4141414141414141"; + assertFalse(account.isModuleInstalled(1, SELF, "")); + account.installModule(1, SELF, _data); + assertTrue(account.isModuleInstalled(1, SELF, "")); + account.uninstallModule(1, SELF, abi.encode(address(1), _data)); + assertFalse(account.isModuleInstalled(1, SELF, "")); + } + + function test_WhenInstallingFallbackModules() external asEntryPoint { + bytes4 selector = MockTarget.set.selector; + _data = hex"4141414141414141"; + + assertFalse(account.isModuleInstalled(3, SELF, abi.encode(selector))); + account.installModule(3, SELF, abi.encode(selector, CALLTYPE_SINGLE, _data)); + assertTrue(account.isModuleInstalled(3, SELF, abi.encode(selector))); + account.uninstallModule(3, SELF, abi.encode(selector, _data)); + assertFalse(account.isModuleInstalled(3, SELF, abi.encode(selector))); + } + + function test_WhenInstallingHooks() external asEntryPoint { + bytes4 selector = MockTarget.set.selector; + _data = hex"4141414141414141"; + + assertFalse(account.isModuleInstalled(4, SELF, abi.encode(selector))); + account.installModule(4, SELF, abi.encode(selector, _data)); + assertTrue(account.isModuleInstalled(4, SELF, abi.encode(selector))); + account.uninstallModule(4, SELF, abi.encode(selector, _data)); + assertFalse(account.isModuleInstalled(4, SELF, abi.encode(selector))); + } +} diff --git a/accounts/safe7579/test/ERC7579Compliance/ModuleManagement.tree b/accounts/safe7579/test/ERC7579Compliance/ModuleManagement.tree new file mode 100644 index 00000000..fa4c9d68 --- /dev/null +++ b/accounts/safe7579/test/ERC7579Compliance/ModuleManagement.tree @@ -0,0 +1,4 @@ +ModuleManagementTest +└── When installing modules // test all module types + ├── It should call onInstall on module + └── It should add it to module storage diff --git a/accounts/safe7579/test/Launchpad.t.sol b/accounts/safe7579/test/Launchpad.t.sol index d4430948..59cc83db 100644 --- a/accounts/safe7579/test/Launchpad.t.sol +++ b/accounts/safe7579/test/Launchpad.t.sol @@ -75,8 +75,7 @@ contract LaunchpadBase is Test { executors[0] = ISafe7579Init.ModuleInit({ module: address(defaultExecutor), initData: bytes("") }); ISafe7579Init.ModuleInit[] memory fallbacks = new ISafe7579Init.ModuleInit[](0); - ISafe7579Init.ModuleInit memory hook = - ISafe7579Init.ModuleInit({ module: address(0), initData: bytes("") }); + ISafe7579Init.ModuleInit[] memory hooks = new ISafe7579Init.ModuleInit[](0); Safe7579Launchpad.InitData memory initData = Safe7579Launchpad.InitData({ singleton: address(singleton), @@ -89,7 +88,7 @@ contract LaunchpadBase is Test { address(safe7579), executors, fallbacks, - hook, + hooks, Solarray.addresses(makeAddr("attester1"), makeAddr("attester2")), 2 ) diff --git a/accounts/safe7579/test/SafeERC7579.t.sol b/accounts/safe7579/test/SafeERC7579.t.sol index 07123c27..d717e309 100644 --- a/accounts/safe7579/test/SafeERC7579.t.sol +++ b/accounts/safe7579/test/SafeERC7579.t.sol @@ -99,42 +99,4 @@ contract Safe7579Test is LaunchpadBase { 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), abi.encode(MockFallback.target.selector, CALLTYPE_SINGLE, "") - ); - (uint256 ret, address msgSender, address context) = MockFallback(address(safe)).target(1337); - - assertEq(ret, 1337); - assertEq(msgSender, address(safe)); - assertEq(context, address(this)); - - vm.prank(address(safe)); - IERC7579Account(address(safe)).uninstallModule( - 3, address(_fallback), abi.encode(MockFallback.target.selector, CALLTYPE_SINGLE, "") - ); - vm.prank(address(safe)); - IERC7579Account(address(safe)).installModule( - 3, address(_fallback), abi.encode(MockFallback.target.selector, CALLTYPE_STATIC, "") - ); - (ret, msgSender, context) = MockFallback(address(safe)).target(1337); - assertEq(ret, 1337); - assertEq(msgSender, address(safe)); - assertEq(context, address(this)); - - // vm.prank(address(safe)); - // IERC7579Account(address(safe)).installModule( - // 3, - // address(_fallback), - // abi.encode(MockFallback.target2.selector, CALLTYPE_DELEGATECALL, "") - // ); - // (uint256 _ret, address _this, address _msgSender) = - // MockFallback(address(safe)).target2(1337); - // - // assertEq(_ret, 1337); - // assertEq(_this, address(safe)); - } } diff --git a/accounts/safe7579/test/mocks/MockTarget.sol b/accounts/safe7579/test/mocks/MockTarget.sol index f56fb925..e60a33e3 100644 --- a/accounts/safe7579/test/mocks/MockTarget.sol +++ b/accounts/safe7579/test/mocks/MockTarget.sol @@ -7,6 +7,7 @@ contract MockTarget { event Access(address sender); function set(uint256 _value) public returns (uint256) { + if (_value == type(uint256).max) revert(); emit Access(msg.sender); value = _value; return _value; From 82ed685a9167e3058ecefe895f297f36f22a2989 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Wed, 17 Apr 2024 13:41:42 +0700 Subject: [PATCH 45/64] refactor to use DCUtil --- accounts/safe7579/src/core/DCUtil.sol | 2 +- accounts/safe7579/src/core/HookManager.sol | 24 ++++--- accounts/safe7579/src/core/ModuleManager.sol | 70 ++++++++++---------- accounts/safe7579/src/utils/DCUtil.sol | 12 ++-- 4 files changed, 57 insertions(+), 51 deletions(-) diff --git a/accounts/safe7579/src/core/DCUtil.sol b/accounts/safe7579/src/core/DCUtil.sol index a12df061..ead69eda 100644 --- a/accounts/safe7579/src/core/DCUtil.sol +++ b/accounts/safe7579/src/core/DCUtil.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.25; import { Safe7579DCUtil } from "../utils/DCUtil.sol"; import { ISafe, ExecOnSafeLib } from "../lib/ExecOnSafeLib.sol"; -contract DelegateCallUtil { +contract Safe7579DCUtilSetup { using ExecOnSafeLib for ISafe; address internal UTIL; diff --git a/accounts/safe7579/src/core/HookManager.sol b/accounts/safe7579/src/core/HookManager.sol index 14c6b873..75b1c704 100644 --- a/accounts/safe7579/src/core/HookManager.sol +++ b/accounts/safe7579/src/core/HookManager.sol @@ -5,11 +5,12 @@ import { ModuleManager } from "./ModuleManager.sol"; import { IHook, IModule } from "erc7579/interfaces/IERC7579Module.sol"; import { MODULE_TYPE_HOOK } from "erc7579/interfaces/IERC7579Module.sol"; import { ISafe, ExecOnSafeLib } from "../lib/ExecOnSafeLib.sol"; - +import { Safe7579DCUtil, ModuleInstallUtil } from "../utils/DCUtil.sol"; /** * @title reference implementation of HookManager * @author zeroknots.eth | rhinestone.wtf */ + abstract contract HookManager is ModuleManager { using ExecOnSafeLib for ISafe; @@ -32,23 +33,24 @@ abstract contract HookManager is ModuleManager { revert HookAlreadyInstalled(currentHook); } $hookManager[msg.sender][selector] = hook; - ISafe(msg.sender).exec({ - target: hook, - value: 0, - callData: abi.encodeCall(IModule.onInstall, (initData)) + ISafe(msg.sender).execDelegateCall({ + target: UTIL, + callData: abi.encodeCall( + ModuleInstallUtil.installModule, (MODULE_TYPE_HOOK, hook, initData) + ) }); - _emitModuleInstall(MODULE_TYPE_HOOK, hook); } function _uninstallHook(address hook, bytes calldata data) internal virtual { (bytes4 selector, bytes memory initData) = abi.decode(data, (bytes4, bytes)); delete $hookManager[msg.sender][selector]; - ISafe(msg.sender).exec({ - target: hook, - value: 0, - callData: abi.encodeCall(IModule.onUninstall, (initData)) + + ISafe(msg.sender).execDelegateCall({ + target: UTIL, + callData: abi.encodeCall( + ModuleInstallUtil.unInstallModule, (MODULE_TYPE_HOOK, hook, initData) + ) }); - _emitModuleUninstall(MODULE_TYPE_HOOK, hook); } function _isHookInstalled( diff --git a/accounts/safe7579/src/core/ModuleManager.sol b/accounts/safe7579/src/core/ModuleManager.sol index b07709e1..2f7065aa 100644 --- a/accounts/safe7579/src/core/ModuleManager.sol +++ b/accounts/safe7579/src/core/ModuleManager.sol @@ -7,11 +7,12 @@ import { IModule } from "erc7579/interfaces/IERC7579Module.sol"; import { ISafe, ExecOnSafeLib } from "../lib/ExecOnSafeLib.sol"; import { SimulateTxAccessor } from "../utils/DelegatecallTarget.sol"; +import { Safe7579DCUtil, ModuleInstallUtil } from "../utils/DCUtil.sol"; import { Enum } from "@safe-global/safe-contracts/contracts/common/Enum.sol"; import { RegistryAdapter } from "./RegistryAdapter.sol"; import { Receiver } from "erc7579/core/Receiver.sol"; import { AccessControl } from "./AccessControl.sol"; -import { DelegateCallUtil } from "./DCUtil.sol"; +import { Safe7579DCUtil, Safe7579DCUtilSetup } from "./DCUtil.sol"; import { CallType, CALLTYPE_SINGLE, CALLTYPE_DELEGATECALL } from "erc7579/lib/ModeLib.sol"; import { @@ -38,7 +39,7 @@ struct ModuleManagerStorage { * Contract that implements ERC7579 Module compatibility for Safe accounts * @author zeroknots.eth | rhinestone.wtf */ -abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter, DelegateCallUtil { +abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter, Safe7579DCUtilSetup { using ExecOnSafeLib for *; using SentinelListLib for SentinelListLib.SentinelList; using SentinelList4337Lib for SentinelList4337Lib.SentinelList; @@ -78,12 +79,12 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter, Del $validators.push({ account: msg.sender, newEntry: validator }); // Initialize Validator Module via Safe - ISafe(msg.sender).exec({ - target: validator, - value: 0, - callData: abi.encodeCall(IModule.onInstall, (data)) + ISafe(msg.sender).execDelegateCall({ + target: UTIL, + callData: abi.encodeCall( + ModuleInstallUtil.installModule, (MODULE_TYPE_VALIDATOR, validator, data) + ) }); - _emitModuleInstall(MODULE_TYPE_VALIDATOR, validator); } /** @@ -94,12 +95,12 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter, Del $validators.pop({ account: msg.sender, prevEntry: prev, popEntry: validator }); // De-Initialize Validator Module via Safe - ISafe(msg.sender).exec({ - target: validator, - value: 0, - callData: abi.encodeCall(IModule.onUninstall, (disableModuleData)) + ISafe(msg.sender).execDelegateCall({ + target: UTIL, + callData: abi.encodeCall( + ModuleInstallUtil.unInstallModule, (MODULE_TYPE_VALIDATOR, validator, disableModuleData) + ) }); - _emitModuleUninstall(MODULE_TYPE_VALIDATOR, validator); } /** @@ -149,12 +150,12 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter, Del SentinelListLib.SentinelList storage $executors = $moduleManager[msg.sender]._executors; $executors.push(executor); // Initialize Executor Module via Safe - ISafe(msg.sender).exec({ - target: executor, - value: 0, - callData: abi.encodeCall(IModule.onInstall, (data)) + ISafe(msg.sender).execDelegateCall({ + target: UTIL, + callData: abi.encodeCall( + ModuleInstallUtil.installModule, (MODULE_TYPE_EXECUTOR, executor, data) + ) }); - _emitModuleInstall(MODULE_TYPE_EXECUTOR, executor); } function _uninstallExecutor(address executor, bytes calldata data) internal { @@ -162,13 +163,13 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter, Del (address prev, bytes memory disableModuleData) = abi.decode(data, (address, bytes)); $executors.pop(prev, executor); - // De-Initialize Executor Module via Safe - ISafe(msg.sender).exec({ - target: executor, - value: 0, - callData: abi.encodeCall(IModule.onUninstall, (disableModuleData)) + // De-Initialize Validator Module via Safe + ISafe(msg.sender).execDelegateCall({ + target: UTIL, + callData: abi.encodeCall( + ModuleInstallUtil.unInstallModule, (MODULE_TYPE_EXECUTOR, executor, disableModuleData) + ) }); - _emitModuleUninstall(MODULE_TYPE_EXECUTOR, executor); } function _isExecutorInstalled(address executor) internal view virtual returns (bool) { @@ -214,12 +215,12 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter, Del $fallbacks.calltype = calltype; $fallbacks.handler = handler; - ISafe(msg.sender).exec({ - target: handler, - value: 0, - callData: abi.encodeCall(IModule.onInstall, (initData)) + ISafe(msg.sender).execDelegateCall({ + target: UTIL, + callData: abi.encodeCall( + ModuleInstallUtil.installModule, (MODULE_TYPE_FALLBACK, handler, initData) + ) }); - _emitModuleInstall(MODULE_TYPE_FALLBACK, handler); } function _isFallbackHandlerInstalled(bytes4 functionSig) internal view virtual returns (bool) { @@ -233,12 +234,13 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter, Del ModuleManagerStorage storage $mms = $moduleManager[msg.sender]; $mms._fallbacks[functionSig].handler = address(0); // De-Initialize Fallback Module via Safe - ISafe(msg.sender).exec({ - target: handler, - value: 0, - callData: abi.encodeCall(IModule.onUninstall, (initData)) + + ISafe(msg.sender).execDelegateCall({ + target: UTIL, + callData: abi.encodeCall( + ModuleInstallUtil.unInstallModule, (MODULE_TYPE_FALLBACK, handler, initData) + ) }); - _emitModuleUninstall(MODULE_TYPE_FALLBACK, handler); } function _isFallbackHandlerInstalled( @@ -274,7 +276,7 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter, Del if (calltype == CALLTYPE_STATIC) { bytes memory ret = ISafe(msg.sender).execDelegateCallReturn({ - target: address(DCTARGET), + target: UTIL, callData: abi.encodeCall( SimulateTxAccessor.simulate, (handler, 0, abi.encodePacked(callData, _msgSender()), Enum.Operation.Call) diff --git a/accounts/safe7579/src/utils/DCUtil.sol b/accounts/safe7579/src/utils/DCUtil.sol index e94b6bff..0e42e642 100644 --- a/accounts/safe7579/src/utils/DCUtil.sol +++ b/accounts/safe7579/src/utils/DCUtil.sol @@ -1,5 +1,7 @@ import { Execution } from "erc7579/interfaces/IERC7579Account.sol"; import { IModule as IERC7579Module } from "erc7579/interfaces/IERC7579Module.sol"; +import { SimulateTxAccessor } from + "@safe-global/safe-contracts/contracts/accessors/SimulateTxAccessor.sol"; contract ModuleInstallUtil { event ModuleInstalled(uint256 moduleTypeId, address module); @@ -7,23 +9,23 @@ contract ModuleInstallUtil { function installModule( uint256 moduleTypeId, - IERC7579Module module, + address module, bytes calldata initData ) external { - module.onInstall(initData); + IERC7579Module(module).onInstall(initData); emit ModuleInstalled(moduleTypeId, address(module)); } function unInstallModule( uint256 moduleTypeId, - IERC7579Module module, + address module, bytes calldata initData ) external { - module.onUninstall(initData); + IERC7579Module(module).onUninstall(initData); emit ModuleUninstalled(moduleTypeId, address(module)); } } @@ -97,4 +99,4 @@ contract BatchedExecUtil { } } -contract Safe7579DCUtil is ModuleInstallUtil, BatchedExecUtil { } +contract Safe7579DCUtil is ModuleInstallUtil, BatchedExecUtil, SimulateTxAccessor { } From 687753843c7044a1e3f2bff4721f2bda2d951129 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Thu, 18 Apr 2024 14:14:34 +0700 Subject: [PATCH 46/64] refactor hooks --- accounts/safe7579/src/SafeERC7579.sol | 161 +++++++-- .../safe7579/src/core/ExecutionHelper.sol | 147 +++++++++ .../safe7579/src/core/ExecutionHelper.sol.bak | 299 ----------------- accounts/safe7579/src/core/HookManager.sol | 38 ++- accounts/safe7579/src/core/ModuleManager.sol | 69 ++-- .../safe7579/src/core/RegistryAdapter.sol | 9 +- .../src/core/{DCUtil.sol => SetupDCUtil.sol} | 3 - accounts/safe7579/src/lib/ExecOnSafeLib.sol | 311 ------------------ accounts/safe7579/src/utils/DCUtil.sol | 34 +- .../safe7579/src/utils/DelegatecallTarget.sol | 79 ----- .../ERC7579Compliance/Executions4337.t.sol | 2 +- .../ERC7579Compliance/ModuleManagement.t.sol | 1 - 12 files changed, 378 insertions(+), 775 deletions(-) create mode 100644 accounts/safe7579/src/core/ExecutionHelper.sol delete mode 100644 accounts/safe7579/src/core/ExecutionHelper.sol.bak rename accounts/safe7579/src/core/{DCUtil.sol => SetupDCUtil.sol} (70%) delete mode 100644 accounts/safe7579/src/lib/ExecOnSafeLib.sol delete mode 100644 accounts/safe7579/src/utils/DelegatecallTarget.sol diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index 30d3a31d..53b210c9 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.23; import { IERC7579Account, Execution } from "erc7579/interfaces/IERC7579Account.sol"; import { IMSA } from "erc7579/interfaces/IMSA.sol"; -import "./lib/ExecOnSafeLib.sol"; import { CallType, ExecType, @@ -51,11 +50,9 @@ contract SafeERC7579 is Initializer, IMSA { - using ExecOnSafeLib for ISafe; using UserOperationLib for PackedUserOperation; using ModeLib for ModeCode; using ExecutionLib for bytes; - using HookedExecOnSafeLib for ISafe; error Unsupported(); @@ -68,49 +65,80 @@ contract SafeERC7579 is // keccak256("safeSignature(bytes32,bytes32,bytes,bytes)"); bytes4 private constant SAFE_SIGNATURE_MAGIC_VALUE = 0x5fd7e97d; - function _execute( + /** + * @inheritdoc IERC7579Account + */ + function execute( ModeCode mode, bytes calldata executionCalldata ) - internal - returns (bytes[] memory returnData) + external + payable + override + onlyEntryPointOrSelf { CallType callType; ExecType execType; - address hook = getActiveHook(msg.sig); // solhint-disable-next-line no-inline-assembly assembly { callType := mode execType := shl(8, mode) } - + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* REVERT ON FAILED EXEC */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + ISafe safe = ISafe(msg.sender); if (execType == EXECTYPE_DEFAULT) { - returnData = HookedExecOnSafeLib.hookedExec(executionCalldata, callType, hook); - } else if (execType == EXECTYPE_TRY) { - returnData = HookedExecOnSafeLib.hookedTryExec(executionCalldata, callType, hook); + // DEFAULT EXEC & SINGLE CALL + if (callType == CALLTYPE_BATCH) { + Execution[] calldata executions = executionCalldata.decodeBatch(); + _exec(safe, executions); + } + // DEFAULT EXEC & BATCH CALL + else if (callType == CALLTYPE_SINGLE) { + (address target, uint256 value, bytes calldata callData) = + executionCalldata.decodeSingle(); + _exec(safe, target, value, callData); + } + // DEFAULT EXEC & DELEGATECALL + else if (callType == CALLTYPE_DELEGATECALL) { + address target = address(bytes20(executionCalldata[:20])); + bytes calldata callData = executionCalldata[20:]; + _delegatecall(safe, target, callData); + } + // handle unsupported calltype + else { + revert UnsupportedCallType(callType); + } + } + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* TRY EXEC */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + else if (execType == EXECTYPE_TRY) { + if (callType == CALLTYPE_BATCH) { + Execution[] calldata executions = executionCalldata.decodeBatch(); + _tryExec(safe, executions); + } else if (callType == CALLTYPE_SINGLE) { + (address target, uint256 value, bytes calldata callData) = + executionCalldata.decodeSingle(); + _tryExec(safe, target, value, callData); + } else if (callType == CALLTYPE_DELEGATECALL) { + address target = address(bytes20(executionCalldata[:20])); + bytes calldata callData = executionCalldata[20:]; + _tryDelegatecall(safe, target, callData); + } else { + revert UnsupportedCallType(callType); + } } - // account reverts when using unsupported execution type + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* HANDLE UNSUPPORTED EXEC TYPE */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ else { revert UnsupportedExecType(execType); } } - /** - * @inheritdoc IERC7579Account - */ - function execute( - ModeCode mode, - bytes calldata executionCalldata - ) - external - payable - override - onlyEntryPointOrSelf - { - _execute(mode, executionCalldata); - } - /** * @inheritdoc IERC7579Account */ @@ -123,9 +151,72 @@ contract SafeERC7579 is override onlyExecutorModule withRegistry(msg.sender, MODULE_TYPE_EXECUTOR) - returns (bytes[] memory returnData) + returns (bytes[] memory returnDatas) { - return _execute(mode, executionCalldata); + CallType callType; + ExecType execType; + + // solhint-disable-next-line no-inline-assembly + assembly { + callType := mode + execType := shl(8, mode) + } + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* REVERT ON FAILED EXEC */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + ISafe safe = ISafe(msg.sender); + if (execType == EXECTYPE_DEFAULT) { + // DEFAULT EXEC & SINGLE CALL + if (callType == CALLTYPE_BATCH) { + Execution[] calldata executions = executionCalldata.decodeBatch(); + returnDatas = _execReturn(safe, executions); + } + // DEFAULT EXEC & BATCH CALL + else if (callType == CALLTYPE_SINGLE) { + (address target, uint256 value, bytes calldata callData) = + executionCalldata.decodeSingle(); + returnDatas = new bytes[](1); + returnDatas[0] = _execReturn(safe, target, value, callData); + } + // DEFAULT EXEC & DELEGATECALL + else if (callType == CALLTYPE_DELEGATECALL) { + address target = address(bytes20(executionCalldata[:20])); + bytes calldata callData = executionCalldata[20:]; + returnDatas = new bytes[](1); + returnDatas[0] = _delegatecallReturn(safe, target, callData); + } + // handle unsupported calltype + else { + revert UnsupportedCallType(callType); + } + } + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* TRY EXEC */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + else if (execType == EXECTYPE_TRY) { + if (callType == CALLTYPE_BATCH) { + Execution[] calldata executions = executionCalldata.decodeBatch(); + (, returnDatas) = _tryExecReturn(safe, executions); + } else if (callType == CALLTYPE_SINGLE) { + (address target, uint256 value, bytes calldata callData) = + executionCalldata.decodeSingle(); + returnDatas = new bytes[](1); + returnDatas[0] = _tryExecReturn(safe, target, value, callData); + } else if (callType == CALLTYPE_DELEGATECALL) { + address target = address(bytes20(executionCalldata[:20])); + bytes calldata callData = executionCalldata[20:]; + returnDatas = new bytes[](1); + returnDatas[0] = _tryDelegatecallReturn(safe, target, callData); + } else { + revert UnsupportedCallType(callType); + } + } + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* HANDLE UNSUPPORTED EXEC TYPE */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + else { + revert UnsupportedExecType(execType); + } } function executeUserOp( @@ -165,7 +256,8 @@ contract SafeERC7579 is return _validateSignatures(userOp); } else { // bubble up the return value of the validator module - bytes memory retData = ISafe(msg.sender).execReturn({ + bytes memory retData = _execReturn({ + safe: ISafe(msg.sender), target: validator, value: 0, callData: abi.encodeCall(IValidator.validateUserOp, (userOp, userOpHash)) @@ -175,7 +267,12 @@ contract SafeERC7579 is // pay prefund if (missingAccountFunds != 0) { - ISafe(msg.sender).exec({ target: entryPoint(), value: missingAccountFunds, callData: "" }); + _exec({ + safe: ISafe(msg.sender), + target: entryPoint(), + value: missingAccountFunds, + callData: "" + }); } } @@ -262,14 +359,12 @@ contract SafeERC7579 is { // address hook = getActiveHook(); address hook = address(0); - bytes memory hookPreContext = ISafe(msg.sender).preHook(hook); if (moduleType == MODULE_TYPE_VALIDATOR) _installValidator(module, initData); else if (moduleType == MODULE_TYPE_EXECUTOR) _installExecutor(module, initData); else if (moduleType == MODULE_TYPE_FALLBACK) _installFallbackHandler(module, initData); else if (moduleType == MODULE_TYPE_HOOK) _installHook(module, initData); else revert UnsupportedModuleType(moduleType); - ISafe(msg.sender).postHook(hook, hookPreContext, true, ""); } /** diff --git a/accounts/safe7579/src/core/ExecutionHelper.sol b/accounts/safe7579/src/core/ExecutionHelper.sol new file mode 100644 index 00000000..5d31a777 --- /dev/null +++ b/accounts/safe7579/src/core/ExecutionHelper.sol @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import { Safe7579DCUtilSetup } from "./SetupDCUtil.sol"; +import { BatchedExecUtil } from "../utils/DCUtil.sol"; +import { Execution } from "erc7579/interfaces/IERC7579Account.sol"; +import { ISafe } from "../interfaces/ISafe.sol"; + +contract ExecutionHelper is Safe7579DCUtilSetup { + event TryExecutionFailed(ISafe safe, uint256 numberInBatch); + event TryExecutionsFailed(ISafe safe, bool[] success); + + error ExecutionFailed(); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EXEC - REVERT ON FAIL */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + function _exec(ISafe safe, Execution[] calldata executions) internal { + _delegatecall({ + safe: safe, + target: UTIL, + callData: abi.encodeCall(BatchedExecUtil.execute, executions) + }); + } + + function _exec(ISafe safe, address target, uint256 value, bytes memory callData) internal { + bool success = safe.execTransactionFromModule(target, value, callData, 0); + if (!success) revert ExecutionFailed(); + } + + function _delegatecall(ISafe safe, address target, bytes memory callData) internal { + bool success = safe.execTransactionFromModule(target, 0, callData, 1); + if (!success) revert ExecutionFailed(); + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EXEC - REVERT ON FAIL & Return Values */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + function _execReturn( + ISafe safe, + Execution[] calldata executions + ) + internal + returns (bytes[] memory retDatas) + { + bytes memory tmp = _delegatecallReturn({ + safe: safe, + target: UTIL, + callData: abi.encodeCall(BatchedExecUtil.executeReturn, executions) + }); + retDatas = abi.decode(tmp, (bytes[])); + } + + function _execReturn( + ISafe safe, + address target, + uint256 value, + bytes memory callData + ) + internal + returns (bytes memory retData) + { + bool success; + (success, retData) = safe.execTransactionFromModuleReturnData(target, value, callData, 0); + if (!success) revert ExecutionFailed(); + } + + function _delegatecallReturn( + ISafe safe, + address target, + bytes memory callData + ) + internal + returns (bytes memory retData) + { + bool success; + (success, retData) = safe.execTransactionFromModuleReturnData(target, 0, callData, 1); + if (!success) revert ExecutionFailed(); + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EXEC - TRY */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + function _tryExec(ISafe safe, Execution[] calldata executions) internal { + _tryDelegatecall({ + safe: safe, + target: UTIL, + callData: abi.encodeCall(BatchedExecUtil.tryExecute, executions) + }); + } + + function _tryExec(ISafe safe, address target, uint256 value, bytes memory callData) internal { + bool success = safe.execTransactionFromModule(target, value, callData, 0); + if (!success) emit TryExecutionFailed(safe, 0); + } + + function _tryDelegatecall(ISafe safe, address target, bytes memory callData) internal { + bool success = safe.execTransactionFromModule(target, 0, callData, 1); + if (!success) emit TryExecutionFailed(safe, 0); + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EXEC - TRY & Return Values */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + function _tryExecReturn( + ISafe safe, + Execution[] calldata executions + ) + internal + returns (bool[] memory success, bytes[] memory retDatas) + { + bytes memory tmp = _tryDelegatecallReturn({ + safe: safe, + target: UTIL, + callData: abi.encodeCall(BatchedExecUtil.tryExecuteReturn, executions) + }); + (success, retDatas) = abi.decode(tmp, (bool[], bytes[])); + } + + function _tryExecReturn( + ISafe safe, + address target, + uint256 value, + bytes memory callData + ) + internal + returns (bytes memory retData) + { + bool success; + (success, retData) = safe.execTransactionFromModuleReturnData(target, value, callData, 0); + if (!success) emit TryExecutionFailed(safe, 0); + } + + function _tryDelegatecallReturn( + ISafe safe, + address target, + bytes memory callData + ) + internal + returns (bytes memory retData) + { + bool success; + (success, retData) = safe.execTransactionFromModuleReturnData(target, 0, callData, 1); + if (!success) emit TryExecutionFailed(safe, 0); + } +} diff --git a/accounts/safe7579/src/core/ExecutionHelper.sol.bak b/accounts/safe7579/src/core/ExecutionHelper.sol.bak deleted file mode 100644 index 6a29a2b8..00000000 --- a/accounts/safe7579/src/core/ExecutionHelper.sol.bak +++ /dev/null @@ -1,299 +0,0 @@ -// 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"; -import { - SimulateTxAccessor, - Enum -} from "@safe-global/safe-contracts/contracts/accessors/SimulateTxAccessor.sol"; - -/** - * @title Helper contract to execute transactions from a safe - * - * @author zeroknots.eth - */ -abstract contract ExecutionHelper { - error ExecutionFailed(); - - event TryExecutionFailed(address safe, uint256 numberInBatch); - - SimulateTxAccessor private immutable SIMULATETX; - - constructor() { - SIMULATETX = new SimulateTxAccessor(); - } - - ///////////////////////////////////////////////////// - // DEFAULT EXEC TYPE - //////////////////////////////////////////////////// - - /** - * 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); - } - } - - function _executeDelegateCall(address safe, address target, bytes calldata callData) internal { - bool success = ISafe(safe).execTransactionFromModule(target, 0, callData, 1); - if (!success) revert ExecutionFailed(); - } - - function _executeDelegateCallMemory( - address safe, - address target, - bytes memory callData - ) - internal - { - bool success = ISafe(safe).execTransactionFromModule(target, 0, callData, 1); - if (!success) revert ExecutionFailed(); - } - - function _executeDelegateCallReturnData( - address safe, - address target, - bytes calldata callData - ) - internal - returns (bytes memory returnData) - { - bool success; - (success, returnData) = - ISafe(safe).execTransactionFromModuleReturnData(target, 0, callData, 1); - 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 - * @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); - } - } - - ///////////////////////////////////////////////////// - // TRY EXEC TYPE - //////////////////////////////////////////////////// - - /** - * Try 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 _tryExecute( - address safe, - address target, - uint256 value, - bytes memory callData - ) - internal - { - bool success = ISafe(safe).execTransactionFromModule(target, value, callData, 0); - if (!success) emit TryExecutionFailed(safe, 0); - } - - /** - * Try 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 _tryExecuteReturnData( - 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) emit TryExecutionFailed(safe, 0); - } - - /** - * Try 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 _tryExecute(address safe, Execution[] calldata executions) internal { - uint256 length = executions.length; - for (uint256 i; i < length; i++) { - Execution calldata execution = executions[i]; - - bool success = ISafe(safe).execTransactionFromModule( - execution.target, execution.value, execution.callData, 0 - ); - if (!success) emit TryExecutionFailed(safe, i); - } - } - - function _tryExecuteDelegateCall( - address safe, - address target, - bytes calldata callData - ) - internal - { - bool success = ISafe(safe).execTransactionFromModule(target, 0, callData, 1); - if (!success) emit TryExecutionFailed(safe, 0); - } - - function _tryExecuteDelegateCallReturnData( - address safe, - address target, - bytes calldata callData - ) - internal - returns (bytes memory returnData) - { - bool success; - (success, returnData) = - ISafe(safe).execTransactionFromModuleReturnData(target, 0, callData, 1); - if (!success) emit TryExecutionFailed(safe, 0); - } - - /** - * 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 _tryExecuteReturnData( - 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]; - - bool success; - (success, returnDatas[i]) = ISafe(safe).execTransactionFromModuleReturnData( - execution.target, execution.value, execution.callData, 0 - ); - if (!success) emit TryExecutionFailed(safe, i); - } - } - - ///////////////////////////////////////////////////// - // STATICCALL - //////////////////////////////////////////////////// - - /** - * Execute staticcall on Safe, get return value from call - * Safe does not implement Enum.Operation for staticcall. - * we are using a trick, of nudging the Safe account to delegatecall to the SimulateTxAccessor, - * and call simulate() - * @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 _executeStaticReturnData( - address safe, - address target, - uint256 value, - bytes memory callData - ) - internal - returns (bytes memory returnData) - { - bool success; - // this is the return data from the Safe.execTransactionFromModuleReturnData call. NOT the - // simulation - (success, returnData) = ISafe(safe).execTransactionFromModuleReturnData( - address(SIMULATETX), - 0, - abi.encodeCall(SIMULATETX.simulate, (target, value, callData, Enum.Operation.Call)), - 1 - ); - if (!success) revert ExecutionFailed(); - // decode according to simulate() return values - (, success, returnData) = abi.decode(returnData, (uint256, bool, bytes)); - if (!success) revert ExecutionFailed(); - } -} diff --git a/accounts/safe7579/src/core/HookManager.sol b/accounts/safe7579/src/core/HookManager.sol index 75b1c704..6c6b60b0 100644 --- a/accounts/safe7579/src/core/HookManager.sol +++ b/accounts/safe7579/src/core/HookManager.sol @@ -1,24 +1,45 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.23; -import { ModuleManager } from "./ModuleManager.sol"; import { IHook, IModule } from "erc7579/interfaces/IERC7579Module.sol"; +import { ISafe } from "../interfaces/ISafe.sol"; import { MODULE_TYPE_HOOK } from "erc7579/interfaces/IERC7579Module.sol"; -import { ISafe, ExecOnSafeLib } from "../lib/ExecOnSafeLib.sol"; import { Safe7579DCUtil, ModuleInstallUtil } from "../utils/DCUtil.sol"; /** * @title reference implementation of HookManager * @author zeroknots.eth | rhinestone.wtf */ -abstract contract HookManager is ModuleManager { - using ExecOnSafeLib for ISafe; - +abstract contract HookManager { + mapping(address smartAccount => address globalHook) internal $globalHook; mapping(address smartAccount => mapping(bytes4 => address hook)) internal $hookManager; error HookPostCheckFailed(); error HookAlreadyInstalled(address currentHook); + enum HookType { + GLOBAL, + SIG + } + + modifier withSelectorHook(bytes4 hookSig) { + address hook = $hookManager[msg.sender][hookSig]; + bool enabled = hook != address(0); + bytes memory _data; + // if (enabled) _data = ISafe(msg.sender).preHook({ withHook: hook }); + _; + // if (enabled) ISafe(msg.sender).postHook({ withHook: hook, hookPreContext: _data }); + } + + modifier withGlobalHook() { + address hook = $globalHook[msg.sender]; + bool enabled = hook != address(0); + bytes memory _data; + // if (enabled) _data = ISafe(msg.sender).preHook({ withHook: hook }); + _; + // if (enabled) ISafe(msg.sender).postHook({ withHook: hook, hookPreContext: _data }); + } + function _installHook( address hook, bytes calldata data @@ -33,7 +54,9 @@ abstract contract HookManager is ModuleManager { revert HookAlreadyInstalled(currentHook); } $hookManager[msg.sender][selector] = hook; - ISafe(msg.sender).execDelegateCall({ + + _delegatecall({ + safe: ISafe(msg.sender), target: UTIL, callData: abi.encodeCall( ModuleInstallUtil.installModule, (MODULE_TYPE_HOOK, hook, initData) @@ -45,7 +68,8 @@ abstract contract HookManager is ModuleManager { (bytes4 selector, bytes memory initData) = abi.decode(data, (bytes4, bytes)); delete $hookManager[msg.sender][selector]; - ISafe(msg.sender).execDelegateCall({ + _delegatecall({ + safe: ISafe(msg.sender), target: UTIL, callData: abi.encodeCall( ModuleInstallUtil.unInstallModule, (MODULE_TYPE_HOOK, hook, initData) diff --git a/accounts/safe7579/src/core/ModuleManager.sol b/accounts/safe7579/src/core/ModuleManager.sol index 2f7065aa..6a0e0350 100644 --- a/accounts/safe7579/src/core/ModuleManager.sol +++ b/accounts/safe7579/src/core/ModuleManager.sol @@ -4,15 +4,17 @@ 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 { ISafe, ExecOnSafeLib } from "../lib/ExecOnSafeLib.sol"; -import { SimulateTxAccessor } from "../utils/DelegatecallTarget.sol"; +import { SimulateTxAccessor } from "../utils/DCUtil.sol"; +import { ISafe } from "../interfaces/ISafe.sol"; import { Safe7579DCUtil, ModuleInstallUtil } from "../utils/DCUtil.sol"; import { Enum } from "@safe-global/safe-contracts/contracts/common/Enum.sol"; import { RegistryAdapter } from "./RegistryAdapter.sol"; import { Receiver } from "erc7579/core/Receiver.sol"; import { AccessControl } from "./AccessControl.sol"; -import { Safe7579DCUtil, Safe7579DCUtilSetup } from "./DCUtil.sol"; +import { HookManager } from "./HookManager.sol"; +import { ExecutionHelper } from "./ExecutionHelper.sol"; +import { Safe7579DCUtil, Safe7579DCUtilSetup } from "./SetupDCUtil.sol"; import { CallType, CALLTYPE_SINGLE, CALLTYPE_DELEGATECALL } from "erc7579/lib/ModeLib.sol"; import { @@ -39,8 +41,7 @@ struct ModuleManagerStorage { * Contract that implements ERC7579 Module compatibility for Safe accounts * @author zeroknots.eth | rhinestone.wtf */ -abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter, Safe7579DCUtilSetup { - using ExecOnSafeLib for *; +abstract contract ModuleManager is HookManager, AccessControl, Receiver, RegistryAdapter { using SentinelListLib for SentinelListLib.SentinelList; using SentinelList4337Lib for SentinelList4337Lib.SentinelList; @@ -79,7 +80,8 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter, Saf $validators.push({ account: msg.sender, newEntry: validator }); // Initialize Validator Module via Safe - ISafe(msg.sender).execDelegateCall({ + _delegatecall({ + safe: ISafe(msg.sender), target: UTIL, callData: abi.encodeCall( ModuleInstallUtil.installModule, (MODULE_TYPE_VALIDATOR, validator, data) @@ -95,7 +97,8 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter, Saf $validators.pop({ account: msg.sender, prevEntry: prev, popEntry: validator }); // De-Initialize Validator Module via Safe - ISafe(msg.sender).execDelegateCall({ + _delegatecall({ + safe: ISafe(msg.sender), target: UTIL, callData: abi.encodeCall( ModuleInstallUtil.unInstallModule, (MODULE_TYPE_VALIDATOR, validator, disableModuleData) @@ -150,7 +153,8 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter, Saf SentinelListLib.SentinelList storage $executors = $moduleManager[msg.sender]._executors; $executors.push(executor); // Initialize Executor Module via Safe - ISafe(msg.sender).execDelegateCall({ + _delegatecall({ + safe: ISafe(msg.sender), target: UTIL, callData: abi.encodeCall( ModuleInstallUtil.installModule, (MODULE_TYPE_EXECUTOR, executor, data) @@ -164,7 +168,8 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter, Saf $executors.pop(prev, executor); // De-Initialize Validator Module via Safe - ISafe(msg.sender).execDelegateCall({ + _delegatecall({ + safe: ISafe(msg.sender), target: UTIL, callData: abi.encodeCall( ModuleInstallUtil.unInstallModule, (MODULE_TYPE_EXECUTOR, executor, disableModuleData) @@ -215,7 +220,8 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter, Saf $fallbacks.calltype = calltype; $fallbacks.handler = handler; - ISafe(msg.sender).execDelegateCall({ + _delegatecall({ + safe: ISafe(msg.sender), target: UTIL, callData: abi.encodeCall( ModuleInstallUtil.installModule, (MODULE_TYPE_FALLBACK, handler, initData) @@ -234,8 +240,8 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter, Saf ModuleManagerStorage storage $mms = $moduleManager[msg.sender]; $mms._fallbacks[functionSig].handler = address(0); // De-Initialize Fallback Module via Safe - - ISafe(msg.sender).execDelegateCall({ + _delegatecall({ + safe: ISafe(msg.sender), target: UTIL, callData: abi.encodeCall( ModuleInstallUtil.unInstallModule, (MODULE_TYPE_FALLBACK, handler, initData) @@ -265,6 +271,7 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter, Saf fallback(bytes calldata callData) external payable + virtual override(Receiver) receiverFallback returns (bytes memory fallbackRet) @@ -273,24 +280,24 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter, Saf address handler = $fallbackHandler.handler; CallType calltype = $fallbackHandler.calltype; if (handler == address(0)) revert NoFallbackHandler(msg.sig); - - if (calltype == CALLTYPE_STATIC) { - bytes memory ret = ISafe(msg.sender).execDelegateCallReturn({ - target: UTIL, - callData: abi.encodeCall( - SimulateTxAccessor.simulate, - (handler, 0, abi.encodePacked(callData, _msgSender()), Enum.Operation.Call) - ) - }); - (,, fallbackRet) = abi.decode(ret, (uint256, bool, bytes)); - return fallbackRet; - } - if (calltype == CALLTYPE_SINGLE) { - return ISafe(msg.sender).execReturn({ - target: handler, - value: 0, - callData: abi.encodePacked(callData, _msgSender()) - }); - } + // + // if (calltype == CALLTYPE_STATIC) { + // bytes memory ret = ISafe(msg.sender).execDelegateCallReturn({ + // target: UTIL, + // callData: abi.encodeCall( + // SimulateTxAccessor.simulate, + // (handler, 0, abi.encodePacked(callData, _msgSender()), Enum.Operation.Call) + // ) + // }); + // (,, fallbackRet) = abi.decode(ret, (uint256, bool, bytes)); + // return fallbackRet; + // } + // if (calltype == CALLTYPE_SINGLE) { + // return ISafe(msg.sender).execReturn({ + // target: handler, + // value: 0, + // callData: abi.encodePacked(callData, _msgSender()) + // }); + // } } } diff --git a/accounts/safe7579/src/core/RegistryAdapter.sol b/accounts/safe7579/src/core/RegistryAdapter.sol index f9ab084c..9c6708f4 100644 --- a/accounts/safe7579/src/core/RegistryAdapter.sol +++ b/accounts/safe7579/src/core/RegistryAdapter.sol @@ -2,11 +2,9 @@ pragma solidity ^0.8.23; import { IERC7484 } from "../interfaces/IERC7484.sol"; -import { ISafe, ExecOnSafeLib } from "../lib/ExecOnSafeLib.sol"; - -abstract contract RegistryAdapter { - using ExecOnSafeLib for *; +import "./ExecutionHelper.sol"; +abstract contract RegistryAdapter is ExecutionHelper { event ERC7484RegistryConfigured(address indexed smartAccount, address indexed registry); mapping(address smartAccount => IERC7484 registry) internal $registry; @@ -27,7 +25,8 @@ abstract contract RegistryAdapter { internal { $registry[msg.sender] = registry; - ISafe(msg.sender).exec({ + _exec({ + safe: ISafe(msg.sender), target: address(registry), value: 0, callData: abi.encodeCall(IERC7484.trustAttesters, (threshold, attesters)) diff --git a/accounts/safe7579/src/core/DCUtil.sol b/accounts/safe7579/src/core/SetupDCUtil.sol similarity index 70% rename from accounts/safe7579/src/core/DCUtil.sol rename to accounts/safe7579/src/core/SetupDCUtil.sol index ead69eda..359235f7 100644 --- a/accounts/safe7579/src/core/DCUtil.sol +++ b/accounts/safe7579/src/core/SetupDCUtil.sol @@ -2,11 +2,8 @@ pragma solidity ^0.8.25; import { Safe7579DCUtil } from "../utils/DCUtil.sol"; -import { ISafe, ExecOnSafeLib } from "../lib/ExecOnSafeLib.sol"; contract Safe7579DCUtilSetup { - using ExecOnSafeLib for ISafe; - address internal UTIL; constructor() { diff --git a/accounts/safe7579/src/lib/ExecOnSafeLib.sol b/accounts/safe7579/src/lib/ExecOnSafeLib.sol deleted file mode 100644 index 77358939..00000000 --- a/accounts/safe7579/src/lib/ExecOnSafeLib.sol +++ /dev/null @@ -1,311 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.23; - -import { Execution } from "erc7579/interfaces/IERC7579Account.sol"; -import { ExecutionLib } from "erc7579/lib/ExecutionLib.sol"; -import { ISafe } from "../interfaces/ISafe.sol"; - -import { - CallType, - CALLTYPE_SINGLE, - CALLTYPE_BATCH, - CALLTYPE_DELEGATECALL -} from "erc7579/lib/ModeLib.sol"; - -error ExecutionFailed(); - -event TryExecutionFailed(ISafe safe, uint256 numberInBatch); - -error UnsupportedCallType(CallType calltype); - -library ExecOnSafeLib { - function exec(ISafe safe, address target, uint256 value, bytes memory callData) internal { - bool success = safe.execTransactionFromModule(target, value, callData, 0); - if (!success) revert ExecutionFailed(); - } - - function exec(ISafe safe, Execution[] calldata executions) internal { - uint256 length = executions.length; - for (uint256 i; i < length; i++) { - Execution calldata execution = executions[i]; - exec({ - safe: safe, - target: execution.target, - value: execution.value, - callData: execution.callData - }); - } - } - - function execDelegateCall(ISafe safe, address target, bytes memory callData) internal { - bool success = safe.execTransactionFromModule(target, 0, callData, 1); - if (!success) revert ExecutionFailed(); - } - - function execReturn( - ISafe safe, - address target, - uint256 value, - bytes memory callData - ) - internal - returns (bytes memory returnData) - { - bool success; - (success, returnData) = safe.execTransactionFromModuleReturnData(target, value, callData, 0); - if (!success) revert ExecutionFailed(); - } - - function execReturn( - ISafe 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] = execReturn({ - safe: safe, - target: execution.target, - value: execution.value, - callData: execution.callData - }); - } - } - - function execDelegateCallReturn( - ISafe safe, - address target, - bytes memory callData - ) - internal - returns (bytes memory returnData) - { - bool success; - (success, returnData) = safe.execTransactionFromModuleReturnData(target, 0, callData, 1); - if (!success) revert ExecutionFailed(); - } -} - -library TryExecOnSafeLib { - /** - * Try 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 tryExec(ISafe safe, address target, uint256 value, bytes memory callData) internal { - bool success = safe.execTransactionFromModule(target, value, callData, 0); - if (!success) emit TryExecutionFailed(safe, 0); - } - - /** - * Try 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 success boolean if the call was successful - * @return returnData data returned from the call - */ - function tryExecReturn( - ISafe safe, - address target, - uint256 value, - bytes memory callData - ) - internal - returns (bool success, bytes memory returnData) - { - (success, returnData) = safe.execTransactionFromModuleReturnData(target, value, callData, 0); - if (!success) emit TryExecutionFailed(safe, 0); - } - - /** - * Try 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 tryExec(ISafe safe, Execution[] calldata executions) internal returns (bool success) { - uint256 length = executions.length; - success = true; - for (uint256 i; i < length; i++) { - Execution calldata execution = executions[i]; - - bool _success = safe.execTransactionFromModule( - execution.target, execution.value, execution.callData, 0 - ); - if (_success == false) { - emit TryExecutionFailed(safe, i); - if (success == true) success = false; - } - } - } - - function tryExecDelegateCall(ISafe safe, address target, bytes calldata callData) internal { - bool success = safe.execTransactionFromModule(target, 0, callData, 1); - if (!success) emit TryExecutionFailed(safe, 0); - } - - function tryExecDelegateCallReturn( - ISafe safe, - address target, - bytes calldata callData - ) - internal - returns (bool success, bytes memory returnData) - { - (success, returnData) = safe.execTransactionFromModuleReturnData(target, 0, callData, 1); - if (!success) emit TryExecutionFailed(safe, 0); - } - - /** - * 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 success boolean if the call was successful - * @return returnDatas array returned datas from the batched calls - */ - function tryExecReturn( - ISafe safe, - Execution[] calldata executions - ) - internal - returns (bool success, bytes[] memory returnDatas) - { - uint256 length = executions.length; - returnDatas = new bytes[](length); - for (uint256 i; i < length; i++) { - Execution calldata execution = executions[i]; - - bool _success = safe.execTransactionFromModule( - execution.target, execution.value, execution.callData, 0 - ); - if (_success == false) { - emit TryExecutionFailed(safe, i); - if (success == true) success = false; - } - } - } -} - -import { IHook } from "erc7579/interfaces/IERC7579Module.sol"; - -library HookedExecOnSafeLib { - using ExecOnSafeLib for ISafe; - using TryExecOnSafeLib for ISafe; - using ExecutionLib for bytes; - - function preHook(ISafe safe, address withHook) internal returns (bytes memory hookPreContext) { - if (withHook == address(0)) return ""; - hookPreContext = abi.decode( - safe.execReturn({ - target: withHook, - value: 0, - callData: abi.encodeCall(IHook.preCheck, (msg.sender, msg.value, msg.data)) - }), - (bytes) - ); - } - - function postHook( - ISafe safe, - address withHook, - bytes memory hookPreContext, - bool excutionSuccess, - bytes memory executionReturnValue - ) - internal - { - if (withHook == address(0)) return; - safe.execReturn({ - target: withHook, - value: 0, - callData: abi.encodeCall( - IHook.postCheck, (hookPreContext, excutionSuccess, executionReturnValue) - ) - }); - } - - function hookedExec( - bytes calldata executionCalldata, - CallType callType, - address hook - ) - internal - returns (bytes[] memory retDatas) - { - ISafe safe = ISafe(msg.sender); - bool hookEnabled = hook != address(0); - bytes memory preHookContext; - if (hookEnabled) preHookContext = preHook(safe, hook); - - if (callType == CALLTYPE_BATCH) { - Execution[] calldata executions = executionCalldata.decodeBatch(); - retDatas = safe.execReturn(executions); - } else if (callType == CALLTYPE_SINGLE) { - (address target, uint256 value, bytes calldata callData) = - executionCalldata.decodeSingle(); - retDatas = new bytes[](1); - retDatas[0] = safe.execReturn(target, value, callData); - } else if (callType == CALLTYPE_DELEGATECALL) { - address target = address(bytes20(executionCalldata[:20])); - bytes calldata callData = executionCalldata[20:]; - retDatas = new bytes[](1); - retDatas[0] = safe.execDelegateCallReturn(target, callData); - } else { - revert UnsupportedCallType(callType); - } - if (hookEnabled) postHook(safe, hook, preHookContext, true, abi.encode(retDatas)); - } - - function hookedTryExec( - bytes calldata executionCalldata, - CallType callType, - address hook - ) - internal - returns (bytes[] memory retDatas) - { - bool success; - ISafe safe = ISafe(msg.sender); - bytes memory preHookContext; - preHookContext = preHook(safe, hook); - - if (callType == CALLTYPE_BATCH) { - Execution[] calldata executions = executionCalldata.decodeBatch(); - (success, retDatas) = safe.tryExecReturn(executions); - } else if (callType == CALLTYPE_SINGLE) { - (address target, uint256 value, bytes calldata callData) = - executionCalldata.decodeSingle(); - retDatas = new bytes[](1); - (success, retDatas[0]) = safe.tryExecReturn(target, value, callData); - } else if (callType == CALLTYPE_DELEGATECALL) { - address target = address(bytes20(executionCalldata[:20])); - bytes calldata callData = executionCalldata[20:]; - retDatas = new bytes[](1); - (success, retDatas[0]) = safe.tryExecDelegateCallReturn(target, callData); - } else { - revert UnsupportedCallType(callType); - } - postHook(safe, hook, preHookContext, true, abi.encode(retDatas)); - } -} - -function _msgSender() pure returns (address sender) { - // The assembly code is more direct than the Solidity version using `abi.decode`. - /* solhint-disable no-inline-assembly */ - /// @solidity memory-safe-assembly - assembly { - sender := shr(96, calldataload(sub(calldatasize(), 20))) - } - /* solhint-enable no-inline-assembly */ -} diff --git a/accounts/safe7579/src/utils/DCUtil.sol b/accounts/safe7579/src/utils/DCUtil.sol index 0e42e642..24aac88f 100644 --- a/accounts/safe7579/src/utils/DCUtil.sol +++ b/accounts/safe7579/src/utils/DCUtil.sol @@ -31,18 +31,28 @@ contract ModuleInstallUtil { } contract BatchedExecUtil { - function tryExecute(Execution[] calldata executions) external returns (bytes[] memory result) { + function tryExecute(Execution[] calldata executions) external returns (bool success) { + uint256 length = executions.length; + + for (uint256 i; i < length; i++) { + Execution calldata _exec = executions[i]; + (success,) = _tryExecute(_exec.target, _exec.value, _exec.callData); + } + } + + function execute(Execution[] calldata executions) external { uint256 length = executions.length; - result = new bytes[](length); for (uint256 i; i < length; i++) { Execution calldata _exec = executions[i]; - bool success; - (success, result[i]) = _tryExecute(_exec.target, _exec.value, _exec.callData); + _execute(_exec.target, _exec.value, _exec.callData); } } - function execute(Execution[] calldata executions) external returns (bytes[] memory result) { + function executeReturn(Execution[] calldata executions) + external + returns (bytes[] memory result) + { uint256 length = executions.length; result = new bytes[](length); @@ -52,6 +62,20 @@ contract BatchedExecUtil { } } + function tryExecuteReturn(Execution[] calldata executions) + external + returns (bool[] memory success, bytes[] memory result) + { + uint256 length = executions.length; + result = new bytes[](length); + success = new bool[](length); + + for (uint256 i; i < length; i++) { + Execution calldata _exec = executions[i]; + (success[i], result[i]) = _tryExecute(_exec.target, _exec.value, _exec.callData); + } + } + function _execute( address target, uint256 value, diff --git a/accounts/safe7579/src/utils/DelegatecallTarget.sol b/accounts/safe7579/src/utils/DelegatecallTarget.sol deleted file mode 100644 index 8bc62148..00000000 --- a/accounts/safe7579/src/utils/DelegatecallTarget.sol +++ /dev/null @@ -1,79 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.23; - -import { Execution } from "erc7579/interfaces/IERC7579Account.sol"; -import { SimulateTxAccessor } from - "@safe-global/safe-contracts/contracts/accessors/SimulateTxAccessor.sol"; - -contract EventEmitter { - event ModuleInstalled(uint256 moduleTypeId, address module); - event ModuleUninstalled(uint256 moduleTypeId, address module); - - function emitModuleInstalled(uint256 moduleTypeId, address module) external { - emit ModuleInstalled(moduleTypeId, module); - } - - function emitModuleUninstalled(uint256 moduleTypeId, address module) external { - emit ModuleUninstalled(moduleTypeId, module); - } -} - -contract ExecMultiCall { - function execute(Execution[] calldata executions) external returns (bytes[] memory result) { - uint256 length = executions.length; - result = new bytes[](length); - - for (uint256 i; i < length; i++) { - Execution calldata _exec = executions[i]; - result[i] = _execute(_exec.target, _exec.value, _exec.callData); - } - } - - function _execute( - address target, - uint256 value, - bytes calldata callData - ) - internal - virtual - returns (bytes memory result) - { - /// @solidity memory-safe-assembly - assembly { - result := mload(0x40) - calldatacopy(result, callData.offset, callData.length) - if iszero(call(gas(), target, value, result, callData.length, codesize(), 0x00)) { - // Bubble up the revert if the call reverts. - returndatacopy(result, 0x00, returndatasize()) - revert(result, returndatasize()) - } - mstore(result, returndatasize()) // Store the length. - let o := add(result, 0x20) - returndatacopy(o, 0x00, returndatasize()) // Copy the returndata. - mstore(0x40, add(o, returndatasize())) // Allocate the memory. - } - } - - function _tryExecute( - address target, - uint256 value, - bytes calldata callData - ) - internal - virtual - returns (bool success, bytes memory result) - { - /// @solidity memory-safe-assembly - assembly { - result := mload(0x40) - calldatacopy(result, callData.offset, callData.length) - success := iszero(call(gas(), target, value, result, callData.length, codesize(), 0x00)) - mstore(result, returndatasize()) // Store the length. - let o := add(result, 0x20) - returndatacopy(o, 0x00, returndatasize()) // Copy the returndata. - mstore(0x40, add(o, returndatasize())) // Allocate the memory. - } - } -} - -contract DelegateCallTarget is EventEmitter, ExecMultiCall, SimulateTxAccessor { } diff --git a/accounts/safe7579/test/ERC7579Compliance/Executions4337.t.sol b/accounts/safe7579/test/ERC7579Compliance/Executions4337.t.sol index 715c7b3c..1b5aa23c 100644 --- a/accounts/safe7579/test/ERC7579Compliance/Executions4337.t.sol +++ b/accounts/safe7579/test/ERC7579Compliance/Executions4337.t.sol @@ -46,7 +46,7 @@ contract Executions4337Test is BaseTest { ModeLib.encode( CALLTYPE_SINGLE, EXECTYPE_TRY, MODE_DEFAULT, ModePayload.wrap(bytes22(0)) ), - ExecutionLib.encodeSingle(address(target), uint256(0), hex"41414141") + ExecutionLib.encodeSingle(address(target), uint256(0), hex"41414145") ); setValueOnTarget = abi.encodeCall(MockTarget.set, 1338); diff --git a/accounts/safe7579/test/ERC7579Compliance/ModuleManagement.t.sol b/accounts/safe7579/test/ERC7579Compliance/ModuleManagement.t.sol index a6a64dd9..a87ba16f 100644 --- a/accounts/safe7579/test/ERC7579Compliance/ModuleManagement.t.sol +++ b/accounts/safe7579/test/ERC7579Compliance/ModuleManagement.t.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.0; import "./Base.t.sol"; import "erc7579/lib/ModeLib.sol"; -import { EventEmitter } from "src/utils/DelegatecallTarget.sol"; contract ModuleManagementTest is BaseTest { bytes _data; From 95cdd99321db84e9841f5dcc5aece4b77c42bd42 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Thu, 18 Apr 2024 14:33:19 +0700 Subject: [PATCH 47/64] modulemanager refactor --- accounts/safe7579/src/SafeERC7579.sol | 3 - .../{HookManager.sol => HookManager.sol.bak} | 0 accounts/safe7579/src/core/Initializer.sol | 9 +- accounts/safe7579/src/core/ModuleManager.sol | 221 +++++++++++++----- .../test/ERC7579Compliance/Fallback.tree | 3 + 5 files changed, 165 insertions(+), 71 deletions(-) rename accounts/safe7579/src/core/{HookManager.sol => HookManager.sol.bak} (100%) create mode 100644 accounts/safe7579/test/ERC7579Compliance/Fallback.tree diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index 53b210c9..33931817 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -357,9 +357,6 @@ contract SafeERC7579 is override onlyEntryPointOrSelf { - // address hook = getActiveHook(); - address hook = address(0); - if (moduleType == MODULE_TYPE_VALIDATOR) _installValidator(module, initData); else if (moduleType == MODULE_TYPE_EXECUTOR) _installExecutor(module, initData); else if (moduleType == MODULE_TYPE_FALLBACK) _installFallbackHandler(module, initData); diff --git a/accounts/safe7579/src/core/HookManager.sol b/accounts/safe7579/src/core/HookManager.sol.bak similarity index 100% rename from accounts/safe7579/src/core/HookManager.sol rename to accounts/safe7579/src/core/HookManager.sol.bak diff --git a/accounts/safe7579/src/core/Initializer.sol b/accounts/safe7579/src/core/Initializer.sol index e22e8658..b8050daf 100644 --- a/accounts/safe7579/src/core/Initializer.sol +++ b/accounts/safe7579/src/core/Initializer.sol @@ -2,8 +2,7 @@ pragma solidity ^0.8.23; import { ISafe7579Init } from "../interfaces/ISafe7579Init.sol"; -import { HookManager } from "./HookManager.sol"; -import { ModuleManagerStorage } from "./ModuleManager.sol"; +import { ModuleManager } from "./ModuleManager.sol"; import { IERC7484 } from "../interfaces/IERC7484.sol"; import { SentinelList4337Lib } from "sentinellist/SentinelList4337.sol"; import { SentinelListLib } from "sentinellist/SentinelList.sol"; @@ -11,7 +10,7 @@ import { SentinelListLib } from "sentinellist/SentinelList.sol"; /** * Functions that can be used to initialze Safe7579 for a Safe Account */ -abstract contract Initializer is ISafe7579Init, HookManager { +abstract contract Initializer is ISafe7579Init, ModuleManager { using SentinelList4337Lib for SentinelList4337Lib.SentinelList; using SentinelListLib for SentinelListLib.SentinelList; @@ -93,9 +92,9 @@ abstract contract Initializer is ISafe7579Init, HookManager { revert InvalidInitData(msg.sender); } - ModuleManagerStorage storage $mms = $moduleManager[msg.sender]; + SentinelListLib.SentinelList storage $executors = $executorStorage[msg.sender]; // this will revert if already initialized. - $mms._executors.init(); + $executors.init(); length = executors.length; for (uint256 i; i < length; i++) { diff --git a/accounts/safe7579/src/core/ModuleManager.sol b/accounts/safe7579/src/core/ModuleManager.sol index 6a0e0350..cdf2a88c 100644 --- a/accounts/safe7579/src/core/ModuleManager.sol +++ b/accounts/safe7579/src/core/ModuleManager.sol @@ -12,7 +12,6 @@ import { Enum } from "@safe-global/safe-contracts/contracts/common/Enum.sol"; import { RegistryAdapter } from "./RegistryAdapter.sol"; import { Receiver } from "erc7579/core/Receiver.sol"; import { AccessControl } from "./AccessControl.sol"; -import { HookManager } from "./HookManager.sol"; import { ExecutionHelper } from "./ExecutionHelper.sol"; import { Safe7579DCUtil, Safe7579DCUtilSetup } from "./SetupDCUtil.sol"; import { CallType, CALLTYPE_SINGLE, CALLTYPE_DELEGATECALL } from "erc7579/lib/ModeLib.sol"; @@ -20,28 +19,29 @@ import { CallType, CALLTYPE_SINGLE, CALLTYPE_DELEGATECALL } from "erc7579/lib/Mo import { MODULE_TYPE_VALIDATOR, MODULE_TYPE_EXECUTOR, - MODULE_TYPE_FALLBACK + MODULE_TYPE_FALLBACK, + MODULE_TYPE_HOOK } from "erc7579/interfaces/IERC7579Module.sol"; CallType constant CALLTYPE_STATIC = CallType.wrap(0xFE); -struct FallbackHandler { - address handler; - CallType calltype; -} - -struct ModuleManagerStorage { - // linked list of executors. List is initialized by initializeAccount() - SentinelListLib.SentinelList _executors; - mapping(bytes4 selector => FallbackHandler fallbackHandler) _fallbacks; -} +// struct FallbackHandler { +// address handler; +// CallType calltype; +// } +// +// struct ModuleManagerStorage { +// // linked list of executors. List is initialized by initializeAccount() +// SentinelListLib.SentinelList _executors; +// mapping(bytes4 selector => FallbackHandler fallbackHandler) _fallbacks; +// } /** * @title ModuleManager * Contract that implements ERC7579 Module compatibility for Safe accounts * @author zeroknots.eth | rhinestone.wtf */ -abstract contract ModuleManager is HookManager, AccessControl, Receiver, RegistryAdapter { +abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { using SentinelListLib for SentinelListLib.SentinelList; using SentinelList4337Lib for SentinelList4337Lib.SentinelList; @@ -54,19 +54,11 @@ abstract contract ModuleManager is HookManager, AccessControl, Receiver, Registr error InvalidFallbackHandler(bytes4 msgSig); error FallbackInstalled(bytes4 msgSig); - mapping(address smartAccount => ModuleManagerStorage moduleManagerStorage) internal - $moduleManager; - + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* VALIDATOR MODULES */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ SentinelList4337Lib.SentinelList internal $validators; - modifier onlyExecutorModule() { - if (!_isExecutorInstalled(_msgSender())) revert InvalidModule(_msgSender()); - _; - } - - ///////////////////////////////////////////////////// - // Manage Validators - //////////////////////////////////////////////////// /** * install and initialize validator module */ @@ -139,9 +131,16 @@ abstract contract ModuleManager is HookManager, AccessControl, Receiver, Registr }); } - ///////////////////////////////////////////////////// - // Manage Executors - //////////////////////////////////////////////////// + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EXECUTOR MODULES */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + mapping(address smartAccount => SentinelListLib.SentinelList _executors) internal + $executorStorage; + + modifier onlyExecutorModule() { + if (!_isExecutorInstalled(_msgSender())) revert InvalidModule(_msgSender()); + _; + } function _installExecutor( address executor, @@ -150,7 +149,7 @@ abstract contract ModuleManager is HookManager, AccessControl, Receiver, Registr internal withRegistry(executor, MODULE_TYPE_EXECUTOR) { - SentinelListLib.SentinelList storage $executors = $moduleManager[msg.sender]._executors; + SentinelListLib.SentinelList storage $executors = $executorStorage[msg.sender]; $executors.push(executor); // Initialize Executor Module via Safe _delegatecall({ @@ -163,7 +162,7 @@ abstract contract ModuleManager is HookManager, AccessControl, Receiver, Registr } function _uninstallExecutor(address executor, bytes calldata data) internal { - SentinelListLib.SentinelList storage $executors = $moduleManager[msg.sender]._executors; + SentinelListLib.SentinelList storage $executors = $executorStorage[msg.sender]; (address prev, bytes memory disableModuleData) = abi.decode(data, (address, bytes)); $executors.pop(prev, executor); @@ -178,7 +177,7 @@ abstract contract ModuleManager is HookManager, AccessControl, Receiver, Registr } function _isExecutorInstalled(address executor) internal view virtual returns (bool) { - SentinelListLib.SentinelList storage $executors = $moduleManager[msg.sender]._executors; + SentinelListLib.SentinelList storage $executors = $executorStorage[msg.sender]; return $executors.contains(executor); } @@ -191,13 +190,21 @@ abstract contract ModuleManager is HookManager, AccessControl, Receiver, Registr virtual returns (address[] memory array, address next) { - SentinelListLib.SentinelList storage $executors = $moduleManager[msg.sender]._executors; + SentinelListLib.SentinelList storage $executors = $executorStorage[msg.sender]; return $executors.getEntriesPaginated(cursor, size); } - ///////////////////////////////////////////////////// - // Manage Fallback - //////////////////////////////////////////////////// + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* FALLBACK MODULES */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + struct FallbackHandler { + address handler; + CallType calltype; + } + + mapping(address smartAccount => mapping(bytes4 selector => FallbackHandler handlerConfig)) + internal $fallbackStorage; + function _installFallbackHandler( address handler, bytes calldata params @@ -216,7 +223,7 @@ abstract contract ModuleManager is HookManager, AccessControl, Receiver, Registr ) revert InvalidFallbackHandler(functionSig); if (_isFallbackHandlerInstalled(functionSig)) revert FallbackInstalled(functionSig); - FallbackHandler storage $fallbacks = $moduleManager[msg.sender]._fallbacks[functionSig]; + FallbackHandler storage $fallbacks = $fallbackStorage[msg.sender][functionSig]; $fallbacks.calltype = calltype; $fallbacks.handler = handler; @@ -230,15 +237,15 @@ abstract contract ModuleManager is HookManager, AccessControl, Receiver, Registr } function _isFallbackHandlerInstalled(bytes4 functionSig) internal view virtual returns (bool) { - FallbackHandler storage $fallback = $moduleManager[msg.sender]._fallbacks[functionSig]; - return $fallback.handler != address(0); + FallbackHandler storage $fallbacks = $fallbackStorage[msg.sender][functionSig]; + return $fallbacks.handler != address(0); } function _uninstallFallbackHandler(address handler, bytes calldata context) internal virtual { (bytes4 functionSig, bytes memory initData) = abi.decode(context, (bytes4, bytes)); - ModuleManagerStorage storage $mms = $moduleManager[msg.sender]; - $mms._fallbacks[functionSig].handler = address(0); + FallbackHandler storage $fallbacks = $fallbackStorage[msg.sender][functionSig]; + $fallbacks.handler = address(0); // De-Initialize Fallback Module via Safe _delegatecall({ safe: ISafe(msg.sender), @@ -262,8 +269,8 @@ abstract contract ModuleManager is HookManager, AccessControl, Receiver, Registr // TODO: check that no onInstall / onUninstall is called - FallbackHandler storage $fallback = $moduleManager[msg.sender]._fallbacks[functionSig]; - return $fallback.handler == _handler; + FallbackHandler storage $fallbacks = $fallbackStorage[msg.sender][functionSig]; + return $fallbacks.handler == _handler; } // FALLBACK @@ -276,28 +283,116 @@ abstract contract ModuleManager is HookManager, AccessControl, Receiver, Registr receiverFallback returns (bytes memory fallbackRet) { - FallbackHandler storage $fallbackHandler = $moduleManager[msg.sender]._fallbacks[msg.sig]; - address handler = $fallbackHandler.handler; - CallType calltype = $fallbackHandler.calltype; + FallbackHandler storage $fallbacks = $fallbackStorage[msg.sender][msg.sig]; + address handler = $fallbacks.handler; + CallType calltype = $fallbacks.calltype; if (handler == address(0)) revert NoFallbackHandler(msg.sig); - // - // if (calltype == CALLTYPE_STATIC) { - // bytes memory ret = ISafe(msg.sender).execDelegateCallReturn({ - // target: UTIL, - // callData: abi.encodeCall( - // SimulateTxAccessor.simulate, - // (handler, 0, abi.encodePacked(callData, _msgSender()), Enum.Operation.Call) - // ) - // }); - // (,, fallbackRet) = abi.decode(ret, (uint256, bool, bytes)); - // return fallbackRet; - // } - // if (calltype == CALLTYPE_SINGLE) { - // return ISafe(msg.sender).execReturn({ - // target: handler, - // value: 0, - // callData: abi.encodePacked(callData, _msgSender()) - // }); - // } + + if (calltype == CALLTYPE_STATIC) { + bytes memory ret = _delegatecallReturn({ + safe: ISafe(msg.sender), + target: UTIL, + callData: abi.encodeCall( + SimulateTxAccessor.simulate, + (handler, 0, abi.encodePacked(callData, _msgSender()), Enum.Operation.Call) + ) + }); + (,, fallbackRet) = abi.decode(ret, (uint256, bool, bytes)); + return fallbackRet; + } + if (calltype == CALLTYPE_SINGLE) { + return _execReturn({ + safe: ISafe(msg.sender), + target: handler, + value: 0, + callData: abi.encodePacked(callData, _msgSender()) + }); + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* HOOK MODULES */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + mapping(address smartAccount => address globalHook) internal $globalHook; + mapping(address smartAccount => mapping(bytes4 => address hook)) internal $hookManager; + + error HookPostCheckFailed(); + error HookAlreadyInstalled(address currentHook); + + enum HookType { + GLOBAL, + SIG + } + + modifier withSelectorHook(bytes4 hookSig) { + address hook = $hookManager[msg.sender][hookSig]; + bool enabled = hook != address(0); + bytes memory _data; + // if (enabled) _data = ISafe(msg.sender).preHook({ withHook: hook }); + _; + // if (enabled) ISafe(msg.sender).postHook({ withHook: hook, hookPreContext: _data }); + } + + modifier withGlobalHook() { + address hook = $globalHook[msg.sender]; + bool enabled = hook != address(0); + bytes memory _data; + // if (enabled) _data = ISafe(msg.sender).preHook({ withHook: hook }); + _; + // if (enabled) ISafe(msg.sender).postHook({ withHook: hook, hookPreContext: _data }); + } + + function _installHook( + address hook, + bytes calldata data + ) + internal + virtual + withRegistry(hook, MODULE_TYPE_HOOK) + { + (bytes4 selector, bytes memory initData) = abi.decode(data, (bytes4, bytes)); + address currentHook = $hookManager[msg.sender][selector]; + if (currentHook != address(0)) { + revert HookAlreadyInstalled(currentHook); + } + $hookManager[msg.sender][selector] = hook; + + _delegatecall({ + safe: ISafe(msg.sender), + target: UTIL, + callData: abi.encodeCall( + ModuleInstallUtil.installModule, (MODULE_TYPE_HOOK, hook, initData) + ) + }); + } + + function _uninstallHook(address hook, bytes calldata data) internal virtual { + (bytes4 selector, bytes memory initData) = abi.decode(data, (bytes4, bytes)); + delete $hookManager[msg.sender][selector]; + + _delegatecall({ + safe: ISafe(msg.sender), + target: UTIL, + callData: abi.encodeCall( + ModuleInstallUtil.unInstallModule, (MODULE_TYPE_HOOK, hook, initData) + ) + }); + } + + function _isHookInstalled( + address module, + bytes calldata context + ) + internal + view + returns (bool) + { + bytes4 selector = abi.decode(context, (bytes4)); + return $hookManager[msg.sender][selector] == module; + } + + function getActiveHook(bytes4 selector) public view returns (address hook) { + return $hookManager[msg.sender][selector]; } } diff --git a/accounts/safe7579/test/ERC7579Compliance/Fallback.tree b/accounts/safe7579/test/ERC7579Compliance/Fallback.tree new file mode 100644 index 00000000..635a086f --- /dev/null +++ b/accounts/safe7579/test/ERC7579Compliance/Fallback.tree @@ -0,0 +1,3 @@ +FallbackTest + When installing global fallbackhandler + It should be used with every execution From 8841547f5c329ea223e46f7fc5f6e72706d8fe23 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Thu, 18 Apr 2024 14:47:09 +0700 Subject: [PATCH 48/64] refactoring to avoid stack too deep --- accounts/safe7579/src/SafeERC7579.sol | 34 +++++-- .../safe7579/src/core/HookManager.sol.bak | 95 ------------------- accounts/safe7579/src/core/ModuleManager.sol | 14 ++- .../safe7579/src/core/RegistryAdapter.sol | 6 +- 4 files changed, 42 insertions(+), 107 deletions(-) delete mode 100644 accounts/safe7579/src/core/HookManager.sol.bak diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index 33931817..8c14bd58 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -75,6 +75,8 @@ contract SafeERC7579 is external payable override + withGlobalHook + withSelectorHook(IERC7579Account.execute.selector) onlyEntryPointOrSelf { CallType callType; @@ -151,6 +153,8 @@ contract SafeERC7579 is override onlyExecutorModule withRegistry(msg.sender, MODULE_TYPE_EXECUTOR) + withGlobalHook + withSelectorHook(IERC7579Account.execute.selector) returns (bytes[] memory returnDatas) { CallType callType; @@ -161,29 +165,41 @@ contract SafeERC7579 is callType := mode execType := shl(8, mode) } + // using JUMPI to avoid stack too deep + return _executeReturn(execType, callType, executionCalldata); + } + + function _executeReturn( + ExecType execType, + CallType callType, + bytes calldata executionCalldata + ) + private + returns (bytes[] memory returnDatas) + { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* REVERT ON FAILED EXEC */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - ISafe safe = ISafe(msg.sender); + if (execType == EXECTYPE_DEFAULT) { // DEFAULT EXEC & SINGLE CALL if (callType == CALLTYPE_BATCH) { Execution[] calldata executions = executionCalldata.decodeBatch(); - returnDatas = _execReturn(safe, executions); + returnDatas = _execReturn(ISafe(msg.sender), executions); } // DEFAULT EXEC & BATCH CALL else if (callType == CALLTYPE_SINGLE) { (address target, uint256 value, bytes calldata callData) = executionCalldata.decodeSingle(); returnDatas = new bytes[](1); - returnDatas[0] = _execReturn(safe, target, value, callData); + returnDatas[0] = _execReturn(ISafe(msg.sender), target, value, callData); } // DEFAULT EXEC & DELEGATECALL else if (callType == CALLTYPE_DELEGATECALL) { address target = address(bytes20(executionCalldata[:20])); bytes calldata callData = executionCalldata[20:]; returnDatas = new bytes[](1); - returnDatas[0] = _delegatecallReturn(safe, target, callData); + returnDatas[0] = _delegatecallReturn(ISafe(msg.sender), target, callData); } // handle unsupported calltype else { @@ -196,17 +212,17 @@ contract SafeERC7579 is else if (execType == EXECTYPE_TRY) { if (callType == CALLTYPE_BATCH) { Execution[] calldata executions = executionCalldata.decodeBatch(); - (, returnDatas) = _tryExecReturn(safe, executions); + (, returnDatas) = _tryExecReturn(ISafe(msg.sender), executions); } else if (callType == CALLTYPE_SINGLE) { (address target, uint256 value, bytes calldata callData) = executionCalldata.decodeSingle(); returnDatas = new bytes[](1); - returnDatas[0] = _tryExecReturn(safe, target, value, callData); + returnDatas[0] = _tryExecReturn(ISafe(msg.sender), target, value, callData); } else if (callType == CALLTYPE_DELEGATECALL) { address target = address(bytes20(executionCalldata[:20])); bytes calldata callData = executionCalldata[20:]; returnDatas = new bytes[](1); - returnDatas[0] = _tryDelegatecallReturn(safe, target, callData); + returnDatas[0] = _tryDelegatecallReturn(ISafe(msg.sender), target, callData); } else { revert UnsupportedCallType(callType); } @@ -355,6 +371,8 @@ contract SafeERC7579 is external payable override + withGlobalHook + withSelectorHook(IERC7579Account.installModule.selector) onlyEntryPointOrSelf { if (moduleType == MODULE_TYPE_VALIDATOR) _installValidator(module, initData); @@ -375,6 +393,8 @@ contract SafeERC7579 is external payable override + withGlobalHook + withSelectorHook(IERC7579Account.installModule.selector) onlyEntryPointOrSelf { if (moduleType == MODULE_TYPE_VALIDATOR) _uninstallValidator(module, deInitData); diff --git a/accounts/safe7579/src/core/HookManager.sol.bak b/accounts/safe7579/src/core/HookManager.sol.bak deleted file mode 100644 index 6c6b60b0..00000000 --- a/accounts/safe7579/src/core/HookManager.sol.bak +++ /dev/null @@ -1,95 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.23; - -import { IHook, IModule } from "erc7579/interfaces/IERC7579Module.sol"; -import { ISafe } from "../interfaces/ISafe.sol"; -import { MODULE_TYPE_HOOK } from "erc7579/interfaces/IERC7579Module.sol"; -import { Safe7579DCUtil, ModuleInstallUtil } from "../utils/DCUtil.sol"; -/** - * @title reference implementation of HookManager - * @author zeroknots.eth | rhinestone.wtf - */ - -abstract contract HookManager { - mapping(address smartAccount => address globalHook) internal $globalHook; - mapping(address smartAccount => mapping(bytes4 => address hook)) internal $hookManager; - - error HookPostCheckFailed(); - error HookAlreadyInstalled(address currentHook); - - enum HookType { - GLOBAL, - SIG - } - - modifier withSelectorHook(bytes4 hookSig) { - address hook = $hookManager[msg.sender][hookSig]; - bool enabled = hook != address(0); - bytes memory _data; - // if (enabled) _data = ISafe(msg.sender).preHook({ withHook: hook }); - _; - // if (enabled) ISafe(msg.sender).postHook({ withHook: hook, hookPreContext: _data }); - } - - modifier withGlobalHook() { - address hook = $globalHook[msg.sender]; - bool enabled = hook != address(0); - bytes memory _data; - // if (enabled) _data = ISafe(msg.sender).preHook({ withHook: hook }); - _; - // if (enabled) ISafe(msg.sender).postHook({ withHook: hook, hookPreContext: _data }); - } - - function _installHook( - address hook, - bytes calldata data - ) - internal - virtual - withRegistry(hook, MODULE_TYPE_HOOK) - { - (bytes4 selector, bytes memory initData) = abi.decode(data, (bytes4, bytes)); - address currentHook = $hookManager[msg.sender][selector]; - if (currentHook != address(0)) { - revert HookAlreadyInstalled(currentHook); - } - $hookManager[msg.sender][selector] = hook; - - _delegatecall({ - safe: ISafe(msg.sender), - target: UTIL, - callData: abi.encodeCall( - ModuleInstallUtil.installModule, (MODULE_TYPE_HOOK, hook, initData) - ) - }); - } - - function _uninstallHook(address hook, bytes calldata data) internal virtual { - (bytes4 selector, bytes memory initData) = abi.decode(data, (bytes4, bytes)); - delete $hookManager[msg.sender][selector]; - - _delegatecall({ - safe: ISafe(msg.sender), - target: UTIL, - callData: abi.encodeCall( - ModuleInstallUtil.unInstallModule, (MODULE_TYPE_HOOK, hook, initData) - ) - }); - } - - function _isHookInstalled( - address module, - bytes calldata context - ) - internal - view - returns (bool) - { - bytes4 selector = abi.decode(context, (bytes4)); - return $hookManager[msg.sender][selector] == module; - } - - function getActiveHook(bytes4 selector) public view returns (address hook) { - return $hookManager[msg.sender][selector]; - } -} diff --git a/accounts/safe7579/src/core/ModuleManager.sol b/accounts/safe7579/src/core/ModuleManager.sol index cdf2a88c..68b0f39e 100644 --- a/accounts/safe7579/src/core/ModuleManager.sol +++ b/accounts/safe7579/src/core/ModuleManager.sol @@ -267,8 +267,6 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { { bytes4 functionSig = abi.decode(additionalContext, (bytes4)); - // TODO: check that no onInstall / onUninstall is called - FallbackHandler storage $fallbacks = $fallbackStorage[msg.sender][functionSig]; return $fallbacks.handler == _handler; } @@ -281,6 +279,16 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { virtual override(Receiver) receiverFallback + withGlobalHook + withSelectorHook(msg.sig) + returns (bytes memory fallbackRet) + { + // using JUMPI to avoid stack too deep + return _callFallbackHandler(callData); + } + + function _callFallbackHandler(bytes calldata callData) + private returns (bytes memory fallbackRet) { FallbackHandler storage $fallbacks = $fallbackStorage[msg.sender][msg.sig]; @@ -327,7 +335,6 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { modifier withSelectorHook(bytes4 hookSig) { address hook = $hookManager[msg.sender][hookSig]; - bool enabled = hook != address(0); bytes memory _data; // if (enabled) _data = ISafe(msg.sender).preHook({ withHook: hook }); _; @@ -336,7 +343,6 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { modifier withGlobalHook() { address hook = $globalHook[msg.sender]; - bool enabled = hook != address(0); bytes memory _data; // if (enabled) _data = ISafe(msg.sender).preHook({ withHook: hook }); _; diff --git a/accounts/safe7579/src/core/RegistryAdapter.sol b/accounts/safe7579/src/core/RegistryAdapter.sol index 9c6708f4..1faa12ef 100644 --- a/accounts/safe7579/src/core/RegistryAdapter.sol +++ b/accounts/safe7579/src/core/RegistryAdapter.sol @@ -10,11 +10,15 @@ abstract contract RegistryAdapter is ExecutionHelper { mapping(address smartAccount => IERC7484 registry) internal $registry; modifier withRegistry(address module, uint256 moduleType) { + _checkRegistry(module, moduleType); + _; + } + + function _checkRegistry(address module, uint256 moduleType) internal view { IERC7484 registry = $registry[msg.sender]; if (address(registry) != address(0)) { registry.checkForAccount(msg.sender, module, moduleType); } - _; } function _configureRegistry( From 981bcec4d16ba181e8eb2fc0db352bc49f531bc8 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Fri, 19 Apr 2024 07:27:04 +0700 Subject: [PATCH 49/64] refactoring for erc1271 --- accounts/safe7579/src/SafeERC7579.sol | 79 ++++++--- .../safe7579/src/core/ExecutionHelper.sol | 38 ++++- accounts/safe7579/src/core/ModuleManager.sol | 14 +- .../src/interfaces/IERC7579Account.sol | 139 ++++++++++++++++ accounts/safe7579/src/lib/ExecutionLib.sol | 62 +++++++ accounts/safe7579/src/lib/ModeLib.sol | 153 ++++++++++++++++++ accounts/safe7579/src/utils/DCUtil.sol | 2 +- .../test/ERC7579Compliance/ERC1271.t.sol | 1 + accounts/safe7579/test/Launchpad.t.sol | 1 + 9 files changed, 450 insertions(+), 39 deletions(-) create mode 100644 accounts/safe7579/src/interfaces/IERC7579Account.sol create mode 100644 accounts/safe7579/src/lib/ExecutionLib.sol create mode 100644 accounts/safe7579/src/lib/ModeLib.sol diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index 8c14bd58..bbe50175 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -1,7 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.23; -import { IERC7579Account, Execution } from "erc7579/interfaces/IERC7579Account.sol"; +import { IERC7579Account, Execution } from "./interfaces/IERC7579Account.sol"; +import { Enum } from "@safe-global/safe-contracts/contracts/common/Enum.sol"; +import { SimulateTxAccessor } from "./utils/DCUtil.sol"; import { IMSA } from "erc7579/interfaces/IMSA.sol"; import { CallType, @@ -13,8 +15,8 @@ import { CALLTYPE_SINGLE, CALLTYPE_BATCH, CALLTYPE_DELEGATECALL -} from "erc7579/lib/ModeLib.sol"; -import { ExecutionLib } from "erc7579/lib/ExecutionLib.sol"; +} from "./lib/ModeLib.sol"; +import { ExecutionLib } from "./lib/ExecutionLib.sol"; import { IValidator, MODULE_TYPE_VALIDATOR, @@ -35,21 +37,20 @@ import { IEntryPoint } from "@ERC4337/account-abstraction/contracts/interfaces/I import { ISafe7579Init } from "./interfaces/ISafe7579Init.sol"; import { IERC1271 } from "./interfaces/IERC1271.sol"; -import "forge-std/console2.sol"; - /** * @title ERC7579 Adapter for Safe accounts. * creates full ERC7579 compliance to Safe accounts * @author rhinestone | zeroknots.eth, Konrad Kopp (@kopy-kat) + * @dev This contract is a Safe account implementation that supports ERC7579 operations. + * In order to facilitate full ERC7579 compliance, the contract implements the IERC7579Account + * interface. + * This contract is an implementation of a Safe account supporting ERC7579 operations and complying + * with the IERC7579Account interface. It serves as a Safe FallbackHandler and module for Safe + * accounts, incorporating complex hacks to ensure ERC7579 compliance and requiring interactions and + * event emissions to be done via the SafeProxy as msg.sender using Safe's + * "executeTransactionFromModule" features. */ -contract SafeERC7579 is - ISafeOp, - IERC7579Account, - ISafe7579Init, - AccessControl, - Initializer, - IMSA -{ +contract SafeERC7579 is ISafeOp, IERC7579Account, ISafe7579Init, AccessControl, Initializer { using UserOperationLib for PackedUserOperation; using ModeLib for ModeCode; using ExecutionLib for bytes; @@ -74,7 +75,6 @@ contract SafeERC7579 is ) external payable - override withGlobalHook withSelectorHook(IERC7579Account.execute.selector) onlyEntryPointOrSelf @@ -118,18 +118,25 @@ contract SafeERC7579 is /* TRY EXEC */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ else if (execType == EXECTYPE_TRY) { + // TRY EXEC & BATCH CALL if (callType == CALLTYPE_BATCH) { Execution[] calldata executions = executionCalldata.decodeBatch(); _tryExec(safe, executions); - } else if (callType == CALLTYPE_SINGLE) { + } + // TRY EXEC & SINGLE CALL + else if (callType == CALLTYPE_SINGLE) { (address target, uint256 value, bytes calldata callData) = executionCalldata.decodeSingle(); _tryExec(safe, target, value, callData); - } else if (callType == CALLTYPE_DELEGATECALL) { + } + // TRY EXEC & DELEGATECALL + else if (callType == CALLTYPE_DELEGATECALL) { address target = address(bytes20(executionCalldata[:20])); bytes calldata callData = executionCalldata[20:]; _tryDelegatecall(safe, target, callData); - } else { + } + // handle unsupported calltype + else { revert UnsupportedCallType(callType); } } @@ -169,6 +176,11 @@ contract SafeERC7579 is return _executeReturn(execType, callType, executionCalldata); } + /** + * Internal function that will be solely called by executeFromExecutor. Not super uniform code, + * but we need need the JUMPI to avoid stack too deep, due to the modifiers in the + * executeFromExecutor function + */ function _executeReturn( ExecType execType, CallType callType, @@ -210,20 +222,27 @@ contract SafeERC7579 is /* TRY EXEC */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ else if (execType == EXECTYPE_TRY) { + // TRY EXEC & SINGLE CALL if (callType == CALLTYPE_BATCH) { Execution[] calldata executions = executionCalldata.decodeBatch(); (, returnDatas) = _tryExecReturn(ISafe(msg.sender), executions); - } else if (callType == CALLTYPE_SINGLE) { + } + // TRY EXEC & BATCH CALL + else if (callType == CALLTYPE_SINGLE) { (address target, uint256 value, bytes calldata callData) = executionCalldata.decodeSingle(); returnDatas = new bytes[](1); returnDatas[0] = _tryExecReturn(ISafe(msg.sender), target, value, callData); - } else if (callType == CALLTYPE_DELEGATECALL) { + } + // TRY EXEC & DELEGATECALL + else if (callType == CALLTYPE_DELEGATECALL) { address target = address(bytes20(executionCalldata[:20])); bytes calldata callData = executionCalldata[20:]; returnDatas = new bytes[](1); returnDatas[0] = _tryDelegatecallReturn(ISafe(msg.sender), target, callData); - } else { + } + // handle unsupported calltype + else { revert UnsupportedCallType(callType); } } @@ -235,6 +254,7 @@ contract SafeERC7579 is } } + // TODO: delete this. need to update IERC7579Account function executeUserOp( PackedUserOperation calldata userOp, bytes32 userOpHash @@ -293,8 +313,8 @@ contract SafeERC7579 is } /** - * Function used as fallback, if no valid validation module was selected. - * will use safe's ECDSA multisig + * Function used as signature check fallback, if no valid validation module was selected. + * will use safe's ECDSA multisig. This code was copied of Safe's ERC4337 module */ function _validateSignatures(PackedUserOperation calldata userOp) internal @@ -332,7 +352,6 @@ contract SafeERC7579 is bytes calldata data ) external - view returns (bytes4 magicValue) { ISafe safe = ISafe(msg.sender); @@ -344,6 +363,8 @@ contract SafeERC7579 is } address validationModule = address(bytes20(data[:20])); + // If validation module with address(0) or no valid validator was provided, + // The signature validation mechanism falls back to Safe's checkSignatures() function if (validationModule == address(0) || !_isValidatorInstalled(validationModule)) { bytes memory messageData = EIP712.encodeMessageData( safe.domainSeparator(), SAFE_MSG_TYPEHASH, abi.encode(keccak256(abi.encode(hash))) @@ -355,9 +376,15 @@ contract SafeERC7579 is return IERC1271.isValidSignature.selector; } - // use 7579 validation module - magicValue = - IValidator(validationModule).isValidSignatureWithSender(_msgSender(), hash, data[20:]); + // if a installed validator module was selected, use 7579 validation module + bytes memory ret = _staticcallReturn({ + safe: ISafe(msg.sender), + target: validationModule, + callData: abi.encodeCall( + IValidator.isValidSignatureWithSender, (_msgSender(), hash, data[20:]) + ) + }); + magicValue = abi.decode(ret, (bytes4)); } /** diff --git a/accounts/safe7579/src/core/ExecutionHelper.sol b/accounts/safe7579/src/core/ExecutionHelper.sol index 5d31a777..63dc9c1e 100644 --- a/accounts/safe7579/src/core/ExecutionHelper.sol +++ b/accounts/safe7579/src/core/ExecutionHelper.sol @@ -2,8 +2,10 @@ pragma solidity ^0.8.23; import { Safe7579DCUtilSetup } from "./SetupDCUtil.sol"; +import { SimulateTxAccessor } from "../utils/DCUtil.sol"; +import { Enum } from "@safe-global/safe-contracts/contracts/common/Enum.sol"; import { BatchedExecUtil } from "../utils/DCUtil.sol"; -import { Execution } from "erc7579/interfaces/IERC7579Account.sol"; +import { Execution } from "../interfaces/IERC7579Account.sol"; import { ISafe } from "../interfaces/ISafe.sol"; contract ExecutionHelper is Safe7579DCUtilSetup { @@ -144,4 +146,38 @@ contract ExecutionHelper is Safe7579DCUtilSetup { (success, retData) = safe.execTransactionFromModuleReturnData(target, 0, callData, 1); if (!success) emit TryExecutionFailed(safe, 0); } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* STATICCALL TRICK */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + function _staticcallReturn( + ISafe safe, + address target, + bytes memory callData + ) + internal + returns (bytes memory retData) + { + bytes memory ret = _delegatecallReturn({ + safe: safe, + target: UTIL, + callData: abi.encodeCall( + SimulateTxAccessor.simulate, + (target, 0, abi.encodePacked(callData, _msgSender()), Enum.Operation.Call) + ) + }); + (,, retData) = abi.decode(ret, (uint256, bool, bytes)); + return retData; + } +} + +function _msgSender() pure returns (address sender) { + // The assembly code is more direct than the Solidity version using `abi.decode`. + /* solhint-disable no-inline-assembly */ + /// @solidity memory-safe-assembly + assembly { + sender := shr(96, calldataload(sub(calldatasize(), 20))) + } + /* solhint-enable no-inline-assembly */ } diff --git a/accounts/safe7579/src/core/ModuleManager.sol b/accounts/safe7579/src/core/ModuleManager.sol index 68b0f39e..d230ecb7 100644 --- a/accounts/safe7579/src/core/ModuleManager.sol +++ b/accounts/safe7579/src/core/ModuleManager.sol @@ -14,7 +14,7 @@ import { Receiver } from "erc7579/core/Receiver.sol"; import { AccessControl } from "./AccessControl.sol"; import { ExecutionHelper } from "./ExecutionHelper.sol"; import { Safe7579DCUtil, Safe7579DCUtilSetup } from "./SetupDCUtil.sol"; -import { CallType, CALLTYPE_SINGLE, CALLTYPE_DELEGATECALL } from "erc7579/lib/ModeLib.sol"; +import { CallType, CALLTYPE_SINGLE, CALLTYPE_DELEGATECALL } from "../lib/ModeLib.sol"; import { MODULE_TYPE_VALIDATOR, @@ -297,16 +297,8 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { if (handler == address(0)) revert NoFallbackHandler(msg.sig); if (calltype == CALLTYPE_STATIC) { - bytes memory ret = _delegatecallReturn({ - safe: ISafe(msg.sender), - target: UTIL, - callData: abi.encodeCall( - SimulateTxAccessor.simulate, - (handler, 0, abi.encodePacked(callData, _msgSender()), Enum.Operation.Call) - ) - }); - (,, fallbackRet) = abi.decode(ret, (uint256, bool, bytes)); - return fallbackRet; + return + _staticcallReturn({ safe: ISafe(msg.sender), target: handler, callData: callData }); } if (calltype == CALLTYPE_SINGLE) { return _execReturn({ diff --git a/accounts/safe7579/src/interfaces/IERC7579Account.sol b/accounts/safe7579/src/interfaces/IERC7579Account.sol new file mode 100644 index 00000000..a4bcefc6 --- /dev/null +++ b/accounts/safe7579/src/interfaces/IERC7579Account.sol @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.21; + +import { CallType, ExecType, ModeCode } from "../lib/ModeLib.sol"; +import { PackedUserOperation } from "account-abstraction/interfaces/IAccount.sol"; + +struct Execution { + address target; + uint256 value; + bytes callData; +} + +interface IERC7579AccountEvents { + event ModuleInstalled(uint256 moduleTypeId, address module); + event ModuleUninstalled(uint256 moduleTypeId, address module); +} + +interface IERC7579Account is IERC7579AccountEvents { + // Error thrown when an unsupported ModuleType is requested + error UnsupportedModuleType(uint256 moduleTypeId); + // Error thrown when an execution with an unsupported CallType was made + error UnsupportedCallType(CallType callType); + // Error thrown when an execution with an unsupported ExecType was made + error UnsupportedExecType(ExecType execType); + // Error thrown when account initialization fails + error AccountInitializationFailed(); + /** + * @dev Executes a transaction on behalf of the account. + * This function is intended to be called by ERC-4337 EntryPoint.sol + * @dev Ensure adequate authorization control: i.e. onlyEntryPointOrSelf + * + * @dev MSA MUST implement this function signature. + * If a mode is requested that is not supported by the Account, it MUST revert + * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details + * @param executionCalldata The encoded execution call data + */ + + function execute(ModeCode mode, bytes calldata executionCalldata) external payable; + + /** + * @dev Executes a transaction on behalf of the account. + * This function is intended to be called by Executor Modules + * @dev Ensure adequate authorization control: i.e. onlyExecutorModule + * + * @dev MSA MUST implement this function signature. + * If a mode is requested that is not supported by the Account, it MUST revert + * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details + * @param executionCalldata The encoded execution call data + */ + function executeFromExecutor( + ModeCode mode, + bytes calldata executionCalldata + ) + external + payable + returns (bytes[] memory returnData); + + /** + * @dev ERC-1271 isValidSignature + * This function is intended to be used to validate a smart account signature + * and may forward the call to a validator module + * + * @param hash The hash of the data that is signed + * @param data The data that is signed + */ + function isValidSignature(bytes32 hash, bytes calldata data) external returns (bytes4); + + /** + * @dev installs a Module of a certain type on the smart account + * @dev Implement Authorization control of your chosing + * @param moduleTypeId the module type ID according the ERC-7579 spec + * @param module the module address + * @param initData arbitrary data that may be required on the module during `onInstall` + * initialization. + */ + function installModule( + uint256 moduleTypeId, + address module, + bytes calldata initData + ) + external + payable; + + /** + * @dev uninstalls a Module of a certain type on the smart account + * @dev Implement Authorization control of your chosing + * @param moduleTypeId the module type ID according the ERC-7579 spec + * @param module the module address + * @param deInitData arbitrary data that may be required on the module during `onUninstall` + * de-initialization. + */ + function uninstallModule( + uint256 moduleTypeId, + address module, + bytes calldata deInitData + ) + external + payable; + + /** + * Function to check if the account supports a certain CallType or ExecType (see ModeLib.sol) + * @param encodedMode the encoded mode + */ + function supportsExecutionMode(ModeCode encodedMode) external view returns (bool); + + /** + * Function to check if the account supports installation of a certain module type Id + * @param moduleTypeId the module type ID according the ERC-7579 spec + */ + function supportsModule(uint256 moduleTypeId) external view returns (bool); + + /** + * Function to check if the account has a certain module installed + * @param moduleTypeId the module type ID according the ERC-7579 spec + * Note: keep in mind that some contracts can be multiple module types at the same time. It + * thus may be necessary to query multiple module types + * @param module the module address + * @param additionalContext additional context data that the smart account may interpret to + * identifiy conditions under which the module is installed. + * usually this is not necessary, but for some special hooks that + * are stored in mappings, this param might be needed + */ + function isModuleInstalled( + uint256 moduleTypeId, + address module, + bytes calldata additionalContext + ) + external + view + returns (bool); + + /** + * @dev Returns the account id of the smart account + * @return accountImplementationId the account id of the smart account + * the accountId should be structured like so: + * "vendorname.accountname.semver" + */ + function accountId() external view returns (string memory accountImplementationId); +} diff --git a/accounts/safe7579/src/lib/ExecutionLib.sol b/accounts/safe7579/src/lib/ExecutionLib.sol new file mode 100644 index 00000000..3d509eb3 --- /dev/null +++ b/accounts/safe7579/src/lib/ExecutionLib.sol @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import { Execution } from "../interfaces/IERC7579Account.sol"; + +/** + * Helper Library for decoding Execution calldata + * malloc for memory allocation is bad for gas. use this assembly instead + */ +library ExecutionLib { + function decodeBatch(bytes calldata callData) + internal + pure + returns (Execution[] calldata executionBatch) + { + /* + * Batch Call Calldata Layout + * Offset (in bytes) | Length (in bytes) | Contents + * 0x0 | 0x4 | bytes4 function selector + * 0x4 | - | + abi.encode(IERC7579Execution.Execution[]) + */ + // solhint-disable-next-line no-inline-assembly + assembly ("memory-safe") { + let dataPointer := add(callData.offset, calldataload(callData.offset)) + + // Extract the ERC7579 Executions + executionBatch.offset := add(dataPointer, 32) + executionBatch.length := calldataload(dataPointer) + } + } + + function encodeBatch(Execution[] memory executions) + internal + pure + returns (bytes memory callData) + { + callData = abi.encode(executions); + } + + function decodeSingle(bytes calldata executionCalldata) + internal + pure + returns (address target, uint256 value, bytes calldata callData) + { + target = address(bytes20(executionCalldata[0:20])); + value = uint256(bytes32(executionCalldata[20:52])); + callData = executionCalldata[52:]; + } + + function encodeSingle( + address target, + uint256 value, + bytes memory callData + ) + internal + pure + returns (bytes memory userOpCalldata) + { + userOpCalldata = abi.encodePacked(target, value, callData); + } +} diff --git a/accounts/safe7579/src/lib/ModeLib.sol b/accounts/safe7579/src/lib/ModeLib.sol new file mode 100644 index 00000000..9c6778f8 --- /dev/null +++ b/accounts/safe7579/src/lib/ModeLib.sol @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +/** + * @title ModeLib + * To allow smart accounts to be very simple, but allow for more complex execution, A custom mode + * encoding is used. + * Function Signature of execute function: + * function execute(ModeCode mode, bytes calldata executionCalldata) external payable; + * This allows for a single bytes32 to be used to encode the execution mode, calltype, execType and + * context. + * NOTE: Simple Account implementations only have to scope for the most significant byte. Account that + * implement + * more complex execution modes may use the entire bytes32. + * + * |--------------------------------------------------------------------| + * | CALLTYPE | EXECTYPE | UNUSED | ModeSelector | ModePayload | + * |--------------------------------------------------------------------| + * | 1 byte | 1 byte | 4 bytes | 4 bytes | 22 bytes | + * |--------------------------------------------------------------------| + * + * CALLTYPE: 1 byte + * CallType is used to determine how the executeCalldata paramter of the execute function has to be + * decoded. + * It can be either single, batch or delegatecall. In the future different calls could be added. + * CALLTYPE can be used by a validation module to determine how to decode . + * + * EXECTYPE: 1 byte + * ExecType is used to determine how the account should handle the execution. + * It can indicate if the execution should revert on failure or continue execution. + * In the future more execution modes may be added. + * Default Behavior (EXECTYPE = 0x00) is to revert on a single failed execution. If one execution in + * a batch fails, the entire batch is reverted + * + * UNUSED: 4 bytes + * Unused bytes are reserved for future use. + * + * ModeSelector: bytes4 + * The "optional" mode selector can be used by account vendors, to implement custom behavior in + * their accounts. + * the way a ModeSelector is to be calculated is bytes4(keccak256("vendorname.featurename")) + * this is to prevent collisions between different vendors, while allowing innovation and the + * development of new features without coordination between ERC-7579 implementing accounts + * + * ModePayload: 22 bytes + * Mode payload is used to pass additional data to the smart account execution, this may be + * interpreted depending on the ModeSelector + * + * ExecutionCallData: n bytes + * single, delegatecall or batch exec abi.encoded as bytes + */ +import { Execution } from "../interfaces/IERC7579Account.sol"; + +// Custom type for improved developer experience +type ModeCode is bytes32; + +type CallType is bytes1; + +type ExecType is bytes1; + +type ModeSelector is bytes4; + +type ModePayload is bytes22; + +// Default CallType +CallType constant CALLTYPE_SINGLE = CallType.wrap(0x00); +// Batched CallType +CallType constant CALLTYPE_BATCH = CallType.wrap(0x01); +// @dev Implementing delegatecall is OPTIONAL! +// implement delegatecall with extreme care. +CallType constant CALLTYPE_STATIC = CallType.wrap(0xFE); +CallType constant CALLTYPE_DELEGATECALL = CallType.wrap(0xFF); + +// @dev default behavior is to revert on failure +// To allow very simple accounts to use mode encoding, the default behavior is to revert on failure +// Since this is value 0x00, no additional encoding is required for simple accounts +ExecType constant EXECTYPE_DEFAULT = ExecType.wrap(0x00); +// @dev account may elect to change execution behavior. For example "try exec" / "allow fail" +ExecType constant EXECTYPE_TRY = ExecType.wrap(0x01); + +ModeSelector constant MODE_DEFAULT = ModeSelector.wrap(bytes4(0x00000000)); +// Example declaration of a custom mode selector +ModeSelector constant MODE_OFFSET = ModeSelector.wrap(bytes4(keccak256("default.mode.offset"))); + +/** + * @dev ModeLib is a helper library to encode/decode ModeCodes + */ +library ModeLib { + function decode(ModeCode mode) + internal + pure + returns ( + CallType _calltype, + ExecType _execType, + ModeSelector _modeSelector, + ModePayload _modePayload + ) + { + assembly { + _calltype := mode + _execType := shl(8, mode) + _modeSelector := shl(48, mode) + _modePayload := shl(80, mode) + } + } + + function encode( + CallType callType, + ExecType execType, + ModeSelector mode, + ModePayload payload + ) + internal + pure + returns (ModeCode) + { + return ModeCode.wrap( + bytes32( + abi.encodePacked(callType, execType, bytes4(0), ModeSelector.unwrap(mode), payload) + ) + ); + } + + function encodeSimpleBatch() internal pure returns (ModeCode mode) { + mode = encode(CALLTYPE_BATCH, EXECTYPE_DEFAULT, MODE_DEFAULT, ModePayload.wrap(0x00)); + } + + function encodeSimpleSingle() internal pure returns (ModeCode mode) { + mode = encode(CALLTYPE_SINGLE, EXECTYPE_DEFAULT, MODE_DEFAULT, ModePayload.wrap(0x00)); + } + + function getCallType(ModeCode mode) internal pure returns (CallType calltype) { + assembly { + calltype := mode + } + } +} + +using { eqModeSelector as == } for ModeSelector global; +using { eqCallType as == } for CallType global; +using { eqExecType as == } for ExecType global; + +function eqCallType(CallType a, CallType b) pure returns (bool) { + return CallType.unwrap(a) == CallType.unwrap(b); +} + +function eqExecType(ExecType a, ExecType b) pure returns (bool) { + return ExecType.unwrap(a) == ExecType.unwrap(b); +} + +function eqModeSelector(ModeSelector a, ModeSelector b) pure returns (bool) { + return ModeSelector.unwrap(a) == ModeSelector.unwrap(b); +} diff --git a/accounts/safe7579/src/utils/DCUtil.sol b/accounts/safe7579/src/utils/DCUtil.sol index 24aac88f..bc599083 100644 --- a/accounts/safe7579/src/utils/DCUtil.sol +++ b/accounts/safe7579/src/utils/DCUtil.sol @@ -1,4 +1,4 @@ -import { Execution } from "erc7579/interfaces/IERC7579Account.sol"; +import { Execution } from "../interfaces/IERC7579Account.sol"; import { IModule as IERC7579Module } from "erc7579/interfaces/IERC7579Module.sol"; import { SimulateTxAccessor } from "@safe-global/safe-contracts/contracts/accessors/SimulateTxAccessor.sol"; diff --git a/accounts/safe7579/test/ERC7579Compliance/ERC1271.t.sol b/accounts/safe7579/test/ERC7579Compliance/ERC1271.t.sol index fe3de84d..9dee685c 100644 --- a/accounts/safe7579/test/ERC7579Compliance/ERC1271.t.sol +++ b/accounts/safe7579/test/ERC7579Compliance/ERC1271.t.sol @@ -21,6 +21,7 @@ contract ERC1271Test is BaseTest { returns (bytes4) { // It should forward the correct msgSender + assertEq(msg.sender, address(account)); assertEq(sender, _sender); assertEq(hash, _hash); // It should slice the correct signature diff --git a/accounts/safe7579/test/Launchpad.t.sol b/accounts/safe7579/test/Launchpad.t.sol index 59cc83db..7835bcda 100644 --- a/accounts/safe7579/test/Launchpad.t.sol +++ b/accounts/safe7579/test/Launchpad.t.sol @@ -127,6 +127,7 @@ contract LaunchpadBase is Test { salt: salt, factoryInitializer: factoryInitializer }); + console2.log("Predicted address: ", predict); userOp.sender = predict; assertEq(userOp.sender, predict); userOp.signature = abi.encodePacked( From e64216487beed3cbe4e4ec2301d964ddd9d17c19 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Fri, 19 Apr 2024 08:04:33 +0700 Subject: [PATCH 50/64] linting fix: linting issues docs --- accounts/safe7579/src/SafeERC7579.sol | 3 - accounts/safe7579/src/core/AccessControl.sol | 5 ++ .../safe7579/src/core/ExecutionHelper.sol | 42 ++++++++----- accounts/safe7579/src/core/ModuleManager.sol | 62 +++++++++++-------- .../safe7579/src/core/RegistryAdapter.sol | 9 ++- .../src/interfaces/IERC7579Account.sol | 1 - accounts/safe7579/src/lib/ModeLib.sol | 3 +- accounts/safe7579/src/utils/DCUtil.sol | 7 ++- accounts/safe7579/src/utils/Launchpad.sol | 25 +++++--- .../test/ERC7579Compliance/ERC4337.t.sol | 1 + 10 files changed, 99 insertions(+), 59 deletions(-) diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index bbe50175..c899705c 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -2,9 +2,6 @@ pragma solidity ^0.8.23; import { IERC7579Account, Execution } from "./interfaces/IERC7579Account.sol"; -import { Enum } from "@safe-global/safe-contracts/contracts/common/Enum.sol"; -import { SimulateTxAccessor } from "./utils/DCUtil.sol"; -import { IMSA } from "erc7579/interfaces/IMSA.sol"; import { CallType, ExecType, diff --git a/accounts/safe7579/src/core/AccessControl.sol b/accounts/safe7579/src/core/AccessControl.sol index 5a866403..2f264117 100644 --- a/accounts/safe7579/src/core/AccessControl.sol +++ b/accounts/safe7579/src/core/AccessControl.sol @@ -4,6 +4,11 @@ pragma solidity >=0.8.0 <0.9.0; import { HandlerContext } from "@safe-global/safe-contracts/contracts/handler/HandlerContext.sol"; import { AccountBase } from "erc7579/core/AccountBase.sol"; +/** + * Implements AccessControl for Safe7579 adapter. + * Since Safe7579 Adapter is installed as a fallback handler on the safe account, we are making use + * of handlercontext (ERC2771) + */ contract AccessControl is HandlerContext, AccountBase { modifier onlyEntryPointOrSelf() virtual override { if (!(_msgSender() == entryPoint() || msg.sender == _msgSender())) { diff --git a/accounts/safe7579/src/core/ExecutionHelper.sol b/accounts/safe7579/src/core/ExecutionHelper.sol index 63dc9c1e..a51d5d4f 100644 --- a/accounts/safe7579/src/core/ExecutionHelper.sol +++ b/accounts/safe7579/src/core/ExecutionHelper.sol @@ -8,7 +8,17 @@ import { BatchedExecUtil } from "../utils/DCUtil.sol"; import { Execution } from "../interfaces/IERC7579Account.sol"; import { ISafe } from "../interfaces/ISafe.sol"; -contract ExecutionHelper is Safe7579DCUtilSetup { +/** + * Abstraction layer for executions. + * @dev All interactions with modules must originate from msg.sender == SafeProxy. This entails + * avoiding direct calls by the Safe7579 Adapter for actions like onInstall on modules or + * validateUserOp on validator modules, and utilizing the Safe's execTransactionFromModule feature + * instead. + * @dev Since Safe7579 offers features like TryExecute for batched executions, rewriting and + * verifying execution success across the codebase can be challenging and error-prone. These + * functions serve to interact with modules and external contracts. + */ +abstract contract ExecutionHelper is Safe7579DCUtilSetup { event TryExecutionFailed(ISafe safe, uint256 numberInBatch); event TryExecutionsFailed(ISafe safe, bool[] success); @@ -151,6 +161,17 @@ contract ExecutionHelper is Safe7579DCUtilSetup { /* STATICCALL TRICK */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + /** + * Safe account does not natively implement Enum.Operation.StaticCall, + * to still receive some guarantees, that the target contract of calls, can not do state + * changes, we are making use of Safe's SimulateTxAccessor. + * @dev This function will nudge the Safe account to make a delegatecall to the DCUTIL contract, + * which inherits SimulateTxAccessor and call the simulate() function there. + * This ensures, that the target contract can not do state changes + * @param safe Safe account to execute the staticcall + * @param target Target contract to staticcall + * @param callData Data to be passed to the target contract + */ function _staticcallReturn( ISafe safe, address target, @@ -161,23 +182,14 @@ contract ExecutionHelper is Safe7579DCUtilSetup { { bytes memory ret = _delegatecallReturn({ safe: safe, - target: UTIL, + target: UTIL, // immutable address for DCUTIL (./utils/DCUTIL.sol) callData: abi.encodeCall( - SimulateTxAccessor.simulate, - (target, 0, abi.encodePacked(callData, _msgSender()), Enum.Operation.Call) + SimulateTxAccessor.simulate, (target, 0, callData, Enum.Operation.Call) ) }); - (,, retData) = abi.decode(ret, (uint256, bool, bytes)); + bool success; + (, success, retData) = abi.decode(ret, (uint256, bool, bytes)); + if (!success) revert ExecutionFailed(); return retData; } } - -function _msgSender() pure returns (address sender) { - // The assembly code is more direct than the Solidity version using `abi.decode`. - /* solhint-disable no-inline-assembly */ - /// @solidity memory-safe-assembly - assembly { - sender := shr(96, calldataload(sub(calldatasize(), 20))) - } - /* solhint-enable no-inline-assembly */ -} diff --git a/accounts/safe7579/src/core/ModuleManager.sol b/accounts/safe7579/src/core/ModuleManager.sol index d230ecb7..e92e4a7c 100644 --- a/accounts/safe7579/src/core/ModuleManager.sol +++ b/accounts/safe7579/src/core/ModuleManager.sol @@ -4,17 +4,13 @@ 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 { SimulateTxAccessor } from "../utils/DCUtil.sol"; import { ISafe } from "../interfaces/ISafe.sol"; import { Safe7579DCUtil, ModuleInstallUtil } from "../utils/DCUtil.sol"; -import { Enum } from "@safe-global/safe-contracts/contracts/common/Enum.sol"; import { RegistryAdapter } from "./RegistryAdapter.sol"; import { Receiver } from "erc7579/core/Receiver.sol"; import { AccessControl } from "./AccessControl.sol"; -import { ExecutionHelper } from "./ExecutionHelper.sol"; -import { Safe7579DCUtil, Safe7579DCUtilSetup } from "./SetupDCUtil.sol"; -import { CallType, CALLTYPE_SINGLE, CALLTYPE_DELEGATECALL } from "../lib/ModeLib.sol"; +import { CallType, CALLTYPE_STATIC, CALLTYPE_SINGLE } from "../lib/ModeLib.sol"; import { MODULE_TYPE_VALIDATOR, @@ -23,23 +19,19 @@ import { MODULE_TYPE_HOOK } from "erc7579/interfaces/IERC7579Module.sol"; -CallType constant CALLTYPE_STATIC = CallType.wrap(0xFE); - -// struct FallbackHandler { -// address handler; -// CallType calltype; -// } -// -// struct ModuleManagerStorage { -// // linked list of executors. List is initialized by initializeAccount() -// SentinelListLib.SentinelList _executors; -// mapping(bytes4 selector => FallbackHandler fallbackHandler) _fallbacks; -// } - /** * @title ModuleManager * Contract that implements ERC7579 Module compatibility for Safe accounts * @author zeroknots.eth | rhinestone.wtf + * @dev All Module types are handled within this + * contract. To make it a bit easier to read, the contract is split into different sections: + * - Validator Modules + * - Executor Modules + * - Fallback Modules + * - Hook Modules + * Note: the Storage mappings for each section, are not listed on the very top, but in the + * respective section + * */ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { using SentinelListLib for SentinelListLib.SentinelList; @@ -47,16 +39,14 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { error InvalidModule(address module); error LinkedListError(); - error CannotRemoveLastValidator(); error InitializerError(); error ValidatorStorageHelperError(); - error NoFallbackHandler(bytes4 msgSig); - error InvalidFallbackHandler(bytes4 msgSig); - error FallbackInstalled(bytes4 msgSig); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* VALIDATOR MODULES */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + // No mapping account => list necessary. this sentinellist flavour handles associated storage to + // smart account itself to comply with 4337 storage restrictions SentinelList4337Lib.SentinelList internal $validators; /** @@ -197,6 +187,10 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* FALLBACK MODULES */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + error NoFallbackHandler(bytes4 msgSig); + error InvalidFallbackHandler(bytes4 msgSig); + error FallbackInstalled(bytes4 msgSig); + struct FallbackHandler { address handler; CallType calltype; @@ -271,7 +265,11 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { return $fallbacks.handler == _handler; } - // FALLBACK + /** + * Fallback implementation supports callTypes: + * - CALLTYPE_STATIC + * - CALLTYPE_SINGLE + */ // solhint-disable-next-line no-complex-fallback fallback(bytes calldata callData) external @@ -291,22 +289,30 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { private returns (bytes memory fallbackRet) { + // get handler for specific function selector FallbackHandler storage $fallbacks = $fallbackStorage[msg.sender][msg.sig]; address handler = $fallbacks.handler; CallType calltype = $fallbacks.calltype; + // if no handler is set for the msg.sig, revert if (handler == address(0)) revert NoFallbackHandler(msg.sig); + // according to ERC7579, when calling to fallback modules, ERC2771 msg.sender has to be + // appended to the calldata, this allows fallback modules to implement + // authorization control if (calltype == CALLTYPE_STATIC) { - return - _staticcallReturn({ safe: ISafe(msg.sender), target: handler, callData: callData }); + return _staticcallReturn({ + safe: ISafe(msg.sender), + target: handler, + callData: abi.encodePacked(callData, _msgSender()) // append ERC2771 + }); } if (calltype == CALLTYPE_SINGLE) { return _execReturn({ safe: ISafe(msg.sender), target: handler, value: 0, - callData: abi.encodePacked(callData, _msgSender()) - }); + callData: abi.encodePacked(callData, _msgSender()) // append ERC2771 + }); } } @@ -356,6 +362,7 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { } $hookManager[msg.sender][selector] = hook; + // delegatecall neccessary, since event for installModule has to be emitted by SafeProxy _delegatecall({ safe: ISafe(msg.sender), target: UTIL, @@ -369,6 +376,7 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { (bytes4 selector, bytes memory initData) = abi.decode(data, (bytes4, bytes)); delete $hookManager[msg.sender][selector]; + // delegatecall neccessary, since event for uninstallModule has to be emitted by SafeProxy _delegatecall({ safe: ISafe(msg.sender), target: UTIL, diff --git a/accounts/safe7579/src/core/RegistryAdapter.sol b/accounts/safe7579/src/core/RegistryAdapter.sol index 1faa12ef..6744a537 100644 --- a/accounts/safe7579/src/core/RegistryAdapter.sol +++ b/accounts/safe7579/src/core/RegistryAdapter.sol @@ -2,8 +2,14 @@ pragma solidity ^0.8.23; import { IERC7484 } from "../interfaces/IERC7484.sol"; -import "./ExecutionHelper.sol"; +import { ExecutionHelper } from "./ExecutionHelper.sol"; +import { ISafe } from "../interfaces/ISafe.sol"; +/** + * IERC7484 Registry adapter. + * this feature is opt-in. The smart account owner can choose to use the registry and which + * attesters to trust. + */ abstract contract RegistryAdapter is ExecutionHelper { event ERC7484RegistryConfigured(address indexed smartAccount, address indexed registry); @@ -17,6 +23,7 @@ abstract contract RegistryAdapter is ExecutionHelper { function _checkRegistry(address module, uint256 moduleType) internal view { IERC7484 registry = $registry[msg.sender]; if (address(registry) != address(0)) { + // this will revert if attestations / threshold are not met registry.checkForAccount(msg.sender, module, moduleType); } } diff --git a/accounts/safe7579/src/interfaces/IERC7579Account.sol b/accounts/safe7579/src/interfaces/IERC7579Account.sol index a4bcefc6..7904d829 100644 --- a/accounts/safe7579/src/interfaces/IERC7579Account.sol +++ b/accounts/safe7579/src/interfaces/IERC7579Account.sol @@ -2,7 +2,6 @@ pragma solidity ^0.8.21; import { CallType, ExecType, ModeCode } from "../lib/ModeLib.sol"; -import { PackedUserOperation } from "account-abstraction/interfaces/IAccount.sol"; struct Execution { address target; diff --git a/accounts/safe7579/src/lib/ModeLib.sol b/accounts/safe7579/src/lib/ModeLib.sol index 9c6778f8..61aa583e 100644 --- a/accounts/safe7579/src/lib/ModeLib.sol +++ b/accounts/safe7579/src/lib/ModeLib.sol @@ -49,7 +49,6 @@ pragma solidity ^0.8.23; * ExecutionCallData: n bytes * single, delegatecall or batch exec abi.encoded as bytes */ -import { Execution } from "../interfaces/IERC7579Account.sol"; // Custom type for improved developer experience type ModeCode is bytes32; @@ -96,6 +95,7 @@ library ModeLib { ModePayload _modePayload ) { + // solhint-disable-next-line no-inline-assembly assembly { _calltype := mode _execType := shl(8, mode) @@ -130,6 +130,7 @@ library ModeLib { } function getCallType(ModeCode mode) internal pure returns (CallType calltype) { + // solhint-disable-next-line no-inline-assembly assembly { calltype := mode } diff --git a/accounts/safe7579/src/utils/DCUtil.sol b/accounts/safe7579/src/utils/DCUtil.sol index bc599083..d3f714c4 100644 --- a/accounts/safe7579/src/utils/DCUtil.sol +++ b/accounts/safe7579/src/utils/DCUtil.sol @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.22; + import { Execution } from "../interfaces/IERC7579Account.sol"; import { IModule as IERC7579Module } from "erc7579/interfaces/IERC7579Module.sol"; import { SimulateTxAccessor } from @@ -85,7 +88,7 @@ contract BatchedExecUtil { virtual returns (bytes memory result) { - /// @solidity memory-safe-assembly + // solhint-disable-next-line no-inline-assembly assembly { result := mload(0x40) calldatacopy(result, callData.offset, callData.length) @@ -110,7 +113,7 @@ contract BatchedExecUtil { virtual returns (bool success, bytes memory result) { - /// @solidity memory-safe-assembly + // solhint-disable-next-line no-inline-assembly assembly { result := mload(0x40) calldatacopy(result, callData.offset, callData.length) diff --git a/accounts/safe7579/src/utils/Launchpad.sol b/accounts/safe7579/src/utils/Launchpad.sol index 1d89d73d..5c0652f9 100644 --- a/accounts/safe7579/src/utils/Launchpad.sol +++ b/accounts/safe7579/src/utils/Launchpad.sol @@ -51,8 +51,15 @@ contract Safe7579Launchpad is IAccount, SafeStorage { address public immutable SUPPORTED_ENTRYPOINT; IERC7484 public immutable REGISTRY; + error InvalidEntryPoint(); + error OnlyDelegatecall(); + error OnlyProxy(); + error PreValidationSetupFailed(); + error InvalidUserOperationData(); + error InvalidInitHash(); + constructor(address entryPoint, IERC7484 registry) { - require(entryPoint != address(0), "Invalid entry point"); + if (entryPoint == address(0)) revert InvalidEntryPoint(); SELF = address(this); SUPPORTED_ENTRYPOINT = entryPoint; @@ -60,17 +67,17 @@ contract Safe7579Launchpad is IAccount, SafeStorage { } modifier onlyDelegatecall() { - require(msg.sender == address(this), "Only delegatecall"); + if (msg.sender != address(this)) revert OnlyDelegatecall(); _; } modifier onlyProxy() { - require(singleton == SELF, "Not called from proxy"); + if (singleton != SELF) revert OnlyProxy(); _; } modifier onlySupportedEntryPoint() { - require(msg.sender == SUPPORTED_ENTRYPOINT, "Unsupported entry point"); + if (msg.sender != SUPPORTED_ENTRYPOINT) revert InvalidEntryPoint(); _; } @@ -128,7 +135,7 @@ contract Safe7579Launchpad is IAccount, SafeStorage { // if a delegatecall target is provided, SafeProxy will execute a delegatecall if (to != address(0)) { (bool success,) = to.delegatecall(preInit); - require(success, "Pre-initialization failed"); + if (!success) revert PreValidationSetupFailed(); } } @@ -162,13 +169,13 @@ contract Safe7579Launchpad is IAccount, SafeStorage { onlySupportedEntryPoint returns (uint256 validationData) { - require( - this.setupSafe.selector == bytes4(userOp.callData[:4]), "invalid user operation data" - ); + if (this.setupSafe.selector != bytes4(userOp.callData[:4])) { + revert InvalidUserOperationData(); + } InitData memory initData = abi.decode(userOp.callData[4:], (InitData)); // read stored initHash from SafeProxy storage. only proceed if the InitData hash matches - require(hash(initData) == _initHash(), "invalid init hash"); + if (hash(initData) != _initHash()) revert InvalidInitHash(); // get validator from nonce encoding address validator; diff --git a/accounts/safe7579/test/ERC7579Compliance/ERC4337.t.sol b/accounts/safe7579/test/ERC7579Compliance/ERC4337.t.sol index 9cc22d37..369fee30 100644 --- a/accounts/safe7579/test/ERC7579Compliance/ERC4337.t.sol +++ b/accounts/safe7579/test/ERC7579Compliance/ERC4337.t.sol @@ -32,6 +32,7 @@ contract ERC4337Test is BaseTest { override returns (uint256) { + assertEq(msg.sender, address(account)); assertEq(userOp.callData, _calldata); assertEq(userOpHash, _userOpHash); return _ret; From 4c9b2bbc6ed12e6af06c3459b7153bf8545f92bc Mon Sep 17 00:00:00 2001 From: zeroknots Date: Fri, 19 Apr 2024 10:07:00 +0700 Subject: [PATCH 51/64] feat: adding global and sig specific hooks --- accounts/safe7579/src/SafeERC7579.sol | 20 +-- accounts/safe7579/src/core/ModuleManager.sol | 125 ++++++++++++++---- .../src/interfaces/IERC7579Module.sol | 96 ++++++++++++++ .../test/ERC7579Compliance/Base.t.sol | 9 +- .../test/ERC7579Compliance/Hooks.t.sol | 45 ++++++- .../ERC7579Compliance/ModuleManagement.t.sol | 48 +++++-- 6 files changed, 294 insertions(+), 49 deletions(-) create mode 100644 accounts/safe7579/src/interfaces/IERC7579Module.sol diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index c899705c..4a298884 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -72,8 +72,9 @@ contract SafeERC7579 is ISafeOp, IERC7579Account, ISafe7579Init, AccessControl, ) external payable - withGlobalHook - withSelectorHook(IERC7579Account.execute.selector) + withHook(IERC7579Account.execute.selector) + // withGlobalHook + // withSelectorHook(IERC7579Account.execute.selector) onlyEntryPointOrSelf { CallType callType; @@ -156,10 +157,13 @@ contract SafeERC7579 is ISafeOp, IERC7579Account, ISafe7579Init, AccessControl, payable override onlyExecutorModule + withHook(IERC7579Account.executeFromExecutor.selector) withRegistry(msg.sender, MODULE_TYPE_EXECUTOR) - withGlobalHook - withSelectorHook(IERC7579Account.execute.selector) - returns (bytes[] memory returnDatas) + returns ( + // withGlobalHook + // withSelectorHook(IERC7579Account.execute.selector) + bytes[] memory returnDatas + ) { CallType callType; ExecType execType; @@ -395,8 +399,7 @@ contract SafeERC7579 is ISafeOp, IERC7579Account, ISafe7579Init, AccessControl, external payable override - withGlobalHook - withSelectorHook(IERC7579Account.installModule.selector) + withHook(IERC7579Account.installModule.selector) onlyEntryPointOrSelf { if (moduleType == MODULE_TYPE_VALIDATOR) _installValidator(module, initData); @@ -417,8 +420,7 @@ contract SafeERC7579 is ISafeOp, IERC7579Account, ISafe7579Init, AccessControl, external payable override - withGlobalHook - withSelectorHook(IERC7579Account.installModule.selector) + withHook(IERC7579Account.uninstallModule.selector) onlyEntryPointOrSelf { if (moduleType == MODULE_TYPE_VALIDATOR) _uninstallValidator(module, deInitData); diff --git a/accounts/safe7579/src/core/ModuleManager.sol b/accounts/safe7579/src/core/ModuleManager.sol index e92e4a7c..b967fee3 100644 --- a/accounts/safe7579/src/core/ModuleManager.sol +++ b/accounts/safe7579/src/core/ModuleManager.sol @@ -3,7 +3,7 @@ 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 { IModule, IHook } from "../interfaces/IERC7579Module.sol"; import { ISafe } from "../interfaces/ISafe.sol"; import { Safe7579DCUtil, ModuleInstallUtil } from "../utils/DCUtil.sol"; @@ -277,8 +277,7 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { virtual override(Receiver) receiverFallback - withGlobalHook - withSelectorHook(msg.sig) + withHook(msg.sig) returns (bytes memory fallbackRet) { // using JUMPI to avoid stack too deep @@ -325,26 +324,59 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { error HookPostCheckFailed(); error HookAlreadyInstalled(address currentHook); + error InvalidHookType(); enum HookType { GLOBAL, SIG } - modifier withSelectorHook(bytes4 hookSig) { - address hook = $hookManager[msg.sender][hookSig]; - bytes memory _data; - // if (enabled) _data = ISafe(msg.sender).preHook({ withHook: hook }); - _; - // if (enabled) ISafe(msg.sender).postHook({ withHook: hook, hookPreContext: _data }); + function _preHooks(bytes4 selector) internal returns (bytes memory global, bytes memory sig) { + address globalHook = $globalHook[msg.sender]; + address sigHook = $hookManager[msg.sender][selector]; + if (globalHook != address(0)) { + global = _execReturn({ + safe: ISafe(msg.sender), + target: globalHook, + value: 0, + callData: abi.encodeCall(IHook.preCheck, (_msgSender(), msg.value, msg.data)) + }); + } + if (sigHook != address(0)) { + sig = _execReturn({ + safe: ISafe(msg.sender), + target: sigHook, + value: 0, + callData: abi.encodeCall(IHook.preCheck, (_msgSender(), msg.value, msg.data)) + }); + } + } + + function _postHooks(bytes4 selector, bytes memory global, bytes memory sig) internal { + address globalHook = $globalHook[msg.sender]; + address sigHook = $hookManager[msg.sender][selector]; + if (globalHook != address(0)) { + _exec({ + safe: ISafe(msg.sender), + target: globalHook, + value: 0, + callData: abi.encodeCall(IHook.postCheck, (global)) + }); + } + if (sigHook != address(0)) { + _exec({ + safe: ISafe(msg.sender), + target: sigHook, + value: 0, + callData: abi.encodeCall(IHook.postCheck, (sig)) + }); + } } - modifier withGlobalHook() { - address hook = $globalHook[msg.sender]; - bytes memory _data; - // if (enabled) _data = ISafe(msg.sender).preHook({ withHook: hook }); + modifier withHook(bytes4 selector) { + (bytes memory global, bytes memory sig) = _preHooks(selector); _; - // if (enabled) ISafe(msg.sender).postHook({ withHook: hook, hookPreContext: _data }); + _postHooks(selector, global, sig); } function _installHook( @@ -355,12 +387,30 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { virtual withRegistry(hook, MODULE_TYPE_HOOK) { - (bytes4 selector, bytes memory initData) = abi.decode(data, (bytes4, bytes)); - address currentHook = $hookManager[msg.sender][selector]; - if (currentHook != address(0)) { - revert HookAlreadyInstalled(currentHook); + (HookType hookType, bytes4 selector, bytes memory initData) = + abi.decode(data, (HookType, bytes4, bytes)); + address currentHook; + + // handle global hooks + if (hookType == HookType.GLOBAL && selector == 0x00000000) { + currentHook = $globalHook[msg.sender]; + // Dont allow hooks to be overwritten. If a hook is currently installed, it must be + // uninstalled first + if (currentHook != address(0)) { + revert HookAlreadyInstalled(currentHook); + } + $globalHook[msg.sender] = hook; + } else if (hookType == HookType.SIG) { + // Dont allow hooks to be overwritten. If a hook is currently installed, it must be + // uninstalled first + if (currentHook != address(0)) { + revert HookAlreadyInstalled(currentHook); + } + currentHook = $hookManager[msg.sender][selector]; + $hookManager[msg.sender][selector] = hook; + } else { + revert InvalidHookType(); } - $hookManager[msg.sender][selector] = hook; // delegatecall neccessary, since event for installModule has to be emitted by SafeProxy _delegatecall({ @@ -373,8 +423,15 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { } function _uninstallHook(address hook, bytes calldata data) internal virtual { - (bytes4 selector, bytes memory initData) = abi.decode(data, (bytes4, bytes)); - delete $hookManager[msg.sender][selector]; + (HookType hookType, bytes4 selector, bytes memory initData) = + abi.decode(data, (HookType, bytes4, bytes)); + if (hookType == HookType.GLOBAL && selector == 0x0) { + delete $globalHook[msg.sender]; + } else if (hookType == HookType.SIG) { + delete $hookManager[msg.sender][selector]; + } else { + revert InvalidHookType(); + } // delegatecall neccessary, since event for uninstallModule has to be emitted by SafeProxy _delegatecall({ @@ -386,6 +443,23 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { }); } + function _getCurrentHook( + HookType hookType, + bytes4 selector + ) + internal + view + returns (address hook) + { + // handle global hooks + if (hookType == HookType.GLOBAL && selector == 0x0) { + hook = $globalHook[msg.sender]; + } + if (hookType == HookType.SIG) { + hook = $hookManager[msg.sender][selector]; + } + } + function _isHookInstalled( address module, bytes calldata context @@ -394,11 +468,16 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { view returns (bool) { - bytes4 selector = abi.decode(context, (bytes4)); - return $hookManager[msg.sender][selector] == module; + (HookType hookType, bytes4 selector) = abi.decode(context, (HookType, bytes4)); + address hook = _getCurrentHook({ hookType: hookType, selector: selector }); + return hook == module; } function getActiveHook(bytes4 selector) public view returns (address hook) { return $hookManager[msg.sender][selector]; } + + function getActiveHook() public view returns (address hook) { + return $globalHook[msg.sender]; + } } diff --git a/accounts/safe7579/src/interfaces/IERC7579Module.sol b/accounts/safe7579/src/interfaces/IERC7579Module.sol new file mode 100644 index 00000000..a8217024 --- /dev/null +++ b/accounts/safe7579/src/interfaces/IERC7579Module.sol @@ -0,0 +1,96 @@ +pragma solidity ^0.8.21; + +import { PackedUserOperation } from "account-abstraction/interfaces/PackedUserOperation.sol"; + +uint256 constant VALIDATION_SUCCESS = 0; +uint256 constant VALIDATION_FAILED = 1; + +uint256 constant MODULE_TYPE_VALIDATOR = 1; +uint256 constant MODULE_TYPE_EXECUTOR = 2; +uint256 constant MODULE_TYPE_FALLBACK = 3; +uint256 constant MODULE_TYPE_HOOK = 4; + +interface IModule { + error AlreadyInitialized(address smartAccount); + error NotInitialized(address smartAccount); + + /** + * @dev This function is called by the smart account during installation of the module + * @param data arbitrary data that may be required on the module during `onInstall` + * initialization + * + * MUST revert on error (i.e. if module is already enabled) + */ + function onInstall(bytes calldata data) external; + + /** + * @dev This function is called by the smart account during uninstallation of the module + * @param data arbitrary data that may be required on the module during `onUninstall` + * de-initialization + * + * MUST revert on error + */ + function onUninstall(bytes calldata data) external; + + /** + * @dev Returns boolean value if module is a certain type + * @param moduleTypeId the module type ID according the ERC-7579 spec + * + * MUST return true if the module is of the given type and false otherwise + */ + function isModuleType(uint256 moduleTypeId) external view returns (bool); + + /** + * @dev Returns if the module was already initialized for a provided smartaccount + */ + function isInitialized(address smartAccount) external view returns (bool); +} + +interface IValidator is IModule { + error InvalidTargetAddress(address target); + + /** + * @dev Validates a transaction on behalf of the account. + * This function is intended to be called by the MSA during the ERC-4337 validaton phase + * Note: solely relying on bytes32 hash and signature is not suffcient for some + * validation implementations (i.e. SessionKeys often need access to userOp.calldata) + * @param userOp The user operation to be validated. The userOp MUST NOT contain any metadata. + * The MSA MUST clean up the userOp before sending it to the validator. + * @param userOpHash The hash of the user operation to be validated + * @return return value according to ERC-4337 + */ + function validateUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash + ) + external + returns (uint256); + + /** + * Validator can be used for ERC-1271 validation + */ + function isValidSignatureWithSender( + address sender, + bytes32 hash, + bytes calldata data + ) + external + view + returns (bytes4); +} + +interface IExecutor is IModule { } + +interface IHook is IModule { + function preCheck( + address msgSender, + uint256 msgValue, + bytes calldata msgData + ) + external + returns (bytes memory hookData); + + function postCheck(bytes calldata hookData) external; +} + +interface IFallback is IModule { } diff --git a/accounts/safe7579/test/ERC7579Compliance/Base.t.sol b/accounts/safe7579/test/ERC7579Compliance/Base.t.sol index c2956053..5392d2fe 100644 --- a/accounts/safe7579/test/ERC7579Compliance/Base.t.sol +++ b/accounts/safe7579/test/ERC7579Compliance/Base.t.sol @@ -50,16 +50,11 @@ contract MockModule is IModule { bytes calldata msgData ) external + virtual returns (bytes memory hookData) { } - function postCheck( - bytes calldata hookData, - bool executionSuccess, - bytes calldata executionReturnValue - ) - external - { } + function postCheck(bytes calldata hookData) external virtual { } } contract BaseTest is LaunchpadBase, MockModule { diff --git a/accounts/safe7579/test/ERC7579Compliance/Hooks.t.sol b/accounts/safe7579/test/ERC7579Compliance/Hooks.t.sol index 82edc201..6249ee81 100644 --- a/accounts/safe7579/test/ERC7579Compliance/Hooks.t.sol +++ b/accounts/safe7579/test/ERC7579Compliance/Hooks.t.sol @@ -1,7 +1,37 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.0; +pragma solidity ^0.8.0; + +import "./ModuleManagement.t.sol"; +// import "src/lib/ModeLib.sol"; +import "forge-std/console2.sol"; + +interface MockFn { + function fallbackFn(bytes32 value) external returns (bytes32); +} + +contract HookTest is ModuleManagementTest, MockFn { + function fallbackFn(bytes32 value) external returns (bytes32) { + return value; + } + + function onInstall(bytes calldata data) public virtual override { } + + function preCheck( + address msgSender, + uint256 msgValue, + bytes calldata msgData + ) + external + override + returns (bytes memory hookData) + { + console2.log("preCheck"); + } + + function setUp() public virtual override { + super.setUp(); + } -contract HookTest { function test_WhenExecutingVia4337() external { // It should execute hook } @@ -10,6 +40,17 @@ contract HookTest { // It should execute hook } + function test_WhenUsingFallbacks() external asEntryPoint { + // It should execute hook + _data = hex"4141414141414141"; + account.installModule(3, SELF, abi.encode(this.fallbackFn.selector, CALLTYPE_SINGLE, _data)); + _installHook(ModuleManager.HookType.SIG, this.fallbackFn.selector, ""); + + bytes32 val = bytes32(bytes(hex"414141414141")); + bytes32 ret = MockFn(address(account)).fallbackFn(val); + assertEq(ret, val); + } + function test_WhenInstallingModule() external { // It should execute hook } diff --git a/accounts/safe7579/test/ERC7579Compliance/ModuleManagement.t.sol b/accounts/safe7579/test/ERC7579Compliance/ModuleManagement.t.sol index a87ba16f..0544a344 100644 --- a/accounts/safe7579/test/ERC7579Compliance/ModuleManagement.t.sol +++ b/accounts/safe7579/test/ERC7579Compliance/ModuleManagement.t.sol @@ -2,7 +2,8 @@ pragma solidity ^0.8.0; import "./Base.t.sol"; -import "erc7579/lib/ModeLib.sol"; +// import "src/lib/ModeLib.sol"; +import { CALLTYPE_SINGLE, ModuleManager } from "src/core/ModuleManager.sol"; contract ModuleManagementTest is BaseTest { bytes _data; @@ -11,7 +12,7 @@ contract ModuleManagementTest is BaseTest { super.setUp(); } - function onInstall(bytes calldata data) public override { + function onInstall(bytes calldata data) public virtual override { assertEq(_data, data); assertEq(msg.sender, address(account)); } @@ -51,14 +52,45 @@ contract ModuleManagementTest is BaseTest { assertFalse(account.isModuleInstalled(3, SELF, abi.encode(selector))); } - function test_WhenInstallingHooks() external asEntryPoint { + function _installHook( + ModuleManager.HookType hookType, + bytes4 selector, + bytes memory initData + ) + public + { + bytes memory data = abi.encode(hookType, selector, initData); + account.installModule(4, SELF, data); + assertTrue(account.isModuleInstalled(4, SELF, abi.encode(hookType, selector))); + } + + function _uninstallHook( + ModuleManager.HookType hookType, + bytes4 selector, + bytes memory initData + ) + public + { + bytes memory data = abi.encode(hookType, selector, initData); + account.uninstallModule(4, SELF, data); + assertFalse(account.isModuleInstalled(4, SELF, abi.encode(hookType, selector))); + } + + function test_WhenInstallingHooks_SIG() external asEntryPoint { + ModuleManager.HookType hookType = ModuleManager.HookType.SIG; bytes4 selector = MockTarget.set.selector; _data = hex"4141414141414141"; - assertFalse(account.isModuleInstalled(4, SELF, abi.encode(selector))); - account.installModule(4, SELF, abi.encode(selector, _data)); - assertTrue(account.isModuleInstalled(4, SELF, abi.encode(selector))); - account.uninstallModule(4, SELF, abi.encode(selector, _data)); - assertFalse(account.isModuleInstalled(4, SELF, abi.encode(selector))); + _installHook(hookType, selector, _data); + _uninstallHook(hookType, selector, _data); + } + + function test_WhenInstallingHooks_GLOBAL() external asEntryPoint { + ModuleManager.HookType hookType = ModuleManager.HookType.GLOBAL; + bytes4 selector = 0x00000000; + _data = hex"4141414141414141"; + + _installHook(hookType, selector, _data); + _uninstallHook(hookType, selector, _data); } } From b8033a7c44e19f718dbacc8c829619dfdf1de282 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Fri, 19 Apr 2024 11:02:16 +0700 Subject: [PATCH 52/64] feat: adding multitype install --- accounts/safe7579/src/SafeERC7579.sol | 9 -- accounts/safe7579/src/core/ModuleManager.sol | 105 ++++++++++++++++-- .../test/ERC7579Compliance/Hooks.t.sol | 25 ++++- 3 files changed, 119 insertions(+), 20 deletions(-) diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index 4a298884..9dfbb1fd 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -255,15 +255,6 @@ contract SafeERC7579 is ISafeOp, IERC7579Account, ISafe7579Init, AccessControl, } } - // TODO: delete this. need to update IERC7579Account - function executeUserOp( - PackedUserOperation calldata userOp, - bytes32 userOpHash - ) - external - payable - { } - /** * ERC4337 v0.7 validation function * @dev expects that a ERC7579 validator module is encoded within the UserOp nonce. diff --git a/accounts/safe7579/src/core/ModuleManager.sol b/accounts/safe7579/src/core/ModuleManager.sol index b967fee3..12bebfc3 100644 --- a/accounts/safe7579/src/core/ModuleManager.sol +++ b/accounts/safe7579/src/core/ModuleManager.sol @@ -11,7 +11,6 @@ import { RegistryAdapter } from "./RegistryAdapter.sol"; import { Receiver } from "erc7579/core/Receiver.sol"; import { AccessControl } from "./AccessControl.sol"; import { CallType, CALLTYPE_STATIC, CALLTYPE_SINGLE } from "../lib/ModeLib.sol"; - import { MODULE_TYPE_VALIDATOR, MODULE_TYPE_EXECUTOR, @@ -41,6 +40,7 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { error LinkedListError(); error InitializerError(); error ValidatorStorageHelperError(); + error InvalidInput(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* VALIDATOR MODULES */ @@ -331,9 +331,13 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { SIG } - function _preHooks(bytes4 selector) internal returns (bytes memory global, bytes memory sig) { - address globalHook = $globalHook[msg.sender]; - address sigHook = $hookManager[msg.sender][selector]; + function _preHooks( + address globalHook, + address sigHook + ) + internal + returns (bytes memory global, bytes memory sig) + { if (globalHook != address(0)) { global = _execReturn({ safe: ISafe(msg.sender), @@ -341,6 +345,7 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { value: 0, callData: abi.encodeCall(IHook.preCheck, (_msgSender(), msg.value, msg.data)) }); + global = abi.decode(global, (bytes)); } if (sigHook != address(0)) { sig = _execReturn({ @@ -349,12 +354,18 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { value: 0, callData: abi.encodeCall(IHook.preCheck, (_msgSender(), msg.value, msg.data)) }); + sig = abi.decode(sig, (bytes)); } } - function _postHooks(bytes4 selector, bytes memory global, bytes memory sig) internal { - address globalHook = $globalHook[msg.sender]; - address sigHook = $hookManager[msg.sender][selector]; + function _postHooks( + address globalHook, + address sigHook, + bytes memory global, + bytes memory sig + ) + internal + { if (globalHook != address(0)) { _exec({ safe: ISafe(msg.sender), @@ -374,9 +385,11 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { } modifier withHook(bytes4 selector) { - (bytes memory global, bytes memory sig) = _preHooks(selector); + address globalHook = $globalHook[msg.sender]; + address sigHook = $hookManager[msg.sender][selector]; + (bytes memory global, bytes memory sig) = _preHooks(globalHook, sigHook); _; - _postHooks(selector, global, sig); + _postHooks(globalHook, sigHook, global, sig); } function _installHook( @@ -392,7 +405,7 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { address currentHook; // handle global hooks - if (hookType == HookType.GLOBAL && selector == 0x00000000) { + if (hookType == HookType.GLOBAL && selector == 0x0) { currentHook = $globalHook[msg.sender]; // Dont allow hooks to be overwritten. If a hook is currently installed, it must be // uninstalled first @@ -480,4 +493,76 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { function getActiveHook() public view returns (address hook) { return $globalHook[msg.sender]; } + + function _multiTypeInstall( + address module, + uint256[] calldata types, + bytes[] calldata contexts, + bytes calldata onInstallData + ) + internal + { + uint256 length = types.length; + if (contexts.length != length) revert InvalidInput(); + + for (uint256 i; i < length; i++) { + uint256 _type = types[i]; + + if (_type == MODULE_TYPE_VALIDATOR) { + $validators.push({ account: msg.sender, newEntry: module }); + } else if (_type == MODULE_TYPE_EXECUTOR) { + $executorStorage[msg.sender].push(module); + } else if (_type == MODULE_TYPE_FALLBACK) { + // do nothing + + (bytes4 functionSig, CallType calltype) = + abi.decode(contexts[i], (bytes4, CallType)); + + // disallow calls to onInstall or onUninstall. + // this could create a security issue + if ( + functionSig == IModule.onInstall.selector + || functionSig == IModule.onUninstall.selector + ) revert InvalidFallbackHandler(functionSig); + if (_isFallbackHandlerInstalled(functionSig)) revert FallbackInstalled(functionSig); + + FallbackHandler storage $fallbacks = $fallbackStorage[msg.sender][functionSig]; + $fallbacks.calltype = calltype; + $fallbacks.handler = module; + } else if (_type == MODULE_TYPE_HOOK) { + (HookType hookType, bytes4 selector) = abi.decode(contexts[i], (HookType, bytes4)); + address currentHook; + + // handle global hooks + if (hookType == HookType.GLOBAL && selector == 0x0) { + currentHook = $globalHook[msg.sender]; + // Dont allow hooks to be overwritten. If a hook is currently installed, it must + // be uninstalled first + if (currentHook != address(0)) { + revert HookAlreadyInstalled(currentHook); + } + $globalHook[msg.sender] = module; + } else if (hookType == HookType.SIG) { + // Dont allow hooks to be overwritten. If a hook is currently installed, it must + // be uninstalled first + if (currentHook != address(0)) { + revert HookAlreadyInstalled(currentHook); + } + currentHook = $hookManager[msg.sender][selector]; + $hookManager[msg.sender][selector] = module; + } else { + revert InvalidHookType(); + } + } + } + + // delegatecall neccessary, since event for installModule has to be emitted by SafeProxy + _delegatecall({ + safe: ISafe(msg.sender), + target: UTIL, + callData: abi.encodeCall( + ModuleInstallUtil.installModule, (MODULE_TYPE_HOOK, module, onInstallData) + ) + }); + } } diff --git a/accounts/safe7579/test/ERC7579Compliance/Hooks.t.sol b/accounts/safe7579/test/ERC7579Compliance/Hooks.t.sol index 6249ee81..8c7da34b 100644 --- a/accounts/safe7579/test/ERC7579Compliance/Hooks.t.sol +++ b/accounts/safe7579/test/ERC7579Compliance/Hooks.t.sol @@ -10,6 +10,17 @@ interface MockFn { } contract HookTest is ModuleManagementTest, MockFn { + uint256 preCheckCalled; + uint256 postCheckCalled; + + modifier requireHookCalled(uint256 expected) { + preCheckCalled = 0; + postCheckCalled = 0; + _; + assertEq(preCheckCalled, expected); + assertEq(postCheckCalled, expected); + } + function fallbackFn(bytes32 value) external returns (bytes32) { return value; } @@ -25,7 +36,16 @@ contract HookTest is ModuleManagementTest, MockFn { override returns (bytes memory hookData) { + preCheckCalled++; + assertEq(msgSender, address(this)); console2.log("preCheck"); + + return hex"beef"; + } + + function postCheck(bytes calldata hookData) external virtual override { + postCheckCalled++; + assertEq(hookData, hex"beef"); } function setUp() public virtual override { @@ -40,11 +60,14 @@ contract HookTest is ModuleManagementTest, MockFn { // It should execute hook } - function test_WhenUsingFallbacks() external asEntryPoint { + function test_WhenUsingFallbacks() external requireHookCalled(2) { // It should execute hook _data = hex"4141414141414141"; + vm.startPrank(address(entrypoint)); account.installModule(3, SELF, abi.encode(this.fallbackFn.selector, CALLTYPE_SINGLE, _data)); _installHook(ModuleManager.HookType.SIG, this.fallbackFn.selector, ""); + _installHook(ModuleManager.HookType.GLOBAL, 0, ""); + vm.stopPrank(); bytes32 val = bytes32(bytes(hex"414141414141")); bytes32 ret = MockFn(address(account)).fallbackFn(val); From 1563fd45a9ffc06f6e7b37dc92ab4ec651100818 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Fri, 19 Apr 2024 13:50:16 +0700 Subject: [PATCH 53/64] adding docs ocs fix fix asdf WIP foo ref wip --- accounts/safe7579/README.md | 98 +++++++++++++++---- accounts/safe7579/src/SafeERC7579.sol | 11 +-- accounts/safe7579/src/core/AccessControl.sol | 9 +- .../safe7579/src/core/ExecutionHelper.sol | 15 +++ accounts/safe7579/src/core/ModuleManager.sol | 30 +++++- accounts/safe7579/src/utils/Launchpad.sol | 5 +- 6 files changed, 134 insertions(+), 34 deletions(-) diff --git a/accounts/safe7579/README.md b/accounts/safe7579/README.md index 240934cc..d790366d 100644 --- a/accounts/safe7579/README.md +++ b/accounts/safe7579/README.md @@ -1,34 +1,34 @@ ## How Safe7579 works -Safe7579 provides full ERC4337 and ERC7579 compliance to Safe accounts by serving as the Safe's FallbackHandler and an enabled module. This setup allows Safe accounts to utilize all ERC7579 modules. A launchpad is developed to facilitate the setup of new safes with Safe7579 using the EntryPoint factory. +Safe7579 provides full `ERC4337` and `ERC7579` compliance to Safe accounts by serving as the Safe's `FallbackHandler` and an enabled module. This setup allows Safe accounts to utilize all `ERC7579` modules. A launchpad is developed to facilitate the setup of new safes with Safe7579 using the EntryPoint factory. ## How does the Launchpad work 1. **Creation by Factory:** - - Bundler informs Entrypoint to handleUserOps. - - Entrypoint calls SenderCreator to call SafeProxyFactory - - SenderCreator requests SafeProxy creation from SafeProxyFactory using createProxyWithNonce. - - SafeProxyFactory creates a new SafeProxy using create2. - - SafeProxy is created with a singleton address set to Launchpad (!) - - InitHash is stored in the SafeProxy storage + - Bundler informs `Entrypoint` to handleUserOps. + - Entrypoint calls `SenderCreator` to call `SafeProxyFactory` + - `SenderCreator` requests safeProxy creation from `SafeProxyFactory` using createProxyWithNonce. + - `SafeProxyFactory` creates a new `SafeProxy` using `create2`. + - `SafeProxy` is created with a singleton address set to `Launchpad` (!) + - `InitHash` is stored in the `SafeProxy` storage 2. **Validation Phase:** - - Entrypoint validates user operations in SafeProxy via validateUserOp. - - SafeProxy delegates validation to Launchpad. - - Launchpad ensures the presence of initHash from phase 1 and calls Safe7579.launchpadValidators. - - ValidatorModule gets installed by Launchpad - - ValidatorModule validates user operations and returns packedValidationData. - - Launchpad returns packedValidationData to SafeProxy, SafeProxy returns to Entrypoint. + - `Entrypoint` validates user operations in `SafeProxy` via `validateUserOp`. + - `SafeProxy` delegates validation to `Launchpad`. + - `Launchpad` ensures the presence of initHash from phase 1 and calls `Safe7579.launchpadValidators` + - `ValidatorModule` gets installed by `Launchpad` + - `ValidatorModule` validates user operations and returns `packedValidationData` + - `Launchpad` returns packedValidationData to `SafeProxy`, `SafeProxy` returns to `Entrypoint` 3. **Execution Phase:** - - Entrypoint triggers launchpad.setupSafe in SafeProxy. - - SafeProxy delegates the setup to Launchpad - - LaunchPad upgradres SafeStorage.singleton to SafeSingleton - - LaunchPad calls SafeProxy.setup() to initialize SafeSingleton - - Setup function in SafeProxy.setup() delegatecalls to lauchpad.initSafe7579 - - initSafe7579() initilazies Safe7579 with executors, fallbacks, hooks, IERC7484 registry + - `Entrypoint` triggers `launchpad.setupSafe()` in `SafeProxy` + - `SafeProxy` delegates the setup to `Launchpad` + - `LaunchPad` upgradres `SafeStorage.singleton` to `SafeSingleton` + - `LaunchPad` calls `SafeProxy.setup()` to initialize `SafeSingleton` + - Setup function in `SafeProxy.setup()` delegatecalls to `lauchpad.initSafe7579` + - `initSafe7579()` initilazies `Safe7579` with executors, fallbacks, hooks, `IERC7484` registry This detailed sequence outlines the creation, validation, and execution phases in the system's operation. @@ -112,6 +112,64 @@ SafeProxy->-Entrypoint: exec done end ``` +Special thanks to [@nlordell (Safe)](https://github.com/nlordell), who came up with [this technique](https://github.com/safe-global/safe-modules/pull/184) + +## How do validations and executions work + +In order to call module logic or interact with external contracts, all calls have to be routed over the SafeProxy. +The Safe7579 adapter is an enabled Safe module on the Safe Account, and makes use for `execTransactionFromModule`, to call into external contracts as the Safe Account. + +In order to select validator modules, the address of the validator module can be encoded in the userOp.nonce key. If an validator module that was not previously installed, or validator module with address(0) be selected, the Safe's `checkSignature` is used as a fallback. + +```mermaid + +sequenceDiagram +participant Bundler +participant Entrypoint +participant SafeProxy +participant SafeSingleton +participant Safe7579 +participant ValidatorModule +participant ERC20 + +alt validation with Validator Module +Bundler->>Entrypoint: handleUserOps +Entrypoint->>SafeProxy: validateUserOp() +SafeProxy-->>SafeSingleton: validateUserOp [delegatecall] +Note over SafeSingleton: select Safe7579 as fallback handler +SafeSingleton->>Safe7579: validateUserOp +Note over Safe7579: validator module selection +alt Use Validator Module +Safe7579->>SafeProxy: execTransactionFromModule: call validation module +SafeProxy-->>SafeSingleton: execTransactionFromModule: call validation module [delegatecall] +SafeSingleton->>ValidatorModule: validateUserOp +end +alt Use Safe signatures +Safe7579->>SafeProxy: checkSignatures +SafeProxy-->>SafeSingleton: checkSignatures [delegatecall] +end +end + +alt Execution +Bundler->>Entrypoint: handleUserOps +Entrypoint->>SafeProxy: execute() +SafeProxy-->>SafeSingleton: execute [delegatecall] +Note over SafeSingleton: select Safe7579 as fallback handler +SafeSingleton->>Safe7579: execute() +Safe7579->>SafeProxy: execTransactionFromModule: call ERC20.transfer [delegatecall] +SafeProxy-->>SafeSingleton: call ERC20.transfer +SafeSingleton->>ERC20: transfer() +end +``` + +## Batched Executions + +Safe Account's `execTransactionFromModule` do not natively offer the ability to batch multiple calls into a single transaction. Yet one of the core feature of ERC7579 is the ability to validate and make batched executions. +To save Gas, instead of calling `execTransactionFromModule` n times, we are making use of a special multicall contract, that will be delegatecalled by the Safe account. +The same contract is also used, to emit events for onInstall / onUninstall of modules. + +## Installation of Modules + ## Authors / Credits✨ Thanks to the following people who have contributed to this project: @@ -125,7 +183,7 @@ Thanks to the following people who have contributed to this project:
Konrad (rhinestone)

📝 -
Nicholas Rodrigues Lordello +

Nicholas Rodrigues Lordello (Safe)

📝 diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index 9dfbb1fd..4ce85f8b 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -47,7 +47,7 @@ import { IERC1271 } from "./interfaces/IERC1271.sol"; * event emissions to be done via the SafeProxy as msg.sender using Safe's * "executeTransactionFromModule" features. */ -contract SafeERC7579 is ISafeOp, IERC7579Account, ISafe7579Init, AccessControl, Initializer { +contract SafeERC7579 is ISafeOp, ISafe7579Init, AccessControl, Initializer, IERC7579Account { using UserOperationLib for PackedUserOperation; using ModeLib for ModeCode; using ExecutionLib for bytes; @@ -159,11 +159,7 @@ contract SafeERC7579 is ISafeOp, IERC7579Account, ISafe7579Init, AccessControl, onlyExecutorModule withHook(IERC7579Account.executeFromExecutor.selector) withRegistry(msg.sender, MODULE_TYPE_EXECUTOR) - returns ( - // withGlobalHook - // withSelectorHook(IERC7579Account.execute.selector) - bytes[] memory returnDatas - ) + returns (bytes[] memory returnDatas) { CallType callType; ExecType execType; @@ -268,7 +264,7 @@ contract SafeERC7579 is ISafeOp, IERC7579Account, ISafe7579Init, AccessControl, ) external payable - onlyEntryPointOrSelf + onlyEntryPoint returns (uint256 validSignature) { address validator; @@ -369,6 +365,7 @@ contract SafeERC7579 is ISafeOp, IERC7579Account, ISafe7579Init, AccessControl, } // if a installed validator module was selected, use 7579 validation module + // TODO: this is borked bytes memory ret = _staticcallReturn({ safe: ISafe(msg.sender), target: validationModule, diff --git a/accounts/safe7579/src/core/AccessControl.sol b/accounts/safe7579/src/core/AccessControl.sol index 2f264117..0ef89c66 100644 --- a/accounts/safe7579/src/core/AccessControl.sol +++ b/accounts/safe7579/src/core/AccessControl.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity >=0.8.0 <0.9.0; +pragma solidity ^0.8.23; import { HandlerContext } from "@safe-global/safe-contracts/contracts/handler/HandlerContext.sol"; import { AccountBase } from "erc7579/core/AccountBase.sol"; @@ -17,6 +17,13 @@ contract AccessControl is HandlerContext, AccountBase { _; } + modifier onlyEntryPoint() virtual override { + if (_msgSender() != entryPoint()) { + revert AccountAccessUnauthorized(); + } + _; + } + function entryPoint() public view virtual override returns (address) { return 0x0000000071727De22E5E9d8BAf0edAc6f37da032; } diff --git a/accounts/safe7579/src/core/ExecutionHelper.sol b/accounts/safe7579/src/core/ExecutionHelper.sol index a51d5d4f..caba7320 100644 --- a/accounts/safe7579/src/core/ExecutionHelper.sol +++ b/accounts/safe7579/src/core/ExecutionHelper.sol @@ -48,6 +48,11 @@ abstract contract ExecutionHelper is Safe7579DCUtilSetup { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EXEC - REVERT ON FAIL & Return Values */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + /** + * Helper function to facilitate batched executions. Since Safe accounts do not support batched + * executions natively, we nudge the safe to delegatecall to ./utils/DCUTIL.sol, which then + * makes a multicall. This is to save on gas + */ function _execReturn( ISafe safe, Execution[] calldata executions @@ -93,6 +98,11 @@ abstract contract ExecutionHelper is Safe7579DCUtilSetup { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EXEC - TRY */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + /** + * Helper function to facilitate batched executions. Since Safe accounts do not support batched + * executions natively, we nudge the safe to delegatecall to ./utils/DCUTIL.sol, which then + * makes a multicall. This is to save on gas + */ function _tryExec(ISafe safe, Execution[] calldata executions) internal { _tryDelegatecall({ safe: safe, @@ -115,6 +125,11 @@ abstract contract ExecutionHelper is Safe7579DCUtilSetup { /* EXEC - TRY & Return Values */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + /** + * Helper function to facilitate batched executions. Since Safe accounts do not support batched + * executions natively, we nudge the safe to delegatecall to ./utils/DCUTIL.sol, which then + * makes a multicall. This is to save on gas + */ function _tryExecReturn( ISafe safe, Execution[] calldata executions diff --git a/accounts/safe7579/src/core/ModuleManager.sol b/accounts/safe7579/src/core/ModuleManager.sol index 12bebfc3..67e3148a 100644 --- a/accounts/safe7579/src/core/ModuleManager.sol +++ b/accounts/safe7579/src/core/ModuleManager.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.23; import { SentinelListLib } from "sentinellist/SentinelList.sol"; import { SentinelList4337Lib } from "sentinellist/SentinelList4337.sol"; import { IModule, IHook } from "../interfaces/IERC7579Module.sol"; +import { IERC7579Account } from "../interfaces/IERC7579Account.sol"; import { ISafe } from "../interfaces/ISafe.sol"; import { Safe7579DCUtil, ModuleInstallUtil } from "../utils/DCUtil.sol"; @@ -73,6 +74,10 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { /** * Uninstall and de-initialize validator module + * @dev This function does not prevent the user from uninstalling all validator modules. + * Since the Safe7579 signature validation can fallback to Safe's checkSignature() + * function, it is okay, if all validator modules are removed. + * This does not brick the account */ function _uninstallValidator(address validator, bytes calldata data) internal { (address prev, bytes memory disableModuleData) = abi.decode(data, (address, bytes)); @@ -508,11 +513,22 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { for (uint256 i; i < length; i++) { uint256 _type = types[i]; + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* INSTALL VALIDATORS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ if (_type == MODULE_TYPE_VALIDATOR) { $validators.push({ account: msg.sender, newEntry: module }); - } else if (_type == MODULE_TYPE_EXECUTOR) { + } + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* INSTALL EXECUTORS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + else if (_type == MODULE_TYPE_EXECUTOR) { $executorStorage[msg.sender].push(module); - } else if (_type == MODULE_TYPE_FALLBACK) { + } + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* INSTALL FALLBACK */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + else if (_type == MODULE_TYPE_FALLBACK) { // do nothing (bytes4 functionSig, CallType calltype) = @@ -529,7 +545,11 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { FallbackHandler storage $fallbacks = $fallbackStorage[msg.sender][functionSig]; $fallbacks.calltype = calltype; $fallbacks.handler = module; - } else if (_type == MODULE_TYPE_HOOK) { + } + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* INSTALL HOOK (global or sig specific) */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + else if (_type == MODULE_TYPE_HOOK) { (HookType hookType, bytes4 selector) = abi.decode(contexts[i], (HookType, bytes4)); address currentHook; @@ -554,6 +574,10 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { revert InvalidHookType(); } } + // handle unsupported moduletype + else { + revert InvalidModule(module); + } } // delegatecall neccessary, since event for installModule has to be emitted by SafeProxy diff --git a/accounts/safe7579/src/utils/Launchpad.sol b/accounts/safe7579/src/utils/Launchpad.sol index 5c0652f9..7290f1a5 100644 --- a/accounts/safe7579/src/utils/Launchpad.sol +++ b/accounts/safe7579/src/utils/Launchpad.sol @@ -13,9 +13,8 @@ import { SafeStorage } from "@safe-global/safe-contracts/contracts/libraries/Saf /** * Launchpad to deploy a Safe account and connect the Safe7579 adapter. - * credits for the idea: nlordell (Safe) - * this launchpad is based on Safe 4337 Signer Launchpad: - * https://github.com/safe-global/safe-modules/pull/184/files + * Special thanks to [nlordell (Safe)](https://github.com/nlordell), who came up with [this + * technique](https://github.com/safe-global/safe-modules/pull/184) * @author rhinestone | zeroknots.eth */ contract Safe7579Launchpad is IAccount, SafeStorage { From ceba7b811e9775ef8d4b2b661d1b98448da672cf Mon Sep 17 00:00:00 2001 From: zeroknots Date: Mon, 22 Apr 2024 10:55:41 +0700 Subject: [PATCH 54/64] feat: wrote comprehensive hook tests --- .../safe7579/src/core/ExecutionHelper.sol | 44 ++++++---- accounts/safe7579/src/interfaces/ISafe.sol | 2 + accounts/safe7579/src/utils/DCUtil.sol | 12 ++- .../test/ERC7579Compliance/Hooks.t.sol | 81 ++++++++++++++++--- .../ERC7579Compliance/ModuleManagement.t.sol | 6 +- 5 files changed, 113 insertions(+), 32 deletions(-) diff --git a/accounts/safe7579/src/core/ExecutionHelper.sol b/accounts/safe7579/src/core/ExecutionHelper.sol index caba7320..7d585af8 100644 --- a/accounts/safe7579/src/core/ExecutionHelper.sol +++ b/accounts/safe7579/src/core/ExecutionHelper.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.23; -import { Safe7579DCUtilSetup } from "./SetupDCUtil.sol"; +import { Safe7579DCUtil, Safe7579DCUtilSetup } from "./SetupDCUtil.sol"; import { SimulateTxAccessor } from "../utils/DCUtil.sol"; import { Enum } from "@safe-global/safe-contracts/contracts/common/Enum.sol"; import { BatchedExecUtil } from "../utils/DCUtil.sol"; @@ -178,11 +178,7 @@ abstract contract ExecutionHelper is Safe7579DCUtilSetup { /** * Safe account does not natively implement Enum.Operation.StaticCall, - * to still receive some guarantees, that the target contract of calls, can not do state - * changes, we are making use of Safe's SimulateTxAccessor. - * @dev This function will nudge the Safe account to make a delegatecall to the DCUTIL contract, - * which inherits SimulateTxAccessor and call the simulate() function there. - * This ensures, that the target contract can not do state changes + * using a trick with simulateAndRevert to execute a staticcall. * @param safe Safe account to execute the staticcall * @param target Target contract to staticcall * @param callData Data to be passed to the target contract @@ -193,18 +189,32 @@ abstract contract ExecutionHelper is Safe7579DCUtilSetup { bytes memory callData ) internal - returns (bytes memory retData) + view + returns (bytes memory result) { - bytes memory ret = _delegatecallReturn({ - safe: safe, - target: UTIL, // immutable address for DCUTIL (./utils/DCUTIL.sol) - callData: abi.encodeCall( - SimulateTxAccessor.simulate, (target, 0, callData, Enum.Operation.Call) + bytes memory staticCallData = abi.encodeCall(Safe7579DCUtil.staticCall, (target, callData)); + bytes memory simulationCallData = + abi.encodeCall(ISafe.simulateAndRevert, (address(UTIL), staticCallData)); + + // solhint-disable-next-line no-inline-assembly + assembly ("memory-safe") { + pop( + staticcall( + gas(), + safe, + add(simulationCallData, 0x20), + mload(simulationCallData), + 0x00, + 0x20 + ) ) - }); - bool success; - (, success, retData) = abi.decode(ret, (uint256, bool, bytes)); - if (!success) revert ExecutionFailed(); - return retData; + + let responseSize := sub(returndatasize(), 0x20) + result := mload(0x40) + mstore(0x40, add(result, responseSize)) + returndatacopy(result, 0x20, responseSize) + + if iszero(mload(0x00)) { revert(add(result, 0x20), mload(result)) } + } } } diff --git a/accounts/safe7579/src/interfaces/ISafe.sol b/accounts/safe7579/src/interfaces/ISafe.sol index 9d770160..f6bb11be 100644 --- a/accounts/safe7579/src/interfaces/ISafe.sol +++ b/accounts/safe7579/src/interfaces/ISafe.sol @@ -98,4 +98,6 @@ interface ISafe { function enableModule(address module) external; function VERSION() external view returns (string memory); + + function simulateAndRevert(address targetContract, bytes memory calldataPayload) external; } diff --git a/accounts/safe7579/src/utils/DCUtil.sol b/accounts/safe7579/src/utils/DCUtil.sol index d3f714c4..a5d4382f 100644 --- a/accounts/safe7579/src/utils/DCUtil.sol +++ b/accounts/safe7579/src/utils/DCUtil.sol @@ -126,4 +126,14 @@ contract BatchedExecUtil { } } -contract Safe7579DCUtil is ModuleInstallUtil, BatchedExecUtil, SimulateTxAccessor { } +contract Safe7579DCUtil is ModuleInstallUtil, BatchedExecUtil, SimulateTxAccessor { + function staticCall(address target, bytes memory data) external view { + assembly ("memory-safe") { + let ptr := mload(0x40) + let success := staticcall(gas(), target, add(data, 0x20), mload(data), 0x00, 0x00) + returndatacopy(ptr, 0x00, returndatasize()) + if success { return(ptr, returndatasize()) } + revert(ptr, returndatasize()) + } + } +} diff --git a/accounts/safe7579/test/ERC7579Compliance/Hooks.t.sol b/accounts/safe7579/test/ERC7579Compliance/Hooks.t.sol index 8c7da34b..59b4432d 100644 --- a/accounts/safe7579/test/ERC7579Compliance/Hooks.t.sol +++ b/accounts/safe7579/test/ERC7579Compliance/Hooks.t.sol @@ -9,23 +9,33 @@ interface MockFn { function fallbackFn(bytes32 value) external returns (bytes32); } -contract HookTest is ModuleManagementTest, MockFn { +contract HookTest is BaseTest, MockFn { uint256 preCheckCalled; uint256 postCheckCalled; + bytes _data; + address _caller; modifier requireHookCalled(uint256 expected) { preCheckCalled = 0; postCheckCalled = 0; _; - assertEq(preCheckCalled, expected); - assertEq(postCheckCalled, expected); + assertEq(preCheckCalled, expected, "preCheckCalled"); + assertEq(postCheckCalled, expected, "postCheckCalled"); } function fallbackFn(bytes32 value) external returns (bytes32) { return value; } - function onInstall(bytes calldata data) public virtual override { } + function onInstall(bytes calldata data) public virtual override { + assertEq(_data, data); + assertEq(msg.sender, address(account)); + } + + function onUninstall(bytes calldata data) public override { + assertEq(_data, data); + assertEq(msg.sender, address(account)); + } function preCheck( address msgSender, @@ -37,7 +47,7 @@ contract HookTest is ModuleManagementTest, MockFn { returns (bytes memory hookData) { preCheckCalled++; - assertEq(msgSender, address(this)); + assertEq(msgSender, address(_caller)); console2.log("preCheck"); return hex"beef"; @@ -52,30 +62,77 @@ contract HookTest is ModuleManagementTest, MockFn { super.setUp(); } - function test_WhenExecutingVia4337() external { - // It should execute hook + function test_WhenExecutingVia4337() external requireHookCalled(1){ + _data = hex"4141414141414141"; + _caller = address(entrypoint); + vm.startPrank(address(entrypoint)); + + bytes memory data = abi.encode(ModuleManager.HookType.GLOBAL, 0x0, _data); + account.installModule(4, SELF, data); + + + bytes memory setValueOnTarget = abi.encodeCall(MockTarget.set, 1337); + account.execute( + ModeLib.encodeSimpleSingle(), + ExecutionLib.encodeSingle(address(target), uint256(0), setValueOnTarget) + ); + vm.stopPrank(); } - function test_WhenExecutingViaModule() external { - // It should execute hook + function test_WhenExecutingViaModule() external requireHookCalled(1) { + _data = hex"4141414141414141"; + _caller = address(this); + vm.startPrank(address(entrypoint)); + // installing this test as an executor + account.installModule(2, SELF, _data); + + bytes memory data = abi.encode(ModuleManager.HookType.GLOBAL, 0x0, _data); + account.installModule(4, SELF, data); + + vm.stopPrank(); + + bytes memory setValueOnTarget = abi.encodeCall(MockTarget.set, 1337); + account.executeFromExecutor( + ModeLib.encodeSimpleSingle(), + ExecutionLib.encodeSingle(address(target), uint256(0), setValueOnTarget) + ); } function test_WhenUsingFallbacks() external requireHookCalled(2) { // It should execute hook _data = hex"4141414141414141"; + _caller = address(this); vm.startPrank(address(entrypoint)); + // installing fallback account.installModule(3, SELF, abi.encode(this.fallbackFn.selector, CALLTYPE_SINGLE, _data)); - _installHook(ModuleManager.HookType.SIG, this.fallbackFn.selector, ""); - _installHook(ModuleManager.HookType.GLOBAL, 0, ""); + + bytes memory data = abi.encode(ModuleManager.HookType.SIG, this.fallbackFn.selector, _data); + account.installModule(4, SELF, data); + data = abi.encode(ModuleManager.HookType.GLOBAL, 0x0, _data); + account.installModule(4, SELF, data); vm.stopPrank(); bytes32 val = bytes32(bytes(hex"414141414141")); + // calling fallback bytes32 ret = MockFn(address(account)).fallbackFn(val); assertEq(ret, val); } - function test_WhenInstallingModule() external { + function test_WhenInstallingModule() external requireHookCalled(3) { // It should execute hook + _data = hex"4141414141414141"; + _caller = address(entrypoint); + vm.startPrank(address(entrypoint)); + + bytes memory data = + abi.encode(ModuleManager.HookType.SIG, IERC7579Account.installModule.selector, _data); + account.installModule(4, SELF, data); + data = abi.encode(ModuleManager.HookType.GLOBAL, 0x0, _data); + account.installModule(4, SELF, data); + + // installing fallback + account.installModule(2, SELF, _data); + vm.stopPrank(); } function test_WhenHookReverts() external { diff --git a/accounts/safe7579/test/ERC7579Compliance/ModuleManagement.t.sol b/accounts/safe7579/test/ERC7579Compliance/ModuleManagement.t.sol index 0544a344..42fc4bc3 100644 --- a/accounts/safe7579/test/ERC7579Compliance/ModuleManagement.t.sol +++ b/accounts/safe7579/test/ERC7579Compliance/ModuleManagement.t.sol @@ -90,7 +90,9 @@ contract ModuleManagementTest is BaseTest { bytes4 selector = 0x00000000; _data = hex"4141414141414141"; - _installHook(hookType, selector, _data); - _uninstallHook(hookType, selector, _data); + bytes memory data = abi.encode(hookType, selector, _data); + account.installModule(4, SELF, data); + + account.uninstallModule(4, SELF, data); } } From 7d33ac856a1c606c55bac4c100fbc85408e69a4f Mon Sep 17 00:00:00 2001 From: zeroknots Date: Mon, 22 Apr 2024 11:02:42 +0700 Subject: [PATCH 55/64] chore: linting --- accounts/safe7579/src/core/ExecutionHelper.sol | 2 -- accounts/safe7579/src/core/ModuleManager.sol | 4 ++-- accounts/safe7579/src/utils/DCUtil.sol | 5 ++--- accounts/safe7579/test/ERC7579Compliance/Hooks.t.sol | 3 +-- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/accounts/safe7579/src/core/ExecutionHelper.sol b/accounts/safe7579/src/core/ExecutionHelper.sol index 7d585af8..7dc60b7d 100644 --- a/accounts/safe7579/src/core/ExecutionHelper.sol +++ b/accounts/safe7579/src/core/ExecutionHelper.sol @@ -2,8 +2,6 @@ pragma solidity ^0.8.23; import { Safe7579DCUtil, Safe7579DCUtilSetup } from "./SetupDCUtil.sol"; -import { SimulateTxAccessor } from "../utils/DCUtil.sol"; -import { Enum } from "@safe-global/safe-contracts/contracts/common/Enum.sol"; import { BatchedExecUtil } from "../utils/DCUtil.sol"; import { Execution } from "../interfaces/IERC7579Account.sol"; import { ISafe } from "../interfaces/ISafe.sol"; diff --git a/accounts/safe7579/src/core/ModuleManager.sol b/accounts/safe7579/src/core/ModuleManager.sol index 67e3148a..41fa8cd7 100644 --- a/accounts/safe7579/src/core/ModuleManager.sol +++ b/accounts/safe7579/src/core/ModuleManager.sol @@ -4,10 +4,9 @@ pragma solidity ^0.8.23; import { SentinelListLib } from "sentinellist/SentinelList.sol"; import { SentinelList4337Lib } from "sentinellist/SentinelList4337.sol"; import { IModule, IHook } from "../interfaces/IERC7579Module.sol"; -import { IERC7579Account } from "../interfaces/IERC7579Account.sol"; import { ISafe } from "../interfaces/ISafe.sol"; -import { Safe7579DCUtil, ModuleInstallUtil } from "../utils/DCUtil.sol"; +import { ModuleInstallUtil } from "../utils/DCUtil.sol"; import { RegistryAdapter } from "./RegistryAdapter.sol"; import { Receiver } from "erc7579/core/Receiver.sol"; import { AccessControl } from "./AccessControl.sol"; @@ -499,6 +498,7 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { return $globalHook[msg.sender]; } + // solhint-disable-next-line code-complexity function _multiTypeInstall( address module, uint256[] calldata types, diff --git a/accounts/safe7579/src/utils/DCUtil.sol b/accounts/safe7579/src/utils/DCUtil.sol index a5d4382f..6f5ee8cc 100644 --- a/accounts/safe7579/src/utils/DCUtil.sol +++ b/accounts/safe7579/src/utils/DCUtil.sol @@ -3,8 +3,6 @@ pragma solidity ^0.8.22; import { Execution } from "../interfaces/IERC7579Account.sol"; import { IModule as IERC7579Module } from "erc7579/interfaces/IERC7579Module.sol"; -import { SimulateTxAccessor } from - "@safe-global/safe-contracts/contracts/accessors/SimulateTxAccessor.sol"; contract ModuleInstallUtil { event ModuleInstalled(uint256 moduleTypeId, address module); @@ -126,8 +124,9 @@ contract BatchedExecUtil { } } -contract Safe7579DCUtil is ModuleInstallUtil, BatchedExecUtil, SimulateTxAccessor { +contract Safe7579DCUtil is ModuleInstallUtil, BatchedExecUtil { function staticCall(address target, bytes memory data) external view { + // solhint-disable-next-line no-inline-assembly assembly ("memory-safe") { let ptr := mload(0x40) let success := staticcall(gas(), target, add(data, 0x20), mload(data), 0x00, 0x00) diff --git a/accounts/safe7579/test/ERC7579Compliance/Hooks.t.sol b/accounts/safe7579/test/ERC7579Compliance/Hooks.t.sol index 59b4432d..f3e842b4 100644 --- a/accounts/safe7579/test/ERC7579Compliance/Hooks.t.sol +++ b/accounts/safe7579/test/ERC7579Compliance/Hooks.t.sol @@ -62,7 +62,7 @@ contract HookTest is BaseTest, MockFn { super.setUp(); } - function test_WhenExecutingVia4337() external requireHookCalled(1){ + function test_WhenExecutingVia4337() external requireHookCalled(1) { _data = hex"4141414141414141"; _caller = address(entrypoint); vm.startPrank(address(entrypoint)); @@ -70,7 +70,6 @@ contract HookTest is BaseTest, MockFn { bytes memory data = abi.encode(ModuleManager.HookType.GLOBAL, 0x0, _data); account.installModule(4, SELF, data); - bytes memory setValueOnTarget = abi.encodeCall(MockTarget.set, 1337); account.execute( ModeLib.encodeSimpleSingle(), From bc1c2fd6d04e64ec9082b34687ead47ea44ea69b Mon Sep 17 00:00:00 2001 From: zeroknots Date: Mon, 22 Apr 2024 11:50:58 +0700 Subject: [PATCH 56/64] multi install multi module type clean --- accounts/safe7579/src/SafeERC7579.sol | 59 ++++- accounts/safe7579/src/core/ModuleManager.sol | 215 +++++++----------- .../ERC7579Compliance/ModuleManagement.t.sol | 13 ++ 3 files changed, 143 insertions(+), 144 deletions(-) diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index 4ce85f8b..36897e3e 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -21,6 +21,7 @@ import { MODULE_TYPE_EXECUTOR, MODULE_TYPE_FALLBACK } from "erc7579/interfaces/IERC7579Module.sol"; +import { ModuleInstallUtil } from "./utils/DCUtil.sol"; import { AccessControl } from "./core/AccessControl.sol"; import { Initializer } from "./core/Initializer.sol"; import { ISafeOp, SAFE_OP_TYPEHASH } from "./interfaces/ISafeOp.sol"; @@ -34,6 +35,8 @@ import { IEntryPoint } from "@ERC4337/account-abstraction/contracts/interfaces/I import { ISafe7579Init } from "./interfaces/ISafe7579Init.sol"; import { IERC1271 } from "./interfaces/IERC1271.sol"; +uint256 constant MULTITYPE_MODULE = 0; + /** * @title ERC7579 Adapter for Safe accounts. * creates full ERC7579 compliance to Safe accounts @@ -340,6 +343,7 @@ contract SafeERC7579 is ISafeOp, ISafe7579Init, AccessControl, Initializer, IERC bytes calldata data ) external + view returns (bytes4 magicValue) { ISafe safe = ISafe(msg.sender); @@ -365,7 +369,6 @@ contract SafeERC7579 is ISafeOp, ISafe7579Init, AccessControl, Initializer, IERC } // if a installed validator module was selected, use 7579 validation module - // TODO: this is borked bytes memory ret = _staticcallReturn({ safe: ISafe(msg.sender), target: validationModule, @@ -390,11 +393,29 @@ contract SafeERC7579 is ISafeOp, ISafe7579Init, AccessControl, Initializer, IERC withHook(IERC7579Account.installModule.selector) onlyEntryPointOrSelf { - if (moduleType == MODULE_TYPE_VALIDATOR) _installValidator(module, initData); - else if (moduleType == MODULE_TYPE_EXECUTOR) _installExecutor(module, initData); - else if (moduleType == MODULE_TYPE_FALLBACK) _installFallbackHandler(module, initData); - else if (moduleType == MODULE_TYPE_HOOK) _installHook(module, initData); - else revert UnsupportedModuleType(moduleType); + bytes memory moduleInitData; + if (moduleType == MODULE_TYPE_VALIDATOR) { + moduleInitData = _installValidator(module, initData); + } else if (moduleType == MODULE_TYPE_EXECUTOR) { + moduleInitData = _installExecutor(module, initData); + } else if (moduleType == MODULE_TYPE_FALLBACK) { + moduleInitData = _installFallbackHandler(module, initData); + } else if (moduleType == MODULE_TYPE_HOOK) { + moduleInitData = _installHook(module, initData); + } else if (moduleType == MULTITYPE_MODULE) { + moduleInitData = _multiTypeInstall(module, initData); + } else { + revert UnsupportedModuleType(moduleType); + } + + // Initialize Module via Safe + _delegatecall({ + safe: ISafe(msg.sender), + target: UTIL, + callData: abi.encodeCall( + ModuleInstallUtil.installModule, (moduleType, module, moduleInitData) + ) + }); } /** @@ -411,11 +432,27 @@ contract SafeERC7579 is ISafeOp, ISafe7579Init, AccessControl, Initializer, IERC withHook(IERC7579Account.uninstallModule.selector) onlyEntryPointOrSelf { - if (moduleType == MODULE_TYPE_VALIDATOR) _uninstallValidator(module, deInitData); - else if (moduleType == MODULE_TYPE_EXECUTOR) _uninstallExecutor(module, deInitData); - else if (moduleType == MODULE_TYPE_FALLBACK) _uninstallFallbackHandler(module, deInitData); - else if (moduleType == MODULE_TYPE_HOOK) _uninstallHook(module, deInitData); - else revert UnsupportedModuleType(moduleType); + bytes memory moduleDeInitData; + if (moduleType == MODULE_TYPE_VALIDATOR) { + moduleDeInitData = _uninstallValidator(module, deInitData); + } else if (moduleType == MODULE_TYPE_EXECUTOR) { + moduleDeInitData = _uninstallExecutor(module, deInitData); + } else if (moduleType == MODULE_TYPE_FALLBACK) { + moduleDeInitData = _uninstallFallbackHandler(module, deInitData); + } else if (moduleType == MODULE_TYPE_HOOK) { + moduleDeInitData = _uninstallHook(module, deInitData); + } else { + revert UnsupportedModuleType(moduleType); + } + + // Deinitialize Module via Safe + _delegatecall({ + safe: ISafe(msg.sender), + target: UTIL, + callData: abi.encodeCall( + ModuleInstallUtil.unInstallModule, (moduleType, module, moduleDeInitData) + ) + }); } /** diff --git a/accounts/safe7579/src/core/ModuleManager.sol b/accounts/safe7579/src/core/ModuleManager.sol index 41fa8cd7..8356ef59 100644 --- a/accounts/safe7579/src/core/ModuleManager.sol +++ b/accounts/safe7579/src/core/ModuleManager.sol @@ -18,6 +18,7 @@ import { MODULE_TYPE_HOOK } from "erc7579/interfaces/IERC7579Module.sol"; +import "forge-std/console2.sol"; /** * @title ModuleManager * Contract that implements ERC7579 Module compatibility for Safe accounts @@ -32,6 +33,7 @@ import { * respective section * */ + abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { using SentinelListLib for SentinelListLib.SentinelList; using SentinelList4337Lib for SentinelList4337Lib.SentinelList; @@ -58,17 +60,10 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { ) internal withRegistry(validator, MODULE_TYPE_VALIDATOR) + returns (bytes memory moduleInitData) { $validators.push({ account: msg.sender, newEntry: validator }); - - // Initialize Validator Module via Safe - _delegatecall({ - safe: ISafe(msg.sender), - target: UTIL, - callData: abi.encodeCall( - ModuleInstallUtil.installModule, (MODULE_TYPE_VALIDATOR, validator, data) - ) - }); + return data; } /** @@ -78,18 +73,16 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { * function, it is okay, if all validator modules are removed. * This does not brick the account */ - function _uninstallValidator(address validator, bytes calldata data) internal { - (address prev, bytes memory disableModuleData) = abi.decode(data, (address, bytes)); + function _uninstallValidator( + address validator, + bytes calldata data + ) + internal + returns (bytes memory moduleInitData) + { + address prev; + (prev, moduleInitData) = abi.decode(data, (address, bytes)); $validators.pop({ account: msg.sender, prevEntry: prev, popEntry: validator }); - - // De-Initialize Validator Module via Safe - _delegatecall({ - safe: ISafe(msg.sender), - target: UTIL, - callData: abi.encodeCall( - ModuleInstallUtil.unInstallModule, (MODULE_TYPE_VALIDATOR, validator, disableModuleData) - ) - }); } /** @@ -142,32 +135,25 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { ) internal withRegistry(executor, MODULE_TYPE_EXECUTOR) + returns (bytes memory moduleInitData) { SentinelListLib.SentinelList storage $executors = $executorStorage[msg.sender]; $executors.push(executor); // Initialize Executor Module via Safe - _delegatecall({ - safe: ISafe(msg.sender), - target: UTIL, - callData: abi.encodeCall( - ModuleInstallUtil.installModule, (MODULE_TYPE_EXECUTOR, executor, data) - ) - }); + return data; } - function _uninstallExecutor(address executor, bytes calldata data) internal { + function _uninstallExecutor( + address executor, + bytes calldata data + ) + internal + returns (bytes memory moduleDeInitData) + { SentinelListLib.SentinelList storage $executors = $executorStorage[msg.sender]; - (address prev, bytes memory disableModuleData) = abi.decode(data, (address, bytes)); + address prev; + (prev, moduleDeInitData) = abi.decode(data, (address, bytes)); $executors.pop(prev, executor); - - // De-Initialize Validator Module via Safe - _delegatecall({ - safe: ISafe(msg.sender), - target: UTIL, - callData: abi.encodeCall( - ModuleInstallUtil.unInstallModule, (MODULE_TYPE_EXECUTOR, executor, disableModuleData) - ) - }); } function _isExecutorInstalled(address executor) internal view virtual returns (bool) { @@ -210,6 +196,7 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { internal virtual withRegistry(handler, MODULE_TYPE_FALLBACK) + returns (bytes memory moduleInitData) { (bytes4 functionSig, CallType calltype, bytes memory initData) = abi.decode(params, (bytes4, CallType, bytes)); @@ -225,13 +212,7 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { $fallbacks.calltype = calltype; $fallbacks.handler = handler; - _delegatecall({ - safe: ISafe(msg.sender), - target: UTIL, - callData: abi.encodeCall( - ModuleInstallUtil.installModule, (MODULE_TYPE_FALLBACK, handler, initData) - ) - }); + return initData; } function _isFallbackHandlerInstalled(bytes4 functionSig) internal view virtual returns (bool) { @@ -239,19 +220,19 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { return $fallbacks.handler != address(0); } - function _uninstallFallbackHandler(address handler, bytes calldata context) internal virtual { - (bytes4 functionSig, bytes memory initData) = abi.decode(context, (bytes4, bytes)); + function _uninstallFallbackHandler( + address handler, + bytes calldata context + ) + internal + virtual + returns (bytes memory moduleDeInitData) + { + bytes4 functionSig; + (functionSig, moduleDeInitData) = abi.decode(context, (bytes4, bytes)); FallbackHandler storage $fallbacks = $fallbackStorage[msg.sender][functionSig]; - $fallbacks.handler = address(0); - // De-Initialize Fallback Module via Safe - _delegatecall({ - safe: ISafe(msg.sender), - target: UTIL, - callData: abi.encodeCall( - ModuleInstallUtil.unInstallModule, (MODULE_TYPE_FALLBACK, handler, initData) - ) - }); + delete $fallbacks.handler; } function _isFallbackHandlerInstalled( @@ -403,6 +384,7 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { internal virtual withRegistry(hook, MODULE_TYPE_HOOK) + returns (bytes memory moduleInitData) { (HookType hookType, bytes4 selector, bytes memory initData) = abi.decode(data, (HookType, bytes4, bytes)); @@ -429,19 +411,20 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { revert InvalidHookType(); } - // delegatecall neccessary, since event for installModule has to be emitted by SafeProxy - _delegatecall({ - safe: ISafe(msg.sender), - target: UTIL, - callData: abi.encodeCall( - ModuleInstallUtil.installModule, (MODULE_TYPE_HOOK, hook, initData) - ) - }); + return initData; } - function _uninstallHook(address hook, bytes calldata data) internal virtual { - (HookType hookType, bytes4 selector, bytes memory initData) = - abi.decode(data, (HookType, bytes4, bytes)); + function _uninstallHook( + address hook, + bytes calldata data + ) + internal + virtual + returns (bytes memory moduleDeInitData) + { + HookType hookType; + bytes4 selector; + (hookType, selector, moduleDeInitData) = abi.decode(data, (HookType, bytes4, bytes)); if (hookType == HookType.GLOBAL && selector == 0x0) { delete $globalHook[msg.sender]; } else if (hookType == HookType.SIG) { @@ -449,15 +432,6 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { } else { revert InvalidHookType(); } - - // delegatecall neccessary, since event for uninstallModule has to be emitted by SafeProxy - _delegatecall({ - safe: ISafe(msg.sender), - target: UTIL, - callData: abi.encodeCall( - ModuleInstallUtil.unInstallModule, (MODULE_TYPE_HOOK, hook, initData) - ) - }); } function _getCurrentHook( @@ -501,12 +475,36 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { // solhint-disable-next-line code-complexity function _multiTypeInstall( address module, - uint256[] calldata types, - bytes[] calldata contexts, - bytes calldata onInstallData + bytes calldata initData ) internal + returns (bytes memory _moduleInitData) { + uint256[] calldata types; + bytes[] calldata contexts; + bytes calldata moduleInitData; + + // equivalent of (types, contexs, moduleInitData) = + // abi.decode(initData,(uint[],bytes[],bytes) + assembly ("memory-safe") { + let offset := initData.offset + let baseOffset := offset + let dataPointer := add(baseOffset, calldataload(offset)) + + types.offset := add(dataPointer, 32) + types.length := calldataload(dataPointer) + offset := add(offset, 32) + + dataPointer := add(baseOffset, calldataload(offset)) + contexts.offset := add(dataPointer, 32) + contexts.length := calldataload(dataPointer) + offset := add(offset, 32) + + dataPointer := add(baseOffset, calldataload(offset)) + moduleInitData.offset := add(dataPointer, 32) + moduleInitData.length := calldataload(dataPointer) + } + uint256 length = types.length; if (contexts.length != length) revert InvalidInput(); @@ -517,76 +515,27 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { /* INSTALL VALIDATORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ if (_type == MODULE_TYPE_VALIDATOR) { - $validators.push({ account: msg.sender, newEntry: module }); + _installValidator(module, contexts[i]); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INSTALL EXECUTORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ else if (_type == MODULE_TYPE_EXECUTOR) { - $executorStorage[msg.sender].push(module); + _installExecutor(module, contexts[i]); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INSTALL FALLBACK */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ else if (_type == MODULE_TYPE_FALLBACK) { - // do nothing - - (bytes4 functionSig, CallType calltype) = - abi.decode(contexts[i], (bytes4, CallType)); - - // disallow calls to onInstall or onUninstall. - // this could create a security issue - if ( - functionSig == IModule.onInstall.selector - || functionSig == IModule.onUninstall.selector - ) revert InvalidFallbackHandler(functionSig); - if (_isFallbackHandlerInstalled(functionSig)) revert FallbackInstalled(functionSig); - - FallbackHandler storage $fallbacks = $fallbackStorage[msg.sender][functionSig]; - $fallbacks.calltype = calltype; - $fallbacks.handler = module; + _installFallbackHandler(module, contexts[i]); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INSTALL HOOK (global or sig specific) */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ else if (_type == MODULE_TYPE_HOOK) { - (HookType hookType, bytes4 selector) = abi.decode(contexts[i], (HookType, bytes4)); - address currentHook; - - // handle global hooks - if (hookType == HookType.GLOBAL && selector == 0x0) { - currentHook = $globalHook[msg.sender]; - // Dont allow hooks to be overwritten. If a hook is currently installed, it must - // be uninstalled first - if (currentHook != address(0)) { - revert HookAlreadyInstalled(currentHook); - } - $globalHook[msg.sender] = module; - } else if (hookType == HookType.SIG) { - // Dont allow hooks to be overwritten. If a hook is currently installed, it must - // be uninstalled first - if (currentHook != address(0)) { - revert HookAlreadyInstalled(currentHook); - } - currentHook = $hookManager[msg.sender][selector]; - $hookManager[msg.sender][selector] = module; - } else { - revert InvalidHookType(); - } - } - // handle unsupported moduletype - else { - revert InvalidModule(module); + _installHook(module, contexts[i]); } } - - // delegatecall neccessary, since event for installModule has to be emitted by SafeProxy - _delegatecall({ - safe: ISafe(msg.sender), - target: UTIL, - callData: abi.encodeCall( - ModuleInstallUtil.installModule, (MODULE_TYPE_HOOK, module, onInstallData) - ) - }); + _moduleInitData = moduleInitData; } } diff --git a/accounts/safe7579/test/ERC7579Compliance/ModuleManagement.t.sol b/accounts/safe7579/test/ERC7579Compliance/ModuleManagement.t.sol index 42fc4bc3..36f3e4f8 100644 --- a/accounts/safe7579/test/ERC7579Compliance/ModuleManagement.t.sol +++ b/accounts/safe7579/test/ERC7579Compliance/ModuleManagement.t.sol @@ -95,4 +95,17 @@ contract ModuleManagementTest is BaseTest { account.uninstallModule(4, SELF, data); } + + function test_multiTypeInstall() public asEntryPoint { + uint256[] memory types = Solarray.uint256s(1, 2); + bytes[] memory contexts = Solarray.bytess(hex"41", hex"41"); + _data = hex"4141414141414141"; + bytes memory moduleInitData = _data; + + bytes memory initData = abi.encode(types, contexts, moduleInitData); + account.installModule(0, SELF, initData); + + assertTrue(account.isModuleInstalled(1, SELF, "")); + assertTrue(account.isModuleInstalled(2, SELF, "")); + } } From 3ede7afcc5033326b4f9c27d2bfe6d69fb7c44d1 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Mon, 22 Apr 2024 12:24:14 +0700 Subject: [PATCH 57/64] docs --- accounts/safe7579/src/SafeERC7579.sol | 122 +++++++++++++++++++++----- accounts/safe7579/src/lib/ModeLib.sol | 2 +- 2 files changed, 103 insertions(+), 21 deletions(-) diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/SafeERC7579.sol index 36897e3e..5e4ac10d 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/SafeERC7579.sol @@ -67,7 +67,21 @@ contract SafeERC7579 is ISafeOp, ISafe7579Init, AccessControl, Initializer, IERC bytes4 private constant SAFE_SIGNATURE_MAGIC_VALUE = 0x5fd7e97d; /** - * @inheritdoc IERC7579Account + * @dev Executes a transaction on behalf of the Safe account. + * This function is intended to be called by ERC-4337 EntryPoint.sol + * @dev If a global hook and/or selector hook is set, it will be called + * @dev AccessControl: only Self of Entrypoint can install modules + * SafeERC7579 supports the following feature set: + * CallTypes: + * - CALLTYPE_SINGLE + * - CALLTYPE_BATCH + * - CALLTYPE_DELEGATECALL + * ExecTypes: + * - EXECTYPE_DEFAULT (revert if not successful) + * - EXECTYPE_TRY + * If a different mode is selected, this function will revert + * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details + * @param executionCalldata The encoded execution call data */ function execute( ModeCode mode, @@ -76,8 +90,6 @@ contract SafeERC7579 is ISafeOp, ISafe7579Init, AccessControl, Initializer, IERC external payable withHook(IERC7579Account.execute.selector) - // withGlobalHook - // withSelectorHook(IERC7579Account.execute.selector) onlyEntryPointOrSelf { CallType callType; @@ -150,7 +162,21 @@ contract SafeERC7579 is ISafeOp, ISafe7579Init, AccessControl, Initializer, IERC } /** - * @inheritdoc IERC7579Account + * @dev Executes a transaction on behalf of the Safe account. + * This function is intended to be called by executor modules + * @dev If a global hook and/or selector hook is set, it will be called + * @dev AccessControl: only enabled executor modules + * SafeERC7579 supports the following feature set: + * CallTypes: + * - CALLTYPE_SINGLE + * - CALLTYPE_BATCH + * - CALLTYPE_DELEGATECALL + * ExecTypes: + * - EXECTYPE_DEFAULT (revert if not successful) + * - EXECTYPE_TRY + * If a different mode is selected, this function will revert + * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details + * @param executionCalldata The encoded execution call data */ function executeFromExecutor( ModeCode mode, @@ -255,7 +281,7 @@ contract SafeERC7579 is ISafeOp, ISafe7579Init, AccessControl, Initializer, IERC } /** - * ERC4337 v0.7 validation function + * ERC4337 v0.7 validation function * @dev expects that a ERC7579 validator module is encoded within the UserOp nonce. * if no validator module is provided, it will fallback to validate the transaction with * Safe's signers @@ -380,7 +406,19 @@ contract SafeERC7579 is ISafeOp, ISafe7579Init, AccessControl, Initializer, IERC } /** - * @inheritdoc IERC7579Account + * Installs a 7579 Module of a certain type on the smart account + * @dev The module has to be initialized from msg.sender == SafeProxy, we thus use a + * delegatecall to DCUtil, which calls the onInstall/onUninstall function on the ERC7579 + * module and emits the ModuleInstall/ModuleUnintall events + * @dev AccessControl: only Self of Entrypoint can install modules + * @dev If the safe set a registry, ERC7484 registry will be queried before installing + * @dev If a global hook and/or selector hook is set, it will be called + * @param moduleType the module type ID according the ERC-7579 spec + * Note: MULTITYPE_MODULE (uint(0)) is a special type to install a module with + * multiple types + * @param module the module address + * @param initData arbitrary data that may be required on the module during `onInstall` + * initialization. */ function installModule( uint256 moduleType, @@ -393,6 +431,8 @@ contract SafeERC7579 is ISafeOp, ISafe7579Init, AccessControl, Initializer, IERC withHook(IERC7579Account.installModule.selector) onlyEntryPointOrSelf { + // internal install functions will decode the initData param, and return sanitzied + // moduleInitData. This is the initData that will be passed to Module.onInstall() bytes memory moduleInitData; if (moduleType == MODULE_TYPE_VALIDATOR) { moduleInitData = _installValidator(module, initData); @@ -419,7 +459,16 @@ contract SafeERC7579 is ISafeOp, ISafe7579Init, AccessControl, Initializer, IERC } /** - * @inheritdoc IERC7579Account + * Uninstalls a Module of a certain type on the smart account. + * @dev The module has to be initialized from msg.sender == SafeProxy, we thus use a + * delegatecall to DCUtil, which calls the onInstall/onUninstall function on the ERC7579 + * module and emits the ModuleInstall/ModuleUnintall events + * @dev AccessControl: only Self of Entrypoint can install modules + * @dev If a global hook and/or selector hook is set, it will be called + * @param moduleType the module type ID according the ERC-7579 spec + * @param module the module address + * @param deInitData arbitrary data that may be required on the module during `onUninstall` + * de-initialization. */ function uninstallModule( uint256 moduleType, @@ -432,6 +481,8 @@ contract SafeERC7579 is ISafeOp, ISafe7579Init, AccessControl, Initializer, IERC withHook(IERC7579Account.uninstallModule.selector) onlyEntryPointOrSelf { + // internal uninstall functions will decode the deInitData param, and return sanitzied + // moduleDeInitData. This is the initData that will be passed to Module.onUninstall() bytes memory moduleDeInitData; if (moduleType == MODULE_TYPE_VALIDATOR) { moduleDeInitData = _uninstallValidator(module, deInitData); @@ -445,8 +496,10 @@ contract SafeERC7579 is ISafeOp, ISafe7579Init, AccessControl, Initializer, IERC revert UnsupportedModuleType(moduleType); } - // Deinitialize Module via Safe - _delegatecall({ + // Deinitialize Module via Safe. + // We are using "try" here, to avoid DoS. A module could revert in 'onUninstall' and prevent + // the account from removing the module + _tryDelegatecall({ safe: ISafe(msg.sender), target: UTIL, callData: abi.encodeCall( @@ -456,18 +509,41 @@ contract SafeERC7579 is ISafeOp, ISafe7579Init, AccessControl, Initializer, IERC } /** - * @inheritdoc IERC7579Account + * SafeERC7579 supports the following feature set: + * CallTypes: + * - CALLTYPE_SINGLE + * - CALLTYPE_BATCH + * - CALLTYPE_DELEGATECALL + * ExecTypes: + * - EXECTYPE_DEFAULT (revert if not successful) + * - EXECTYPE_TRY */ - function supportsExecutionMode(ModeCode encodedMode) external pure override returns (bool) { - CallType callType = encodedMode.getCallType(); - if (callType == CALLTYPE_BATCH) return true; - else if (callType == CALLTYPE_SINGLE) return true; - else if (callType == CALLTYPE_DELEGATECALL) return true; + function supportsExecutionMode(ModeCode encodedMode) + external + pure + override + returns (bool supported) + { + CallType callType; + ExecType execType; + // solhint-disable-next-line no-inline-assembly + assembly { + callType := encodedMode + execType := shl(8, encodedMode) + } + if (callType == CALLTYPE_BATCH) supported = true; + else if (callType == CALLTYPE_SINGLE) supported = true; + else if (callType == CALLTYPE_DELEGATECALL) supported = true; + else return false; + + if (supported && execType == EXECTYPE_DEFAULT) return supported; + else if (supported && execType == EXECTYPE_TRY) return supported; else return false; } /** - * @inheritdoc IERC7579Account + * Function to check if the account supports installation of a certain module type Id + * @param moduleTypeId the module type ID according the ERC-7579 spec */ function supportsModule(uint256 moduleTypeId) external pure override returns (bool) { if (moduleTypeId == MODULE_TYPE_VALIDATOR) return true; @@ -478,7 +554,15 @@ contract SafeERC7579 is ISafeOp, ISafe7579Init, AccessControl, Initializer, IERC } /** - * @inheritdoc IERC7579Account + * Function to check if the account has a certain module installed + * @param moduleType the module type ID according the ERC-7579 spec + * Note: keep in mind that some contracts can be multiple module types at the same time. It + * thus may be necessary to query multiple module types + * @param module the module address + * @param additionalContext additional context data that the smart account may interpret to + * identifiy conditions under which the module is installed. + * usually this is not necessary, but for some special hooks that + * are stored in mappings, this param might be needed */ function isModuleInstalled( uint256 moduleType, @@ -504,7 +588,7 @@ contract SafeERC7579 is ISafeOp, ISafe7579Init, AccessControl, Initializer, IERC } /** - * @inheritdoc IERC7579Account + * @dev Returns the 7579 account id of the smart account */ function accountId() external view override returns (string memory accountImplementationId) { string memory safeVersion = ISafe(msg.sender).VERSION(); @@ -605,8 +689,6 @@ contract SafeERC7579 is ISafeOp, ISafe7579Init, AccessControl, Initializer, IERC uint192 key = uint192(bytes24(bytes20(address(validator)))); nonce = IEntryPoint(entryPoint()).getNonce(safe, key); } - - function initializeAccount(bytes calldata callData) external payable { } } library EIP712 { diff --git a/accounts/safe7579/src/lib/ModeLib.sol b/accounts/safe7579/src/lib/ModeLib.sol index 61aa583e..df594a6d 100644 --- a/accounts/safe7579/src/lib/ModeLib.sol +++ b/accounts/safe7579/src/lib/ModeLib.sol @@ -65,9 +65,9 @@ type ModePayload is bytes22; CallType constant CALLTYPE_SINGLE = CallType.wrap(0x00); // Batched CallType CallType constant CALLTYPE_BATCH = CallType.wrap(0x01); +CallType constant CALLTYPE_STATIC = CallType.wrap(0xFE); // @dev Implementing delegatecall is OPTIONAL! // implement delegatecall with extreme care. -CallType constant CALLTYPE_STATIC = CallType.wrap(0xFE); CallType constant CALLTYPE_DELEGATECALL = CallType.wrap(0xFF); // @dev default behavior is to revert on failure From 350eef2717523869214589da586fc65bc8777ab8 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Mon, 22 Apr 2024 12:30:54 +0700 Subject: [PATCH 58/64] cleaning --- accounts/safe7579/src/core/ModuleManager.sol | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/accounts/safe7579/src/core/ModuleManager.sol b/accounts/safe7579/src/core/ModuleManager.sol index 8356ef59..80a2fb6d 100644 --- a/accounts/safe7579/src/core/ModuleManager.sol +++ b/accounts/safe7579/src/core/ModuleManager.sol @@ -18,7 +18,6 @@ import { MODULE_TYPE_HOOK } from "erc7579/interfaces/IERC7579Module.sol"; -import "forge-std/console2.sol"; /** * @title ModuleManager * Contract that implements ERC7579 Module compatibility for Safe accounts @@ -31,9 +30,7 @@ import "forge-std/console2.sol"; * - Hook Modules * Note: the Storage mappings for each section, are not listed on the very top, but in the * respective section - * */ - abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { using SentinelListLib for SentinelListLib.SentinelList; using SentinelList4337Lib for SentinelList4337Lib.SentinelList; @@ -67,7 +64,7 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { } /** - * Uninstall and de-initialize validator module + * Uninstall validator module * @dev This function does not prevent the user from uninstalling all validator modules. * Since the Safe7579 signature validation can fallback to Safe's checkSignature() * function, it is okay, if all validator modules are removed. @@ -139,7 +136,6 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { { SentinelListLib.SentinelList storage $executors = $executorStorage[msg.sender]; $executors.push(executor); - // Initialize Executor Module via Safe return data; } @@ -251,9 +247,12 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { } /** - * Fallback implementation supports callTypes: - * - CALLTYPE_STATIC - * - CALLTYPE_SINGLE + * @dev AccessControl: any external contract / EOA may call this function + * SafeERC7579 Fallback supports the following feature set: + * CallTypes: + * - CALLTYPE_SINGLE + * - CALLTYPE_BATCH + * @dev If a global hook and/or selector hook is set, it will be called */ // solhint-disable-next-line no-complex-fallback fallback(bytes calldata callData) @@ -484,8 +483,9 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { bytes[] calldata contexts; bytes calldata moduleInitData; - // equivalent of (types, contexs, moduleInitData) = - // abi.decode(initData,(uint[],bytes[],bytes) + // equivalent of: + // (types, contexs, moduleInitData) = abi.decode(initData,(uint[],bytes[],bytes) + // solhint-disable-next-line no-inline-assembly assembly ("memory-safe") { let offset := initData.offset let baseOffset := offset From 901a0aec6b9d841b852e5487f4931cc12472f02e Mon Sep 17 00:00:00 2001 From: zeroknots Date: Mon, 22 Apr 2024 12:36:58 +0700 Subject: [PATCH 59/64] add docs --- accounts/safe7579/src/core/RegistryAdapter.sol | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/accounts/safe7579/src/core/RegistryAdapter.sol b/accounts/safe7579/src/core/RegistryAdapter.sol index 6744a537..9365a066 100644 --- a/accounts/safe7579/src/core/RegistryAdapter.sol +++ b/accounts/safe7579/src/core/RegistryAdapter.sol @@ -11,7 +11,7 @@ import { ISafe } from "../interfaces/ISafe.sol"; * attesters to trust. */ abstract contract RegistryAdapter is ExecutionHelper { - event ERC7484RegistryConfigured(address indexed smartAccount, address indexed registry); + event ERC7484RegistryConfigured(address indexed smartAccount, IERC7484 indexed registry); mapping(address smartAccount => IERC7484 registry) internal $registry; @@ -20,6 +20,10 @@ abstract contract RegistryAdapter is ExecutionHelper { _; } + /** + * Check on ERC7484 Registry, if suffcient attestations were made + * This will revert, if not succicient valid attestations are on the registry + */ function _checkRegistry(address module, uint256 moduleType) internal view { IERC7484 registry = $registry[msg.sender]; if (address(registry) != address(0)) { @@ -28,6 +32,9 @@ abstract contract RegistryAdapter is ExecutionHelper { } } + /** + * Configure ERC7484 Registry for Safe + */ function _configureRegistry( IERC7484 registry, address[] calldata attesters, @@ -42,5 +49,6 @@ abstract contract RegistryAdapter is ExecutionHelper { value: 0, callData: abi.encodeCall(IERC7484.trustAttesters, (threshold, attesters)) }); + emit ERC7484RegistryConfigured(msg.sender, registry); } } From 0a2f09b0d8d57423ce7951967ef1ce58934b2654 Mon Sep 17 00:00:00 2001 From: zeroknots Date: Tue, 23 Apr 2024 09:14:01 +0700 Subject: [PATCH 60/64] refactor --- accounts/safe7579/src/DataTypes.sol | 26 ++ accounts/safe7579/src/ISafe7579.sol | 273 ++++++++++++++++++ .../src/{SafeERC7579.sol => Safe7579.sol} | 113 ++------ .../Launchpad.sol => Safe7579Launchpad.sol} | 36 ++- accounts/safe7579/src/core/AccessControl.sol | 4 +- accounts/safe7579/src/core/Initializer.sol | 34 +-- accounts/safe7579/src/core/ModuleManager.sol | 37 +-- .../safe7579/src/core/RegistryAdapter.sol | 6 +- accounts/safe7579/src/core/SetupDCUtil.sol | 5 +- ...Safe7579Init.sol => ISafe7579Init.sol.bak} | 14 +- .../test/ERC7579Compliance/Base.t.sol | 3 +- .../ERC7579Compliance/Executions4337.t.sol | 13 +- .../ERC7579Compliance/ExecutionsModule.t.sol | 10 +- .../test/ERC7579Compliance/Hooks.t.sol | 15 +- .../ERC7579Compliance/ModuleManagement.t.sol | 24 +- accounts/safe7579/test/Launchpad.t.sol | 28 +- accounts/safe7579/test/SafeERC7579.t.sol | 7 +- .../safe7579/Safe7579Factory.sol | 6 +- 18 files changed, 425 insertions(+), 229 deletions(-) create mode 100644 accounts/safe7579/src/DataTypes.sol create mode 100644 accounts/safe7579/src/ISafe7579.sol rename accounts/safe7579/src/{SafeERC7579.sol => Safe7579.sol} (80%) rename accounts/safe7579/src/{utils/Launchpad.sol => Safe7579Launchpad.sol} (92%) rename accounts/safe7579/src/interfaces/{ISafe7579Init.sol => ISafe7579Init.sol.bak} (68%) diff --git a/accounts/safe7579/src/DataTypes.sol b/accounts/safe7579/src/DataTypes.sol new file mode 100644 index 00000000..9405d00d --- /dev/null +++ b/accounts/safe7579/src/DataTypes.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.25; + +import { IERC7484 } from "./interfaces/IERC7484.sol"; +import { CallType } from "./lib/ModeLib.sol"; + +struct FallbackHandler { + address handler; + CallType calltype; +} + +enum HookType { + GLOBAL, + SIG +} + +struct ModuleInit { + address module; + bytes initData; +} + +struct RegistryInit { + IERC7484 registry; + address[] attesters; + uint8 threshold; +} diff --git a/accounts/safe7579/src/ISafe7579.sol b/accounts/safe7579/src/ISafe7579.sol new file mode 100644 index 00000000..55f3f6cc --- /dev/null +++ b/accounts/safe7579/src/ISafe7579.sol @@ -0,0 +1,273 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.25; + +import "./DataTypes.sol"; +import { IERC7579Account } from "./interfaces//IERC7579Account.sol"; + +import { CallType, ExecType, ModeCode } from "./lib/ModeLib.sol"; +import { PackedUserOperation } from + "@ERC4337/account-abstraction/contracts/core/UserOperationLib.sol"; + +/** + * @title ERC7579 Adapter for Safe accounts. + * creates full ERC7579 compliance to Safe accounts + * @author rhinestone | zeroknots.eth, Konrad Kopp (@kopy-kat) + */ +interface ISafe7579 is IERC7579Account { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* Validation */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /** + * ERC4337 v0.7 validation function + * @dev expects that a ERC7579 validator module is encoded within the UserOp nonce. + * if no validator module is provided, it will fallback to validate the transaction with + * Safe's signers + */ + function validateUserOp( + PackedUserOperation memory userOp, + bytes32 userOpHash, + uint256 missingAccountFunds + ) + external + payable + returns (uint256 packedValidSig); + + /** + * Will use Safe's signed messages or checkSignatures features or ERC7579 validation modules + * if no signature is provided, it makes use of Safe's signedMessages + * if address(0) or a non-installed validator module is provided, it will use Safe's + * checkSignatures + * if a valid validator module is provided, it will use the module's validateUserOp function + * @param hash message hash of ERC1271 request + * @param data abi.encodePacked(address validationModule, bytes signatures) + */ + function isValidSignature( + bytes32 hash, + bytes memory data + ) + external + view + returns (bytes4 magicValue); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* Executions */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /** + * @dev Executes a transaction on behalf of the Safe account. + * This function is intended to be called by ERC-4337 EntryPoint.sol + * @dev If a global hook and/or selector hook is set, it will be called + * @dev AccessControl: only Self of Entrypoint can install modules + * Safe7579 supports the following feature set: + * CallTypes: + * - CALLTYPE_SINGLE + * - CALLTYPE_BATCH + * - CALLTYPE_DELEGATECALL + * ExecTypes: + * - EXECTYPE_DEFAULT (revert if not successful) + * - EXECTYPE_TRY + * If a different mode is selected, this function will revert + * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details + * @param executionCalldata The encoded execution call data + */ + function execute(ModeCode mode, bytes memory executionCalldata) external payable; + + /** + * @dev Executes a transaction on behalf of the Safe account. + * This function is intended to be called by executor modules + * @dev If a global hook and/or selector hook is set, it will be called + * @dev AccessControl: only enabled executor modules + * Safe7579 supports the following feature set: + * CallTypes: + * - CALLTYPE_SINGLE + * - CALLTYPE_BATCH + * - CALLTYPE_DELEGATECALL + * ExecTypes: + * - EXECTYPE_DEFAULT (revert if not successful) + * - EXECTYPE_TRY + * If a different mode is selected, this function will revert + * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details + * @param executionCalldata The encoded execution call data + */ + function executeFromExecutor( + ModeCode mode, + bytes memory executionCalldata + ) + external + payable + returns (bytes[] memory returnDatas); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* Manage Modules */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /** + * Installs a 7579 Module of a certain type on the smart account + * @dev The module has to be initialized from msg.sender == SafeProxy, we thus use a + * delegatecall to DCUtil, which calls the onInstall/onUninstall function on the ERC7579 + * module and emits the ModuleInstall/ModuleUnintall events + * @dev AccessControl: only Self of Entrypoint can install modules + * @dev If the safe set a registry, ERC7484 registry will be queried before installing + * @dev If a global hook and/or selector hook is set, it will be called + * @param moduleType the module type ID according the ERC-7579 spec + * Note: MULTITYPE_MODULE (uint(0)) is a special type to install a module with + * multiple types + * @param module the module address + * @param initData arbitrary data that may be required on the module during `onInstall` + * initialization. + */ + function installModule( + uint256 moduleType, + address module, + bytes memory initData + ) + external + payable; + + /** + * Uninstalls a Module of a certain type on the smart account. + * @dev The module has to be initialized from msg.sender == SafeProxy, we thus use a + * delegatecall to DCUtil, which calls the onInstall/onUninstall function on the ERC7579 + * module and emits the ModuleInstall/ModuleUnintall events + * @dev AccessControl: only Self of Entrypoint can install modules + * @dev If a global hook and/or selector hook is set, it will be called + * @param moduleType the module type ID according the ERC-7579 spec + * @param module the module address + * @param deInitData arbitrary data that may be required on the module during `onUninstall` + * de-initialization. + */ + function uninstallModule( + uint256 moduleType, + address module, + bytes memory deInitData + ) + external + payable; + + /** + * Function to check if the account has a certain module installed + * @param moduleType the module type ID according the ERC-7579 spec + * Note: keep in mind that some contracts can be multiple module types at the same time. It + * thus may be necessary to query multiple module types + * @param module the module address + * @param additionalContext additional context data that the smart account may interpret to + * identifiy conditions under which the module is installed. + * usually this is not necessary, but for some special hooks that + * are stored in mappings, this param might be needed + */ + function isModuleInstalled( + uint256 moduleType, + address module, + bytes memory additionalContext + ) + external + view + returns (bool); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* Initialize Safe7579 */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /** + * This function can be called by the Launchpad.initSafe7579() or by already existing Safes that + * want to use Safe7579 + * if this is called by the Launchpad, it is expected that launchpadValidators() was called + * previously, and the param validators is empty + * @param validators validator modules and initData + * @param executors executor modules and initData + * @param executors executor modules and initData + * @param fallbacks fallback modules and initData + * @param hooks hook module and initData + * @param registryInit (OPTIONAL) registry, attesters and threshold for IERC7484 Registry + * If not provided, the registry will be set to the zero address, and no + * registry checks will be performed + */ + function initializeAccount( + ModuleInit[] memory validators, + ModuleInit[] memory executors, + ModuleInit[] memory fallbacks, + ModuleInit[] memory hooks, + RegistryInit memory registryInit + ) + external + payable; + + /** + * This function is intended to be called by Launchpad.validateUserOp() + * @dev it will initialize the SentinelList4337 list for validators, and sstore all + * validators + * @dev Since this function has to be 4337 compliant (storage access), only validator storage is acccess + * @dev Note: this function DOES NOT call onInstall() on the validator modules or emit + * ModuleInstalled events. this has to be done by the launchpad + */ + function launchpadValidators(ModuleInit[] memory validators) external payable; + + /** + * TODO: + */ + function setRegistry(IERC7484 registry, address[] memory attesters, uint8 threshold) external; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* Query Account Details */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + function getValidatorPaginated( + address start, + uint256 pageSize + ) + external + view + returns (address[] memory array, address next); + + function getActiveHook() external view returns (address hook); + function getActiveHook(bytes4 selector) external view returns (address hook); + function getExecutorsPaginated( + address cursor, + uint256 size + ) + external + view + returns (address[] memory array, address next); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* Query Misc */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + function supportsExecutionMode(ModeCode encodedMode) external pure returns (bool supported); + function supportsModule(uint256 moduleTypeId) external pure returns (bool); + function accountId() external view returns (string memory accountImplementationId); + + /** + * Domain Separator for EIP-712. + */ + function domainSeparator() external view returns (bytes32); + /** + * Safe7579 is using validator selection encoding in the userop nonce. + * to make it easier for SDKs / devs to integrate, this function can be + * called to get the next nonce for a specific validator + * @param safe address of safe account + * @param validator ERC7579 validator to encode + */ + function getNonce(address safe, address validator) external view returns (uint256 nonce); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* Custom Errors */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + error InvalidModule(address module); + error LinkedListError(); + error InitializerError(); + error ValidatorStorageHelperError(); + + // fallback handlers + error InvalidInput(); + error NoFallbackHandler(bytes4 msgSig); + error InvalidFallbackHandler(bytes4 msgSig); + error FallbackInstalled(bytes4 msgSig); + + // Hooks + error HookPostCheckFailed(); + error HookAlreadyInstalled(address currentHook); + error InvalidHookType(); + + // Registry Adapter + event ERC7484RegistryConfigured(address indexed smartAccount, IERC7484 indexed registry); +} diff --git a/accounts/safe7579/src/SafeERC7579.sol b/accounts/safe7579/src/Safe7579.sol similarity index 80% rename from accounts/safe7579/src/SafeERC7579.sol rename to accounts/safe7579/src/Safe7579.sol index 4f9ef697..68cdb73f 100644 --- a/accounts/safe7579/src/SafeERC7579.sol +++ b/accounts/safe7579/src/Safe7579.sol @@ -1,5 +1,5 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.23; +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.25; import { IERC7579Account, Execution } from "./interfaces/IERC7579Account.sol"; import { @@ -26,13 +26,13 @@ import { AccessControl } from "./core/AccessControl.sol"; import { Initializer } from "./core/Initializer.sol"; import { ISafeOp, SAFE_OP_TYPEHASH } from "./interfaces/ISafeOp.sol"; import { ISafe } from "./interfaces/ISafe.sol"; +import { ISafe7579 } from "./ISafe7579.sol"; import { PackedUserOperation, UserOperationLib } from "@ERC4337/account-abstraction/contracts/core/UserOperationLib.sol"; import { _packValidationData } from "@ERC4337/account-abstraction/contracts/core/Helpers.sol"; import { IEntryPoint } from "@ERC4337/account-abstraction/contracts/interfaces/IEntryPoint.sol"; -import { ISafe7579Init } from "./interfaces/ISafe7579Init.sol"; import { IERC1271 } from "./interfaces/IERC1271.sol"; uint256 constant MULTITYPE_MODULE = 0; @@ -50,13 +50,11 @@ uint256 constant MULTITYPE_MODULE = 0; * event emissions to be done via the SafeProxy as msg.sender using Safe's * "executeTransactionFromModule" features. */ -contract SafeERC7579 is ISafeOp, ISafe7579Init, AccessControl, Initializer, IERC7579Account { +contract Safe7579 is ISafe7579, ISafeOp, AccessControl, Initializer { using UserOperationLib for PackedUserOperation; using ModeLib for ModeCode; using ExecutionLib for bytes; - error Unsupported(); - bytes32 private constant DOMAIN_SEPARATOR_TYPEHASH = 0x47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a79469218; @@ -67,21 +65,7 @@ contract SafeERC7579 is ISafeOp, ISafe7579Init, AccessControl, Initializer, IERC bytes4 private constant SAFE_SIGNATURE_MAGIC_VALUE = 0x5fd7e97d; /** - * @dev Executes a transaction on behalf of the Safe account. - * This function is intended to be called by ERC-4337 EntryPoint.sol - * @dev If a global hook and/or selector hook is set, it will be called - * @dev AccessControl: only Self of Entrypoint can install modules - * SafeERC7579 supports the following feature set: - * CallTypes: - * - CALLTYPE_SINGLE - * - CALLTYPE_BATCH - * - CALLTYPE_DELEGATECALL - * ExecTypes: - * - EXECTYPE_DEFAULT (revert if not successful) - * - EXECTYPE_TRY - * If a different mode is selected, this function will revert - * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details - * @param executionCalldata The encoded execution call data + * @inheritdoc ISafe7579 */ function execute( ModeCode mode, @@ -162,21 +146,7 @@ contract SafeERC7579 is ISafeOp, ISafe7579Init, AccessControl, Initializer, IERC } /** - * @dev Executes a transaction on behalf of the Safe account. - * This function is intended to be called by executor modules - * @dev If a global hook and/or selector hook is set, it will be called - * @dev AccessControl: only enabled executor modules - * SafeERC7579 supports the following feature set: - * CallTypes: - * - CALLTYPE_SINGLE - * - CALLTYPE_BATCH - * - CALLTYPE_DELEGATECALL - * ExecTypes: - * - EXECTYPE_DEFAULT (revert if not successful) - * - EXECTYPE_TRY - * If a different mode is selected, this function will revert - * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details - * @param executionCalldata The encoded execution call data + * @inheritdoc ISafe7579 */ function executeFromExecutor( ModeCode mode, @@ -281,10 +251,7 @@ contract SafeERC7579 is ISafeOp, ISafe7579Init, AccessControl, Initializer, IERC } /** - * ERC4337 v0.7 validation function - * @dev expects that a ERC7579 validator module is encoded within the UserOp nonce. - * if no validator module is provided, it will fallback to validate the transaction with - * Safe's signers + * @inheritdoc ISafe7579 */ function validateUserOp( PackedUserOperation calldata userOp, @@ -356,13 +323,7 @@ contract SafeERC7579 is ISafeOp, ISafe7579Init, AccessControl, Initializer, IERC } /** - * Will use Safe's signed messages or checkSignatures features or ERC7579 validation modules - * if no signature is provided, it makes use of Safe's signedMessages - * if address(0) or a non-installed validator module is provided, it will use Safe's - * checkSignatures - * if a valid validator module is provided, it will use the module's validateUserOp function - * @param hash message hash of ERC1271 request - * @param data abi.encodePacked(address validationModule, bytes signatures) + * @inheritdoc ISafe7579 */ function isValidSignature( bytes32 hash, @@ -406,19 +367,7 @@ contract SafeERC7579 is ISafeOp, ISafe7579Init, AccessControl, Initializer, IERC } /** - * Installs a 7579 Module of a certain type on the smart account - * @dev The module has to be initialized from msg.sender == SafeProxy, we thus use a - * delegatecall to DCUtil, which calls the onInstall/onUninstall function on the ERC7579 - * module and emits the ModuleInstall/ModuleUnintall events - * @dev AccessControl: only Self of Entrypoint can install modules - * @dev If the safe set a registry, ERC7484 registry will be queried before installing - * @dev If a global hook and/or selector hook is set, it will be called - * @param moduleType the module type ID according the ERC-7579 spec - * Note: MULTITYPE_MODULE (uint(0)) is a special type to install a module with - * multiple types - * @param module the module address - * @param initData arbitrary data that may be required on the module during `onInstall` - * initialization. + * @inheritdoc ISafe7579 */ function installModule( uint256 moduleType, @@ -459,16 +408,7 @@ contract SafeERC7579 is ISafeOp, ISafe7579Init, AccessControl, Initializer, IERC } /** - * Uninstalls a Module of a certain type on the smart account. - * @dev The module has to be initialized from msg.sender == SafeProxy, we thus use a - * delegatecall to DCUtil, which calls the onInstall/onUninstall function on the ERC7579 - * module and emits the ModuleInstall/ModuleUnintall events - * @dev AccessControl: only Self of Entrypoint can install modules - * @dev If a global hook and/or selector hook is set, it will be called - * @param moduleType the module type ID according the ERC-7579 spec - * @param module the module address - * @param deInitData arbitrary data that may be required on the module during `onUninstall` - * de-initialization. + * @inheritdoc ISafe7579 */ function uninstallModule( uint256 moduleType, @@ -509,14 +449,7 @@ contract SafeERC7579 is ISafeOp, ISafe7579Init, AccessControl, Initializer, IERC } /** - * SafeERC7579 supports the following feature set: - * CallTypes: - * - CALLTYPE_SINGLE - * - CALLTYPE_BATCH - * - CALLTYPE_DELEGATECALL - * ExecTypes: - * - EXECTYPE_DEFAULT (revert if not successful) - * - EXECTYPE_TRY + * @inheritdoc ISafe7579 */ function supportsExecutionMode(ModeCode encodedMode) external @@ -542,8 +475,7 @@ contract SafeERC7579 is ISafeOp, ISafe7579Init, AccessControl, Initializer, IERC } /** - * Function to check if the account supports installation of a certain module type Id - * @param moduleTypeId the module type ID according the ERC-7579 spec + * @inheritdoc ISafe7579 */ function supportsModule(uint256 moduleTypeId) external pure override returns (bool) { if (moduleTypeId == MODULE_TYPE_VALIDATOR) return true; @@ -554,15 +486,7 @@ contract SafeERC7579 is ISafeOp, ISafe7579Init, AccessControl, Initializer, IERC } /** - * Function to check if the account has a certain module installed - * @param moduleType the module type ID according the ERC-7579 spec - * Note: keep in mind that some contracts can be multiple module types at the same time. It - * thus may be necessary to query multiple module types - * @param module the module address - * @param additionalContext additional context data that the smart account may interpret to - * identifiy conditions under which the module is installed. - * usually this is not necessary, but for some special hooks that - * are stored in mappings, this param might be needed + * @inheritdoc ISafe7579 */ function isModuleInstalled( uint256 moduleType, @@ -571,7 +495,6 @@ contract SafeERC7579 is ISafeOp, ISafe7579Init, AccessControl, Initializer, IERC ) external view - override returns (bool) { if (moduleType == MODULE_TYPE_VALIDATOR) { @@ -588,9 +511,9 @@ contract SafeERC7579 is ISafeOp, ISafe7579Init, AccessControl, Initializer, IERC } /** - * @dev Returns the 7579 account id of the smart account + * @inheritdoc ISafe7579 */ - function accountId() external view override returns (string memory accountImplementationId) { + function accountId() external view returns (string memory accountImplementationId) { string memory safeVersion = ISafe(msg.sender).VERSION(); return string(abi.encodePacked("safe-", safeVersion, ".erc7579.v0.0.1")); } @@ -674,16 +597,14 @@ contract SafeERC7579 is ISafeOp, ISafe7579Init, AccessControl, Initializer, IERC } /** - * Domain Separator for EIP-712. + * @inheritdoc ISafe7579 */ function domainSeparator() public view returns (bytes32) { return keccak256(abi.encode(DOMAIN_SEPARATOR_TYPEHASH, block.chainid, this)); } /** - * Safe7579 is using validator selection encoding in the userop nonce. - * to make it easier for SDKs / devs to integrate, this function can be - * called to get the next nonce for a specific validator + * @inheritdoc ISafe7579 */ function getNonce(address safe, address validator) external view returns (uint256 nonce) { uint192 key = uint192(bytes24(bytes20(address(validator)))); diff --git a/accounts/safe7579/src/utils/Launchpad.sol b/accounts/safe7579/src/Safe7579Launchpad.sol similarity index 92% rename from accounts/safe7579/src/utils/Launchpad.sol rename to accounts/safe7579/src/Safe7579Launchpad.sol index 7290f1a5..781c48d3 100644 --- a/accounts/safe7579/src/utils/Launchpad.sol +++ b/accounts/safe7579/src/Safe7579Launchpad.sol @@ -2,10 +2,11 @@ pragma solidity ^0.8.22; import { IAccount, PackedUserOperation } from "account-abstraction/interfaces/IAccount.sol"; -import { ISafe } from "../interfaces/ISafe.sol"; -import { ISafe7579Init } from "../interfaces/ISafe7579Init.sol"; -import { IERC7484 } from "../interfaces/IERC7484.sol"; -import { SafeERC7579 } from "../SafeERC7579.sol"; +import { ISafe } from "./interfaces/ISafe.sol"; +import { ISafe7579 } from "./ISafe7579.sol"; +import { IERC7484 } from "./interfaces/IERC7484.sol"; +import "./DataTypes.sol"; +import { Safe7579 } from "./Safe7579.sol"; import { IValidator } from "erc7579/interfaces/IERC7579Module.sol"; @@ -13,6 +14,7 @@ import { SafeStorage } from "@safe-global/safe-contracts/contracts/libraries/Saf /** * Launchpad to deploy a Safe account and connect the Safe7579 adapter. + * Check Readme.md for more information. * Special thanks to [nlordell (Safe)](https://github.com/nlordell), who came up with [this * technique](https://github.com/safe-global/safe-modules/pull/184) * @author rhinestone | zeroknots.eth @@ -36,14 +38,14 @@ contract Safe7579Launchpad is IAccount, SafeStorage { uint256 threshold; address setupTo; bytes setupData; - address safe7579; - ISafe7579Init.ModuleInit[] validators; + ISafe7579 safe7579; + ModuleInit[] validators; bytes callData; } // solhint-disable max-line-length bytes32 private constant SAFE_INIT_TYPEHASH = keccak256( - "InitData(address singleton,address[] owners,uint256 threshold,address setupTo,bytes setupData,address safe7579,ISafe7579Init.ModuleInit[] validators,bytes callData)" + "InitData(address singleton,address[] owners,uint256 threshold,address setupTo,bytes setupData,address safe7579,ModuleInit[] validators,bytes callData)" ); address private immutable SELF; @@ -89,9 +91,9 @@ contract Safe7579Launchpad is IAccount, SafeStorage { */ function initSafe7579( address safe7579, - ISafe7579Init.ModuleInit[] calldata executors, - ISafe7579Init.ModuleInit[] calldata fallbacks, - ISafe7579Init.ModuleInit[] calldata hooks, + ModuleInit[] calldata executors, + ModuleInit[] calldata fallbacks, + ModuleInit[] calldata hooks, address[] calldata attesters, uint8 threshold ) @@ -99,16 +101,12 @@ contract Safe7579Launchpad is IAccount, SafeStorage { onlyDelegatecall { ISafe(address(this)).enableModule(safe7579); - SafeERC7579(payable(safe7579)).initializeAccount({ - validators: new ISafe7579Init.ModuleInit[](0), + ISafe7579(payable(safe7579)).initializeAccount({ + validators: new ModuleInit[](0), executors: executors, fallbacks: fallbacks, hooks: hooks, - registryInit: ISafe7579Init.RegistryInit({ - registry: REGISTRY, - attesters: attesters, - threshold: threshold - }) + registryInit: RegistryInit({ registry: REGISTRY, attesters: attesters, threshold: threshold }) }); } @@ -185,7 +183,7 @@ contract Safe7579Launchpad is IAccount, SafeStorage { } // initialize validator on behalf of the safe account - ISafe7579Init(initData.safe7579).launchpadValidators(initData.validators); + ISafe7579(initData.safe7579).launchpadValidators(initData.validators); // Call onInstall on each validator module to set up the validators. // Since this function is delegatecalled by the SafeProxy, the Validator Module is called @@ -239,7 +237,7 @@ contract Safe7579Launchpad is IAccount, SafeStorage { _threshold: initData.threshold, to: initData.setupTo, data: initData.setupData, - fallbackHandler: initData.safe7579, + fallbackHandler: address(initData.safe7579), paymentToken: address(0), payment: 0, paymentReceiver: payable(address(0)) diff --git a/accounts/safe7579/src/core/AccessControl.sol b/accounts/safe7579/src/core/AccessControl.sol index ec906dee..d868d3db 100644 --- a/accounts/safe7579/src/core/AccessControl.sol +++ b/accounts/safe7579/src/core/AccessControl.sol @@ -8,8 +8,9 @@ import { AccountBase } from "erc7579/core/AccountBase.sol"; * Implements AccessControl for Safe7579 adapter. * Since Safe7579 Adapter is installed as a fallback handler on the safe account, we are making use * of handlercontext (ERC2771) + * @author zeroknots.eth | rhinestone.wtf */ -contract AccessControl is HandlerContext, AccountBase { +abstract contract AccessControl is HandlerContext, AccountBase { modifier onlyEntryPointOrSelf() virtual override { if (!(_msgSender() == entryPoint() || msg.sender == _msgSender())) { revert AccountAccessUnauthorized(); @@ -18,7 +19,6 @@ contract AccessControl is HandlerContext, AccountBase { } modifier onlyEntryPoint() virtual override { - if (_msgSender() != entryPoint()) { revert AccountAccessUnauthorized(); } diff --git a/accounts/safe7579/src/core/Initializer.sol b/accounts/safe7579/src/core/Initializer.sol index b8050daf..66e15558 100644 --- a/accounts/safe7579/src/core/Initializer.sol +++ b/accounts/safe7579/src/core/Initializer.sol @@ -1,7 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.23; -import { ISafe7579Init } from "../interfaces/ISafe7579Init.sol"; +import { ISafe7579 } from "../ISafe7579.sol"; +import "../DataTypes.sol"; import { ModuleManager } from "./ModuleManager.sol"; import { IERC7484 } from "../interfaces/IERC7484.sol"; import { SentinelList4337Lib } from "sentinellist/SentinelList4337.sol"; @@ -9,8 +10,9 @@ import { SentinelListLib } from "sentinellist/SentinelList.sol"; /** * Functions that can be used to initialze Safe7579 for a Safe Account + * @author zeroknots.eth | rhinestone.wtf */ -abstract contract Initializer is ISafe7579Init, ModuleManager { +abstract contract Initializer is ISafe7579, ModuleManager { using SentinelList4337Lib for SentinelList4337Lib.SentinelList; using SentinelListLib for SentinelListLib.SentinelList; @@ -19,12 +21,7 @@ abstract contract Initializer is ISafe7579Init, ModuleManager { error InvalidInitData(address safe); /** - * This function is intended to be called by Launchpad.validateUserOp() - * @dev it will initialize the SentinelList4337 list for validators, and sstore all - * validators - * @dev Since this function has to be 4337 compliant (storage access), only validator storage is acccess - * @dev Note: this function DOES NOT call onInstall() on the validator modules or emit - * ModuleInstalled events. this has to be done by the launchpad + * @inheritdoc ISafe7579 */ function launchpadValidators(ModuleInit[] calldata validators) external payable override { // this will revert if already initialized @@ -40,18 +37,7 @@ abstract contract Initializer is ISafe7579Init, ModuleManager { } /** - * This function can be called by the Launchpad.initSafe7579() or by already existing Safes that - * want to use Safe7579 - * if this is called by the Launchpad, it is expected that launchpadValidators() was called - * previously, and the param validators is empty - * @param validators validator modules and initData - * @param executors executor modules and initData - * @param executors executor modules and initData - * @param fallbacks fallback modules and initData - * @param hooks hook module and initData - * @param registryInit (OPTIONAL) registry, attesters and threshold for IERC7484 Registry - * If not provided, the registry will be set to the zero address, and no - * registry checks will be performed + * @inheritdoc ISafe7579 */ function initializeAccount( ModuleInit[] calldata validators, @@ -68,6 +54,10 @@ abstract contract Initializer is ISafe7579Init, ModuleManager { _initModules(validators, executors, fallbacks, hooks); } + /** + * _initModules may be used via launchpad deploymet or directly by already deployed Safe + * accounts + */ function _initModules( ModuleInit[] calldata validators, ModuleInit[] calldata executors, @@ -77,7 +67,6 @@ abstract contract Initializer is ISafe7579Init, ModuleManager { internal { uint256 length = validators.length; - // _initModules may be used via launchpad or directly by already deployed Safe accounts // if this function is called by the launchpad, validators will be initialized via // launchpadValidators() // to avoid double initialization, we check if the validators are already initialized @@ -120,6 +109,9 @@ abstract contract Initializer is ISafe7579Init, ModuleManager { emit Safe7579Initialized(msg.sender); } + /** + * @inheritdoc ISafe7579 + */ function setRegistry( IERC7484 registry, address[] calldata attesters, diff --git a/accounts/safe7579/src/core/ModuleManager.sol b/accounts/safe7579/src/core/ModuleManager.sol index 31eccd2a..210c39ff 100644 --- a/accounts/safe7579/src/core/ModuleManager.sol +++ b/accounts/safe7579/src/core/ModuleManager.sol @@ -5,6 +5,8 @@ import { SentinelListLib } from "sentinellist/SentinelList.sol"; import { SentinelList4337Lib } from "sentinellist/SentinelList4337.sol"; import { IModule, IHook } from "../interfaces/IERC7579Module.sol"; import { ISafe } from "../interfaces/ISafe.sol"; +import { ISafe7579 } from "../ISafe7579.sol"; +import "../DataTypes.sol"; import { ModuleInstallUtil } from "../utils/DCUtil.sol"; import { RegistryAdapter } from "./RegistryAdapter.sol"; @@ -31,16 +33,10 @@ import { * Note: the Storage mappings for each section, are not listed on the very top, but in the * respective section */ -abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { +abstract contract ModuleManager is ISafe7579, AccessControl, Receiver, RegistryAdapter { using SentinelListLib for SentinelListLib.SentinelList; using SentinelList4337Lib for SentinelList4337Lib.SentinelList; - error InvalidModule(address module); - error LinkedListError(); - error InitializerError(); - error ValidatorStorageHelperError(); - error InvalidInput(); - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* VALIDATOR MODULES */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ @@ -173,14 +169,6 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* FALLBACK MODULES */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - error NoFallbackHandler(bytes4 msgSig); - error InvalidFallbackHandler(bytes4 msgSig); - error FallbackInstalled(bytes4 msgSig); - - struct FallbackHandler { - address handler; - CallType calltype; - } mapping(address smartAccount => mapping(bytes4 selector => FallbackHandler handlerConfig)) internal $fallbackStorage; @@ -229,7 +217,6 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { FallbackHandler storage $fallbacks = $fallbackStorage[msg.sender][functionSig]; delete $fallbacks.handler; - } function _isFallbackHandlerInstalled( @@ -249,7 +236,7 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { /** * @dev AccessControl: any external contract / EOA may call this function - * SafeERC7579 Fallback supports the following feature set: + * Safe7579 Fallback supports the following feature set: * CallTypes: * - CALLTYPE_SINGLE * - CALLTYPE_BATCH @@ -307,15 +294,9 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { mapping(address smartAccount => address globalHook) internal $globalHook; mapping(address smartAccount => mapping(bytes4 => address hook)) internal $hookManager; - error HookPostCheckFailed(); - error HookAlreadyInstalled(address currentHook); - error InvalidHookType(); - - enum HookType { - GLOBAL, - SIG - } - + /** + * Run precheck hook for global and function selector specific + */ function _preHooks( address globalHook, address sigHook @@ -343,6 +324,7 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { } } + // Run post hooks (global and function sig) function _postHooks( address globalHook, address sigHook, @@ -369,6 +351,9 @@ abstract contract ModuleManager is AccessControl, Receiver, RegistryAdapter { } } + /** + * modifier that executes global hook, and function signature specific hook if enabled + */ modifier withHook(bytes4 selector) { address globalHook = $globalHook[msg.sender]; address sigHook = $hookManager[msg.sender][selector]; diff --git a/accounts/safe7579/src/core/RegistryAdapter.sol b/accounts/safe7579/src/core/RegistryAdapter.sol index 9365a066..77ac4146 100644 --- a/accounts/safe7579/src/core/RegistryAdapter.sol +++ b/accounts/safe7579/src/core/RegistryAdapter.sol @@ -4,15 +4,15 @@ pragma solidity ^0.8.23; import { IERC7484 } from "../interfaces/IERC7484.sol"; import { ExecutionHelper } from "./ExecutionHelper.sol"; import { ISafe } from "../interfaces/ISafe.sol"; +import { ISafe7579 } from "../ISafe7579.sol"; /** * IERC7484 Registry adapter. * this feature is opt-in. The smart account owner can choose to use the registry and which * attesters to trust. + * @author zeroknots.eth | rhinestone.wtf */ -abstract contract RegistryAdapter is ExecutionHelper { - event ERC7484RegistryConfigured(address indexed smartAccount, IERC7484 indexed registry); - +abstract contract RegistryAdapter is ISafe7579, ExecutionHelper { mapping(address smartAccount => IERC7484 registry) internal $registry; modifier withRegistry(address module, uint256 moduleType) { diff --git a/accounts/safe7579/src/core/SetupDCUtil.sol b/accounts/safe7579/src/core/SetupDCUtil.sol index 359235f7..7cd143dd 100644 --- a/accounts/safe7579/src/core/SetupDCUtil.sol +++ b/accounts/safe7579/src/core/SetupDCUtil.sol @@ -3,7 +3,10 @@ pragma solidity ^0.8.25; import { Safe7579DCUtil } from "../utils/DCUtil.sol"; -contract Safe7579DCUtilSetup { +/** + * Deployes Safe7579DCUtil + */ +abstract contract Safe7579DCUtilSetup { address internal UTIL; constructor() { diff --git a/accounts/safe7579/src/interfaces/ISafe7579Init.sol b/accounts/safe7579/src/interfaces/ISafe7579Init.sol.bak similarity index 68% rename from accounts/safe7579/src/interfaces/ISafe7579Init.sol rename to accounts/safe7579/src/interfaces/ISafe7579Init.sol.bak index 2efa5eda..fb986f44 100644 --- a/accounts/safe7579/src/interfaces/ISafe7579Init.sol +++ b/accounts/safe7579/src/interfaces/ISafe7579Init.sol.bak @@ -2,19 +2,9 @@ pragma solidity ^0.8.23; import { IERC7484 } from "./IERC7484.sol"; +import "./DataTypes.sol"; -interface ISafe7579Init { - struct ModuleInit { - address module; - bytes initData; - } - - struct RegistryInit { - IERC7484 registry; - address[] attesters; - uint8 threshold; - } - +interface ISafe7579 { function initializeAccount( ModuleInit[] calldata validators, ModuleInit[] calldata executors, diff --git a/accounts/safe7579/test/ERC7579Compliance/Base.t.sol b/accounts/safe7579/test/ERC7579Compliance/Base.t.sol index 5392d2fe..dd3e4cd7 100644 --- a/accounts/safe7579/test/ERC7579Compliance/Base.t.sol +++ b/accounts/safe7579/test/ERC7579Compliance/Base.t.sol @@ -2,8 +2,9 @@ pragma solidity ^0.8.23; import "../Launchpad.t.sol"; -import "erc7579/interfaces/IERC7579Account.sol"; +import { IERC7579Account } from "erc7579/interfaces/IERC7579Account.sol"; import "erc7579/interfaces/IERC7579Module.sol"; +import { ModeLib } from "erc7579/lib/ModeLib.sol"; contract MockModule is IModule { bool initialized; diff --git a/accounts/safe7579/test/ERC7579Compliance/Executions4337.t.sol b/accounts/safe7579/test/ERC7579Compliance/Executions4337.t.sol index 1b5aa23c..c8a23482 100644 --- a/accounts/safe7579/test/ERC7579Compliance/Executions4337.t.sol +++ b/accounts/safe7579/test/ERC7579Compliance/Executions4337.t.sol @@ -2,7 +2,18 @@ pragma solidity ^0.8.0; import "./Base.t.sol"; -import "erc7579/lib/ModeLib.sol"; +import { + ExecType, + ModeCode, + ModeLib, + ModePayload, + MODE_DEFAULT, + EXECTYPE_DEFAULT, + EXECTYPE_TRY, + CALLTYPE_SINGLE, + CALLTYPE_BATCH, + CALLTYPE_DELEGATECALL +} from "erc7579/lib/ModeLib.sol"; contract Executions4337Test is BaseTest { function setUp() public virtual override { diff --git a/accounts/safe7579/test/ERC7579Compliance/ExecutionsModule.t.sol b/accounts/safe7579/test/ERC7579Compliance/ExecutionsModule.t.sol index 9e8e484e..a80ac274 100644 --- a/accounts/safe7579/test/ERC7579Compliance/ExecutionsModule.t.sol +++ b/accounts/safe7579/test/ERC7579Compliance/ExecutionsModule.t.sol @@ -2,7 +2,15 @@ pragma solidity ^0.8.0; import "./Base.t.sol"; -import "erc7579/lib/ModeLib.sol"; + +import { + ModeLib, + ModePayload, + MODE_DEFAULT, + EXECTYPE_TRY, + CALLTYPE_SINGLE, + CALLTYPE_BATCH +} from "erc7579/lib/ModeLib.sol"; contract ExecutionsModuleTest is BaseTest { function setUp() public virtual override { diff --git a/accounts/safe7579/test/ERC7579Compliance/Hooks.t.sol b/accounts/safe7579/test/ERC7579Compliance/Hooks.t.sol index f3e842b4..b602784f 100644 --- a/accounts/safe7579/test/ERC7579Compliance/Hooks.t.sol +++ b/accounts/safe7579/test/ERC7579Compliance/Hooks.t.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; import "./ModuleManagement.t.sol"; -// import "src/lib/ModeLib.sol"; +import { ModeLib } from "erc7579/lib/ModeLib.sol"; import "forge-std/console2.sol"; interface MockFn { @@ -67,7 +67,7 @@ contract HookTest is BaseTest, MockFn { _caller = address(entrypoint); vm.startPrank(address(entrypoint)); - bytes memory data = abi.encode(ModuleManager.HookType.GLOBAL, 0x0, _data); + bytes memory data = abi.encode(HookType.GLOBAL, 0x0, _data); account.installModule(4, SELF, data); bytes memory setValueOnTarget = abi.encodeCall(MockTarget.set, 1337); @@ -85,7 +85,7 @@ contract HookTest is BaseTest, MockFn { // installing this test as an executor account.installModule(2, SELF, _data); - bytes memory data = abi.encode(ModuleManager.HookType.GLOBAL, 0x0, _data); + bytes memory data = abi.encode(HookType.GLOBAL, 0x0, _data); account.installModule(4, SELF, data); vm.stopPrank(); @@ -105,9 +105,9 @@ contract HookTest is BaseTest, MockFn { // installing fallback account.installModule(3, SELF, abi.encode(this.fallbackFn.selector, CALLTYPE_SINGLE, _data)); - bytes memory data = abi.encode(ModuleManager.HookType.SIG, this.fallbackFn.selector, _data); + bytes memory data = abi.encode(HookType.SIG, this.fallbackFn.selector, _data); account.installModule(4, SELF, data); - data = abi.encode(ModuleManager.HookType.GLOBAL, 0x0, _data); + data = abi.encode(HookType.GLOBAL, 0x0, _data); account.installModule(4, SELF, data); vm.stopPrank(); @@ -123,10 +123,9 @@ contract HookTest is BaseTest, MockFn { _caller = address(entrypoint); vm.startPrank(address(entrypoint)); - bytes memory data = - abi.encode(ModuleManager.HookType.SIG, IERC7579Account.installModule.selector, _data); + bytes memory data = abi.encode(HookType.SIG, IERC7579Account.installModule.selector, _data); account.installModule(4, SELF, data); - data = abi.encode(ModuleManager.HookType.GLOBAL, 0x0, _data); + data = abi.encode(HookType.GLOBAL, 0x0, _data); account.installModule(4, SELF, data); // installing fallback diff --git a/accounts/safe7579/test/ERC7579Compliance/ModuleManagement.t.sol b/accounts/safe7579/test/ERC7579Compliance/ModuleManagement.t.sol index 36f3e4f8..30c5fd53 100644 --- a/accounts/safe7579/test/ERC7579Compliance/ModuleManagement.t.sol +++ b/accounts/safe7579/test/ERC7579Compliance/ModuleManagement.t.sol @@ -3,7 +3,9 @@ pragma solidity ^0.8.0; import "./Base.t.sol"; // import "src/lib/ModeLib.sol"; -import { CALLTYPE_SINGLE, ModuleManager } from "src/core/ModuleManager.sol"; +import { ModuleManager } from "src/core/ModuleManager.sol"; + +import { CALLTYPE_SINGLE, CALLTYPE_BATCH, CALLTYPE_DELEGATECALL } from "erc7579/lib/ModeLib.sol"; contract ModuleManagementTest is BaseTest { bytes _data; @@ -52,32 +54,20 @@ contract ModuleManagementTest is BaseTest { assertFalse(account.isModuleInstalled(3, SELF, abi.encode(selector))); } - function _installHook( - ModuleManager.HookType hookType, - bytes4 selector, - bytes memory initData - ) - public - { + function _installHook(HookType hookType, bytes4 selector, bytes memory initData) public { bytes memory data = abi.encode(hookType, selector, initData); account.installModule(4, SELF, data); assertTrue(account.isModuleInstalled(4, SELF, abi.encode(hookType, selector))); } - function _uninstallHook( - ModuleManager.HookType hookType, - bytes4 selector, - bytes memory initData - ) - public - { + function _uninstallHook(HookType hookType, bytes4 selector, bytes memory initData) public { bytes memory data = abi.encode(hookType, selector, initData); account.uninstallModule(4, SELF, data); assertFalse(account.isModuleInstalled(4, SELF, abi.encode(hookType, selector))); } function test_WhenInstallingHooks_SIG() external asEntryPoint { - ModuleManager.HookType hookType = ModuleManager.HookType.SIG; + HookType hookType = HookType.SIG; bytes4 selector = MockTarget.set.selector; _data = hex"4141414141414141"; @@ -86,7 +76,7 @@ contract ModuleManagementTest is BaseTest { } function test_WhenInstallingHooks_GLOBAL() external asEntryPoint { - ModuleManager.HookType hookType = ModuleManager.HookType.GLOBAL; + HookType hookType = HookType.GLOBAL; bytes4 selector = 0x00000000; _data = hex"4141414141414141"; diff --git a/accounts/safe7579/test/Launchpad.t.sol b/accounts/safe7579/test/Launchpad.t.sol index 7835bcda..9a19b11d 100644 --- a/accounts/safe7579/test/Launchpad.t.sol +++ b/accounts/safe7579/test/Launchpad.t.sol @@ -2,7 +2,10 @@ pragma solidity ^0.8.23; import "forge-std/Test.sol"; -import { SafeERC7579 } from "src/SafeERC7579.sol"; +import { Safe7579 } from "src/Safe7579.sol"; +import { ISafe7579 } from "src/ISafe7579.sol"; +import { IERC7484 } from "src/interfaces/IERC7484.sol"; +import "src/DataTypes.sol"; import { ModuleManager } from "src/core/ModuleManager.sol"; import { MockValidator } from "./mocks/MockValidator.sol"; import { MockRegistry } from "./mocks/MockRegistry.sol"; @@ -19,14 +22,13 @@ import { SafeProxyFactory } from "@safe-global/safe-contracts/contracts/proxies/SafeProxyFactory.sol"; import { LibClone } from "solady/utils/LibClone.sol"; -import "src/utils/Launchpad.sol"; -import "src/interfaces/ISafe7579Init.sol"; +import { Safe7579Launchpad } from "src/Safe7579Launchpad.sol"; import { Solarray } from "solarray/Solarray.sol"; import "./dependencies/EntryPoint.sol"; contract LaunchpadBase is Test { - SafeERC7579 safe7579; + Safe7579 safe7579; Safe singleton; Safe safe; SafeProxyFactory safeProxyFactory; @@ -58,7 +60,7 @@ contract LaunchpadBase is Test { singleton = new Safe(); safeProxyFactory = new SafeProxyFactory(); registry = new MockRegistry(); - safe7579 = new SafeERC7579(); + safe7579 = new Safe7579(); launchpad = new Safe7579Launchpad(address(entrypoint), registry); // Set up Modules @@ -68,14 +70,12 @@ contract LaunchpadBase is Test { bytes32 salt; - ISafe7579Init.ModuleInit[] memory validators = new ISafe7579Init.ModuleInit[](1); - validators[0] = - ISafe7579Init.ModuleInit({ module: address(defaultValidator), initData: bytes("") }); - ISafe7579Init.ModuleInit[] memory executors = new ISafe7579Init.ModuleInit[](1); - executors[0] = - ISafe7579Init.ModuleInit({ module: address(defaultExecutor), initData: bytes("") }); - ISafe7579Init.ModuleInit[] memory fallbacks = new ISafe7579Init.ModuleInit[](0); - ISafe7579Init.ModuleInit[] memory hooks = new ISafe7579Init.ModuleInit[](0); + ModuleInit[] memory validators = new ModuleInit[](1); + validators[0] = ModuleInit({ module: address(defaultValidator), initData: bytes("") }); + ModuleInit[] memory executors = new ModuleInit[](1); + executors[0] = ModuleInit({ module: address(defaultExecutor), initData: bytes("") }); + ModuleInit[] memory fallbacks = new ModuleInit[](0); + ModuleInit[] memory hooks = new ModuleInit[](0); Safe7579Launchpad.InitData memory initData = Safe7579Launchpad.InitData({ singleton: address(singleton), @@ -93,7 +93,7 @@ contract LaunchpadBase is Test { 2 ) ), - safe7579: address(safe7579), + safe7579: ISafe7579(safe7579), validators: validators, callData: abi.encodeCall( IERC7579Account.execute, diff --git a/accounts/safe7579/test/SafeERC7579.t.sol b/accounts/safe7579/test/SafeERC7579.t.sol index a95864ce..8fa2859b 100644 --- a/accounts/safe7579/test/SafeERC7579.t.sol +++ b/accounts/safe7579/test/SafeERC7579.t.sol @@ -1,10 +1,10 @@ // 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 "erc7579/lib/ModeLib.sol"; +// import "erc7579/lib/ExecutionLib.sol"; import "./Launchpad.t.sol"; +import { ModeLib } from "erc7579/lib/ModeLib.sol"; import "forge-std/console2.sol"; @@ -99,5 +99,4 @@ contract Safe7579Test is LaunchpadBase { assertEq(ret.length, 2); assertEq(abi.decode(ret[0], (uint256)), 1338); } - } diff --git a/packages/modulekit/src/accountFactory/safe7579/Safe7579Factory.sol b/packages/modulekit/src/accountFactory/safe7579/Safe7579Factory.sol index 1d2a157d..97354737 100644 --- a/packages/modulekit/src/accountFactory/safe7579/Safe7579Factory.sol +++ b/packages/modulekit/src/accountFactory/safe7579/Safe7579Factory.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.23; import "forge-std/Base.sol"; -import { SafeERC7579 } from "@rhinestone/safe7579/src/SafeERC7579.sol"; +import { Safe7579 } from "@rhinestone/safe7579/src/Safe7579.sol"; import "@safe-global/safe-contracts/contracts/Safe.sol"; import { LibClone } from "solady/src/utils/LibClone.sol"; @@ -11,14 +11,14 @@ import { BootstrapSafe } from "./BootstrapSafe.sol"; abstract contract Safe7579Factory is TestBase { // singletons - SafeERC7579 internal erc7579Mod; + Safe7579 internal erc7579Mod; Safe internal safeImpl; BootstrapSafe internal bootstrapSafe; constructor() { // Set up MSA and Factory - erc7579Mod = new SafeERC7579(); + erc7579Mod = new Safe7579(); safeImpl = new Safe(); bootstrapSafe = new BootstrapSafe(); } From 471e96bf31355c20a67d4bd65e5a96abc680047e Mon Sep 17 00:00:00 2001 From: zeroknots Date: Tue, 23 Apr 2024 09:20:29 +0700 Subject: [PATCH 61/64] cleaning up wip --- accounts/safe7579/notes.txt | 0 accounts/safe7579/src/ISafe7579.sol | 4 ++-- accounts/safe7579/src/Safe7579.sol | 2 +- accounts/safe7579/src/Safe7579Launchpad.sol | 5 ++--- accounts/safe7579/src/core/AccessControl.sol | 2 +- .../safe7579/src/core/ExecutionHelper.sol | 2 +- accounts/safe7579/src/core/Initializer.sol | 2 +- accounts/safe7579/src/core/ModuleManager.sol | 6 +++--- .../safe7579/src/core/RegistryAdapter.sol | 2 +- accounts/safe7579/src/core/SetupDCUtil.sol | 2 +- accounts/safe7579/src/interfaces/IERC1271.sol | 2 +- .../src/interfaces/IERC7579Account.sol | 2 +- .../src/interfaces/IERC7579Module.sol | 2 +- .../src/interfaces/ISafe7579Init.sol.bak | 19 ------------------- accounts/safe7579/src/lib/ExecutionLib.sol | 1 + accounts/safe7579/src/lib/ModeLib.sol | 1 + 16 files changed, 18 insertions(+), 36 deletions(-) delete mode 100644 accounts/safe7579/notes.txt delete mode 100644 accounts/safe7579/src/interfaces/ISafe7579Init.sol.bak diff --git a/accounts/safe7579/notes.txt b/accounts/safe7579/notes.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/accounts/safe7579/src/ISafe7579.sol b/accounts/safe7579/src/ISafe7579.sol index 55f3f6cc..d5830355 100644 --- a/accounts/safe7579/src/ISafe7579.sol +++ b/accounts/safe7579/src/ISafe7579.sol @@ -1,5 +1,5 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.25; +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; import "./DataTypes.sol"; import { IERC7579Account } from "./interfaces//IERC7579Account.sol"; diff --git a/accounts/safe7579/src/Safe7579.sol b/accounts/safe7579/src/Safe7579.sol index 68cdb73f..7cad04a7 100644 --- a/accounts/safe7579/src/Safe7579.sol +++ b/accounts/safe7579/src/Safe7579.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.25; +pragma solidity ^0.8.20; import { IERC7579Account, Execution } from "./interfaces/IERC7579Account.sol"; import { diff --git a/accounts/safe7579/src/Safe7579Launchpad.sol b/accounts/safe7579/src/Safe7579Launchpad.sol index 781c48d3..cbaa8f77 100644 --- a/accounts/safe7579/src/Safe7579Launchpad.sol +++ b/accounts/safe7579/src/Safe7579Launchpad.sol @@ -1,12 +1,11 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.22; +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.20; import { IAccount, PackedUserOperation } from "account-abstraction/interfaces/IAccount.sol"; import { ISafe } from "./interfaces/ISafe.sol"; import { ISafe7579 } from "./ISafe7579.sol"; import { IERC7484 } from "./interfaces/IERC7484.sol"; import "./DataTypes.sol"; -import { Safe7579 } from "./Safe7579.sol"; import { IValidator } from "erc7579/interfaces/IERC7579Module.sol"; diff --git a/accounts/safe7579/src/core/AccessControl.sol b/accounts/safe7579/src/core/AccessControl.sol index d868d3db..0e972b30 100644 --- a/accounts/safe7579/src/core/AccessControl.sol +++ b/accounts/safe7579/src/core/AccessControl.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.23; +pragma solidity ^0.8.20; import { HandlerContext } from "@safe-global/safe-contracts/contracts/handler/HandlerContext.sol"; import { AccountBase } from "erc7579/core/AccountBase.sol"; diff --git a/accounts/safe7579/src/core/ExecutionHelper.sol b/accounts/safe7579/src/core/ExecutionHelper.sol index 7dc60b7d..00ca29fc 100644 --- a/accounts/safe7579/src/core/ExecutionHelper.sol +++ b/accounts/safe7579/src/core/ExecutionHelper.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.23; +pragma solidity ^0.8.20; import { Safe7579DCUtil, Safe7579DCUtilSetup } from "./SetupDCUtil.sol"; import { BatchedExecUtil } from "../utils/DCUtil.sol"; diff --git a/accounts/safe7579/src/core/Initializer.sol b/accounts/safe7579/src/core/Initializer.sol index 66e15558..e59a4de8 100644 --- a/accounts/safe7579/src/core/Initializer.sol +++ b/accounts/safe7579/src/core/Initializer.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.23; +pragma solidity ^0.8.20; import { ISafe7579 } from "../ISafe7579.sol"; import "../DataTypes.sol"; diff --git a/accounts/safe7579/src/core/ModuleManager.sol b/accounts/safe7579/src/core/ModuleManager.sol index 210c39ff..5bebe25b 100644 --- a/accounts/safe7579/src/core/ModuleManager.sol +++ b/accounts/safe7579/src/core/ModuleManager.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.23; +pragma solidity ^0.8.20; import { SentinelListLib } from "sentinellist/SentinelList.sol"; import { SentinelList4337Lib } from "sentinellist/SentinelList4337.sol"; @@ -205,7 +205,7 @@ abstract contract ModuleManager is ISafe7579, AccessControl, Receiver, RegistryA } function _uninstallFallbackHandler( - address handler, + address, /*handler*/ bytes calldata context ) internal @@ -400,7 +400,7 @@ abstract contract ModuleManager is ISafe7579, AccessControl, Receiver, RegistryA } function _uninstallHook( - address hook, + address, /*hook*/ bytes calldata data ) internal diff --git a/accounts/safe7579/src/core/RegistryAdapter.sol b/accounts/safe7579/src/core/RegistryAdapter.sol index 77ac4146..3b399fe6 100644 --- a/accounts/safe7579/src/core/RegistryAdapter.sol +++ b/accounts/safe7579/src/core/RegistryAdapter.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.23; +pragma solidity ^0.8.20; import { IERC7484 } from "../interfaces/IERC7484.sol"; import { ExecutionHelper } from "./ExecutionHelper.sol"; diff --git a/accounts/safe7579/src/core/SetupDCUtil.sol b/accounts/safe7579/src/core/SetupDCUtil.sol index 7cd143dd..02e3f8e7 100644 --- a/accounts/safe7579/src/core/SetupDCUtil.sol +++ b/accounts/safe7579/src/core/SetupDCUtil.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.25; +pragma solidity ^0.8.20; import { Safe7579DCUtil } from "../utils/DCUtil.sol"; diff --git a/accounts/safe7579/src/interfaces/IERC1271.sol b/accounts/safe7579/src/interfaces/IERC1271.sol index 5aff1322..5d870ac6 100644 --- a/accounts/safe7579/src/interfaces/IERC1271.sol +++ b/accounts/safe7579/src/interfaces/IERC1271.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: LGPL-3.0-only -pragma solidity ^0.8.23; +pragma solidity ^0.8.20; interface IERC1271 { /** diff --git a/accounts/safe7579/src/interfaces/IERC7579Account.sol b/accounts/safe7579/src/interfaces/IERC7579Account.sol index 7904d829..262ecad3 100644 --- a/accounts/safe7579/src/interfaces/IERC7579Account.sol +++ b/accounts/safe7579/src/interfaces/IERC7579Account.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.21; +pragma solidity ^0.8.20; import { CallType, ExecType, ModeCode } from "../lib/ModeLib.sol"; diff --git a/accounts/safe7579/src/interfaces/IERC7579Module.sol b/accounts/safe7579/src/interfaces/IERC7579Module.sol index a8217024..8479856a 100644 --- a/accounts/safe7579/src/interfaces/IERC7579Module.sol +++ b/accounts/safe7579/src/interfaces/IERC7579Module.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.8.21; +pragma solidity ^0.8.20; import { PackedUserOperation } from "account-abstraction/interfaces/PackedUserOperation.sol"; diff --git a/accounts/safe7579/src/interfaces/ISafe7579Init.sol.bak b/accounts/safe7579/src/interfaces/ISafe7579Init.sol.bak deleted file mode 100644 index fb986f44..00000000 --- a/accounts/safe7579/src/interfaces/ISafe7579Init.sol.bak +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.23; - -import { IERC7484 } from "./IERC7484.sol"; -import "./DataTypes.sol"; - -interface ISafe7579 { - function initializeAccount( - ModuleInit[] calldata validators, - ModuleInit[] calldata executors, - ModuleInit[] calldata fallbacks, - ModuleInit[] calldata hooks, - RegistryInit calldata registryInit - ) - external - payable; - - function launchpadValidators(ModuleInit[] calldata validators) external payable; -} diff --git a/accounts/safe7579/src/lib/ExecutionLib.sol b/accounts/safe7579/src/lib/ExecutionLib.sol index 3d509eb3..f0c4e59c 100644 --- a/accounts/safe7579/src/lib/ExecutionLib.sol +++ b/accounts/safe7579/src/lib/ExecutionLib.sol @@ -6,6 +6,7 @@ import { Execution } from "../interfaces/IERC7579Account.sol"; /** * Helper Library for decoding Execution calldata * malloc for memory allocation is bad for gas. use this assembly instead + * @author rhinestone | zeroknots.eth, Konrad Kopp (@kopy-kat) */ library ExecutionLib { function decodeBatch(bytes calldata callData) diff --git a/accounts/safe7579/src/lib/ModeLib.sol b/accounts/safe7579/src/lib/ModeLib.sol index df594a6d..957e1246 100644 --- a/accounts/safe7579/src/lib/ModeLib.sol +++ b/accounts/safe7579/src/lib/ModeLib.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.23; /** * @title ModeLib + * @author rhinestone | zeroknots.eth, Konrad Kopp (@kopy-kat) * To allow smart accounts to be very simple, but allow for more complex execution, A custom mode * encoding is used. * Function Signature of execute function: From e4b91f8ec9a11150e2a7c75d879745c72a4bca96 Mon Sep 17 00:00:00 2001 From: kopy-kat Date: Wed, 1 May 2024 19:29:30 +0100 Subject: [PATCH 62/64] feat: add userOp constructor --- .../interfaces/IUserOperationConstructor.sol | 40 ++++++++++ .../Safe7579UserOperationConstructor.sol | 73 +++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 accounts/safe7579/src/interfaces/IUserOperationConstructor.sol create mode 100644 accounts/safe7579/src/utils/Safe7579UserOperationConstructor.sol diff --git a/accounts/safe7579/src/interfaces/IUserOperationConstructor.sol b/accounts/safe7579/src/interfaces/IUserOperationConstructor.sol new file mode 100644 index 00000000..c44ad1f8 --- /dev/null +++ b/accounts/safe7579/src/interfaces/IUserOperationConstructor.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import { PackedUserOperation } from + "@ERC4337/account-abstraction/contracts/core/UserOperationLib.sol"; +import { Execution } from "./IERC7579Account.sol"; + +interface IUserOpConstructor { +// function getNonceWithContext( +// address smartAccount, +// bytes calldata permissionsContext +// ) +// external +// view +// returns (uint256); + +// /** +// * @dev Returns the calldata for the user operation, +// * given the permissions context and the executions. +// * @param executions are just standard (destination, value, callData) sets +// * as the dApp that calls this method is unaware of SA's execution interfaces +// * Execution from 7579 is used here as it is exactly this basic structure. +// */ +// function getCallDataWithContext( +// address smartAccount, +// Execution[] calldata executions, +// bytes calldata permissionsContext +// ) +// external +// view +// returns (bytes memory); + +// function getSignatureWithContext( +// address smartAccount, +// PackedUserOperation calldata userOp, +// bytes calldata permissionsContext +// ) +// external +// returns (bytes memory signature); +} diff --git a/accounts/safe7579/src/utils/Safe7579UserOperationConstructor.sol b/accounts/safe7579/src/utils/Safe7579UserOperationConstructor.sol new file mode 100644 index 00000000..f2d84102 --- /dev/null +++ b/accounts/safe7579/src/utils/Safe7579UserOperationConstructor.sol @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import { + IUserOpConstructor, PackedUserOperation +} from "src/interfaces/IUserOperationConstructor.sol"; +import { ModeLib } from "erc7579/lib/ModeLib.sol"; +import { Execution, ExecutionLib } from "erc7579/lib/ExecutionLib.sol"; +import { IEntryPoint } from "@ERC4337/account-abstraction/contracts/interfaces/IEntryPoint.sol"; +import { IERC7579Account } from "erc7579/interfaces/IERC7579Account.sol"; + +contract Safe7579UserOpConstructor is IUserOpConstructor { + IEntryPoint public immutable entryPoint; + + constructor(address _entryPoint) { + entryPoint = IEntryPoint(_entryPoint); + } + + function getNonceWithContext( + address smartAccount, + bytes calldata permissionsContext + ) + external + view + returns (uint256) + { + address validator = address(bytes20(permissionsContext[0:20])); + uint192 key = uint192(bytes24(bytes20(address(validator)))); + return entryPoint.getNonce(address(smartAccount), key); + } + + function getCallDataWithContext( + address smartAccount, + Execution[] calldata executions, + bytes calldata permissionsContext + ) + external + view + returns (bytes memory callDataWithContext) + { + if (executions.length == 0) { + revert("No executions provided"); + } + if (executions.length == 1) { + callDataWithContext = abi.encodeCall( + IERC7579Account.execute, + ( + ModeLib.encodeSimpleSingle(), + ExecutionLib.encodeSingle( + executions[0].target, executions[0].value, executions[0].callData + ) + ) + ); + } else { + callDataWithContext = abi.encodeCall( + IERC7579Account.execute, + (ModeLib.encodeSimpleBatch(), ExecutionLib.encodeBatch(executions)) + ); + } + // TODO: add delegatecall, tryExecute and other execution modes handling + } + + function getSignatureWithContext( + address smartAccount, + PackedUserOperation calldata userOp, + bytes calldata permissionsContext + ) + external + returns (bytes memory signature) + { + signature = userOp.signature; + } +} From 7ac113c9a5b758fab5993ea800d1170cc6c4c14d Mon Sep 17 00:00:00 2001 From: kopy-kat Date: Wed, 1 May 2024 22:32:31 +0100 Subject: [PATCH 63/64] feat: update userop builder to latest interface --- .../src/interfaces/IUserOperationBuilder.sol | 85 +++++++++++++++++++ .../interfaces/IUserOperationConstructor.sol | 40 --------- ...r.sol => Safe7579UserOperationBuilder.sol} | 55 +++++++----- 3 files changed, 121 insertions(+), 59 deletions(-) create mode 100644 accounts/safe7579/src/interfaces/IUserOperationBuilder.sol delete mode 100644 accounts/safe7579/src/interfaces/IUserOperationConstructor.sol rename accounts/safe7579/src/utils/{Safe7579UserOperationConstructor.sol => Safe7579UserOperationBuilder.sol} (55%) diff --git a/accounts/safe7579/src/interfaces/IUserOperationBuilder.sol b/accounts/safe7579/src/interfaces/IUserOperationBuilder.sol new file mode 100644 index 00000000..3645c83a --- /dev/null +++ b/accounts/safe7579/src/interfaces/IUserOperationBuilder.sol @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import { PackedUserOperation } from + "@ERC4337/account-abstraction/contracts/core/UserOperationLib.sol"; +import { Execution } from "./IERC7579Account.sol"; + +interface IUserOperationBuilder { +// /** +// * @dev Returns the ERC-4337 EntryPoint that the account implementation +// * supports. +// */ +// function entryPoint() external view returns (address); + +// /** +// * @dev Returns the nonce to use for the UserOp, given the context. +// * @param smartAccount is the address of the UserOp sender. +// * @param context is the data required for the UserOp builder to +// * properly compute the requested field for the UserOp. +// */ +// function getNonce( +// address smartAccount, +// bytes calldata context +// ) +// external +// view +// returns (uint256); + +// /** +// * @dev Returns the calldata for the UserOp, given the context and +// * the executions. +// * @param smartAccount is the address of the UserOp sender. +// * @param executions are (destination, value, callData) tuples that +// * the UserOp wants to execute. It's an array so the UserOp can +// * batch executions. +// * @param context is the data required for the UserOp builder to +// * properly compute the requested field for the UserOp. +// */ +// function getCallData( +// address smartAccount, +// Execution[] calldata executions, +// bytes calldata context +// ) +// external +// view +// returns (bytes memory); + +// /** +// * @dev Returns the dummy signature for the UserOp, given the context +// * and the executions. +// * @param smartAccount is the address of the UserOp sender. +// * @param executions are (destination, value, callData) tuples that +// * the UserOp wants to execute. It's an array so the UserOp can +// * batch executions. +// * @param context is the data required for the UserOp builder to +// * properly compute the requested field for the UserOp. +// */ +// function getDummySignature( +// address smartAccount, +// Execution[] calldata executions, +// bytes calldata context +// ) +// external +// view +// returns (bytes memory signature); + +// /** +// * @dev Returns a correctly encoded signature, given a UserOp that +// * has been correctly filled out except for the signature field. +// * @param smartAccount is the address of the UserOp sender. +// * @param userOperation is the UserOp. Every field of the UserOp should +// * be valid except for the signature field. The "PackedUserOperation" +// * struct is as defined in ERC-4337. +// * @param context is the data required for the UserOp builder to +// * properly compute the requested field for the UserOp. +// */ +// function getSignature( +// address smartAccount, +// PackedUserOperation calldata userOperation, +// bytes calldata context +// ) +// external +// view +// returns (bytes memory signature); +} diff --git a/accounts/safe7579/src/interfaces/IUserOperationConstructor.sol b/accounts/safe7579/src/interfaces/IUserOperationConstructor.sol deleted file mode 100644 index c44ad1f8..00000000 --- a/accounts/safe7579/src/interfaces/IUserOperationConstructor.sol +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.24; - -import { PackedUserOperation } from - "@ERC4337/account-abstraction/contracts/core/UserOperationLib.sol"; -import { Execution } from "./IERC7579Account.sol"; - -interface IUserOpConstructor { -// function getNonceWithContext( -// address smartAccount, -// bytes calldata permissionsContext -// ) -// external -// view -// returns (uint256); - -// /** -// * @dev Returns the calldata for the user operation, -// * given the permissions context and the executions. -// * @param executions are just standard (destination, value, callData) sets -// * as the dApp that calls this method is unaware of SA's execution interfaces -// * Execution from 7579 is used here as it is exactly this basic structure. -// */ -// function getCallDataWithContext( -// address smartAccount, -// Execution[] calldata executions, -// bytes calldata permissionsContext -// ) -// external -// view -// returns (bytes memory); - -// function getSignatureWithContext( -// address smartAccount, -// PackedUserOperation calldata userOp, -// bytes calldata permissionsContext -// ) -// external -// returns (bytes memory signature); -} diff --git a/accounts/safe7579/src/utils/Safe7579UserOperationConstructor.sol b/accounts/safe7579/src/utils/Safe7579UserOperationBuilder.sol similarity index 55% rename from accounts/safe7579/src/utils/Safe7579UserOperationConstructor.sol rename to accounts/safe7579/src/utils/Safe7579UserOperationBuilder.sol index f2d84102..4e782515 100644 --- a/accounts/safe7579/src/utils/Safe7579UserOperationConstructor.sol +++ b/accounts/safe7579/src/utils/Safe7579UserOperationBuilder.sol @@ -2,47 +2,51 @@ pragma solidity ^0.8.24; import { - IUserOpConstructor, PackedUserOperation -} from "src/interfaces/IUserOperationConstructor.sol"; + IUserOperationBuilder, PackedUserOperation +} from "src/interfaces/IUserOperationBuilder.sol"; import { ModeLib } from "erc7579/lib/ModeLib.sol"; import { Execution, ExecutionLib } from "erc7579/lib/ExecutionLib.sol"; import { IEntryPoint } from "@ERC4337/account-abstraction/contracts/interfaces/IEntryPoint.sol"; import { IERC7579Account } from "erc7579/interfaces/IERC7579Account.sol"; -contract Safe7579UserOpConstructor is IUserOpConstructor { - IEntryPoint public immutable entryPoint; +contract Safe7579UserOperationBuilder is IUserOperationBuilder { + IEntryPoint internal immutable _entryPoint; - constructor(address _entryPoint) { - entryPoint = IEntryPoint(_entryPoint); + constructor(address _entryPointAddress) { + _entryPoint = IEntryPoint(_entryPointAddress); } - function getNonceWithContext( + function entryPoint() external view returns (address) { + return address(_entryPoint); + } + + function getNonce( address smartAccount, - bytes calldata permissionsContext + bytes calldata context ) external view returns (uint256) { - address validator = address(bytes20(permissionsContext[0:20])); + address validator = address(bytes20(context[0:20])); uint192 key = uint192(bytes24(bytes20(address(validator)))); - return entryPoint.getNonce(address(smartAccount), key); + return _entryPoint.getNonce(address(smartAccount), key); } - function getCallDataWithContext( + function getCallData( address smartAccount, Execution[] calldata executions, - bytes calldata permissionsContext + bytes calldata context ) external view - returns (bytes memory callDataWithContext) + returns (bytes memory) { if (executions.length == 0) { revert("No executions provided"); } if (executions.length == 1) { - callDataWithContext = abi.encodeCall( + return abi.encodeCall( IERC7579Account.execute, ( ModeLib.encodeSimpleSingle(), @@ -52,7 +56,7 @@ contract Safe7579UserOpConstructor is IUserOpConstructor { ) ); } else { - callDataWithContext = abi.encodeCall( + return abi.encodeCall( IERC7579Account.execute, (ModeLib.encodeSimpleBatch(), ExecutionLib.encodeBatch(executions)) ); @@ -60,14 +64,27 @@ contract Safe7579UserOpConstructor is IUserOpConstructor { // TODO: add delegatecall, tryExecute and other execution modes handling } - function getSignatureWithContext( + function getDummySignature( + address smartAccount, + Execution[] calldata executions, + bytes calldata context + ) + external + view + returns (bytes memory signature) + { + return context; + } + + function getSignature( address smartAccount, - PackedUserOperation calldata userOp, - bytes calldata permissionsContext + PackedUserOperation calldata userOperation, + bytes calldata context ) external + view returns (bytes memory signature) { - signature = userOp.signature; + signature = userOperation.signature; } } From 5676f3f6b3af26423e0f6789676953b835001b4e Mon Sep 17 00:00:00 2001 From: kopy-kat Date: Thu, 9 May 2024 18:28:10 +0100 Subject: [PATCH 64/64] chore: add deployments --- .../Deploy.s.sol/11155111/run-1715275639.json | 91 +++++++++++++++++++ .../Deploy.s.sol/11155111/run-latest.json | 91 +++++++++++++++++++ accounts/safe7579/script/Deploy.s.sol | 27 ++++++ 3 files changed, 209 insertions(+) create mode 100644 accounts/safe7579/broadcast/Deploy.s.sol/11155111/run-1715275639.json create mode 100644 accounts/safe7579/broadcast/Deploy.s.sol/11155111/run-latest.json create mode 100644 accounts/safe7579/script/Deploy.s.sol diff --git a/accounts/safe7579/broadcast/Deploy.s.sol/11155111/run-1715275639.json b/accounts/safe7579/broadcast/Deploy.s.sol/11155111/run-1715275639.json new file mode 100644 index 00000000..a78370b5 --- /dev/null +++ b/accounts/safe7579/broadcast/Deploy.s.sol/11155111/run-1715275639.json @@ -0,0 +1,91 @@ +{ + "transactions": [ + { + "hash": "0xadee694915caabe82504b2d1afe5144199b8e1dca581228940b9fdf8966bdd53", + "transactionType": "CREATE2", + "contractName": "Safe7579", + "contractAddress": "0xbaca6f74a5549368568f387fd989c279f940f1a5", + "function": null, + "arguments": null, + "transaction": { + "from": "0x8749313f626b100b822d573c71dfffdaca383032", + "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", + "gas": "0x64306b", + "value": "0x0", + "input": "0x00000000000000000000000000000000000000000000000000000000000000006080604052348015600f57600080fd5b50604051601a90605a565b604051809103906000f0801580156035573d6000803e3d6000fd5b50600080546001600160a01b0319166001600160a01b03929092169190911790556067565b6109d880614a9483390190565b614a1e806100766000396000f3fe6080604052600436106101235760003560e01c8063b0d691fe116100a0578063e9ae5c5311610064578063e9ae5c531461040f578063ea5f61d014610422578063eab77e1714610442578063f2dc691d14610462578063f698da25146104825761012a565b8063b0d691fe14610340578063b875d5d814610363578063d03c7914146103af578063d691c964146103cf578063d828435d146103ef5761012a565b80636a5e1515116100e75780636a5e1515146102b757806385571368146102ca5780639517e29f146102f85780639cfd7cff1461030b578063a71763a81461032d5761012a565b80630a664dba146101d4578063112d3a7d146102185780631626ba7e1461024857806319822f7c14610281578063540fb4f9146102a25761012a565b3661012a57005b600036606060003560e01c63bc197c81811463f23a6e6182141763150b7a028214171561015b57806020526020603cf35b5033600090815260056020908152604080832054600683528184206001600160e01b031985351680865293529083205491926001600160a01b039182169290911690806101a88484610497565b915091506101b68888610555565b95506101c484848484610669565b5050505050915050805190602001f35b3480156101e057600080fd5b50336000908152600560205260409020546001600160a01b03165b6040516001600160a01b0390911681526020015b60405180910390f35b34801561022457600080fd5b506102386102333660046139e3565b6106ec565b604051901515815260200161020f565b34801561025457600080fd5b50610268610263366004613a3e565b610749565b6040516001600160e01b0319909116815260200161020f565b61029461028f366004613a89565b6109de565b60405190815260200161020f565b6102b56102b0366004613b38565b610af2565b005b6102b56102c5366004613c1e565b610b3f565b3480156102d657600080fd5b506102ea6102e5366004613c5f565b610ba0565b60405161020f929190613c8b565b6102b56103063660046139e3565b610bbc565b34801561031757600080fd5b50610320610d61565b60405161020f9190613d3e565b6102b561033b3660046139e3565b610df3565b34801561034c57600080fd5b506f71727de22e5e9d8baf0edac6f37da0326101fb565b34801561036f57600080fd5b506101fb61037e366004613d67565b3360009081526006602090815260408083206001600160e01b0319909416835292905220546001600160a01b031690565b3480156103bb57600080fd5b506102386103ca366004613d84565b610f5f565b6103e26103dd366004613a3e565b611007565b60405161020f9190613d9d565b3480156103fb57600080fd5b5061029461040a366004613e01565b6110d3565b6102b561041d366004613a3e565b611173565b34801561042e57600080fd5b506102ea61043d366004613c5f565b611518565b34801561044e57600080fd5b506102b561045d366004613e4b565b611542565b34801561046e57600080fd5b5061023861047d366004613d84565b6115b1565b34801561048e57600080fd5b50610294611600565b6060806001600160a01b03841615610517576104fe338560006104b8611659565b346000366040516024016104cf9493929190613eda565b60408051601f198184030181529190526020810180516001600160e01b031663d68f602560e01b179052611665565b9150818060200190518101906105149190613fce565b91505b6001600160a01b0383161561054e57610535338460006104b8611659565b90508080602001905181019061054b9190613fce565b90505b9250929050565b3360009081526004602090815260408083206001600160e01b0319843516845290915290208054606091906001600160a01b03811690600160a01b900460f81b816105c657604051632464e76d60e11b81526001600160e01b03196000351660048201526024015b60405180910390fd5b6105d481607f60f91b61170e565b156106185761060e338388886105e8611659565b6040516020016105fa93929190614002565b604051602081830303815290604052611720565b9350505050610663565b61062381600061170e565b1561065f5761060e338360008989610639611659565b60405160200161064b93929190614002565b604051602081830303815290604052611665565b5050505b92915050565b6001600160a01b038416156106bf576106bf33856000856040516024016106909190613d3e565b60408051601f198184030181529190526020810180516001600160e01b0316630b9dfbed60e11b1790526117e0565b6001600160a01b038316156106e6576106e633846000846040516024016106909190613d3e565b50505050565b600060018503610706576106ff8461187f565b9050610741565b60028503610717576106ff8461188d565b6003850361072a576106ff8484846118a6565b6004850361073d576106ff8484846118f3565b5060005b949350505050565b600033821580156107c15750604051635ae6bd3760e01b8152600481018690526001600160a01b03821690635ae6bd3790602401602060405180830381865afa15801561079a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107be9190614028565b15155b156107d65750630b135d3f60e11b90506109d7565b60006107e56014828688614041565b6107ee9161406b565b60601c905080158061080657506108048161187f565b155b1561095c5760006108d1836001600160a01b031663f698da256040518163ffffffff1660e01b8152600401602060405180830381865afa15801561084e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108729190614028565b60408051602081018b90527f60b3cbf8b4a223d68d641b3b6ddf9a298e7f33710cf3d3a9d1146b5a6150fbca910160408051601f198184030181528282528051602091820120908301520160405160208183030381529060405261192e565b805160208201209091506001600160a01b03841663934f3a1182846108f98a6014818e614041565b6040518563ffffffff1660e01b815260040161091894939291906140a0565b60006040518083038186803b15801561093057600080fd5b505afa158015610944573d6000803e3d6000fd5b50630b135d3f60e11b97506109d79650505050505050565b60006109bb338361096b611659565b8a6109798a6014818e614041565b60405160240161098c9493929190613eda565b60408051601f198184030181529190526020810180516001600160e01b0316637aa8f17760e11b179052611720565b9050808060200190518101906109d191906140d7565b93505050505b9392505050565b60006f71727de22e5e9d8baf0edac6f37da0326109f9611659565b6001600160a01b031614610a2057604051635629665f60e11b815260040160405180910390fd5b6020840135606081901c90811580610a3e5750610a3c8261187f565b155b15610a5357610a4c866119a8565b9250610ab8565b6000610a9e338460008a8a604051602401610a6f929190614139565b60408051601f198184030181529190526020810180516001600160e01b0316639700320360e01b179052611665565b905080806020019051810190610ab49190614028565b9350505b8315610ae957610ae9336f71727de22e5e9d8baf0edac6f37da03286604051806020016040528060008152506117e0565b50509392505050565b610b24610b026020830183614238565b610b0f6020840184614255565b610b1f606086016040870161429e565b611a4e565b610b348989898989898989611afc565b505050505050505050565b610b4a600233611d3f565b8060005b818110156106e65736848483818110610b6957610b696142b9565b9050602002810190610b7b91906142cf565b9050610b9733610b8e6020840184614238565b60029190611dba565b50600101610b4e565b60606000610bb16002338686611eaf565b915091509250929050565b3360009081526005602090815260408083205460068352818420639517e29f60e01b80865293529083205491926001600160a01b03918216929091169080610c048484610497565b91509150610c1f6f71727de22e5e9d8baf0edac6f37da03290565b6001600160a01b0316610c30611659565b6001600160a01b03161480610c5d5750610c48611659565b6001600160a01b0316336001600160a01b0316145b610c7a57604051635629665f60e11b815260040160405180910390fd5b606060018a03610c9657610c8f898989612065565b9050610cfb565b60028a03610ca957610c8f8989896120c1565b60038a03610cbc57610c8f89898961212b565b60048a03610ccf57610c8f89898961226c565b89610cdf57610c8f8989896123eb565b60405163041c38b360e41b8152600481018b90526024016105bd565b600054604051610d549133916001600160a01b0390911690610d25908e908e9087906024016142ef565b60408051601f198184030181529190526020810180516001600160e01b0316639517e29f60e01b179052612573565b50610b3484848484610669565b60606000336001600160a01b031663ffa1ad746040518163ffffffff1660e01b8152600401600060405180830381865afa158015610da3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610dcb9190810190614319565b905080604051602001610dde9190614361565b60405160208183030381529060405291505090565b33600090815260056020908152604080832054600683528184206314e2ec7560e31b80865293529083205491926001600160a01b03918216929091169080610e3b8484610497565b91509150610e566f71727de22e5e9d8baf0edac6f37da03290565b6001600160a01b0316610e67611659565b6001600160a01b03161480610e945750610e7f611659565b6001600160a01b0316336001600160a01b0316145b610eb157604051635629665f60e11b815260040160405180910390fd5b606060018a03610ecd57610ec689898961260c565b9050610f06565b60028a03610ee057610ec6898989612635565b60038a03610ef357610ec6898989612662565b60048a03610cdf57610ec68989896126b0565b600054604051610d549133916001600160a01b0390911690610f30908e908e9087906024016142ef565b60408051601f198184030181529190526020810180516001600160e01b0316637827252560e01b179052612768565b600081600881901b610f7582600160f81b61170e565b15610f835760019250610fc6565b610f8e82600061170e565b15610f9c5760019250610fc6565b610fae826001600160f81b031961170e565b15610fbc5760019250610fc6565b5060009392505050565b828015610fd95750610fd981600061170e565b15610fe5575050919050565b828015610ffb5750610ffb81600160f81b61170e565b15610fbc575050919050565b6060611019611014611659565b61188d565b61104a57611025611659565b604051635c93ff2f60e11b81526001600160a01b0390911660048201526024016105bd565b33600090815260056020908152604080832054600683528184206335a4725960e21b80865293529083205491926001600160a01b039182169290911690806110928484610497565b915091503360026110a3828261281e565b8a600881901b6110b581838e8e6128a9565b9950505050506110c784848484610669565b50505050509392505050565b6000602082901b640100000000600160c01b03166f71727de22e5e9d8baf0edac6f37da032604051631aab3f0d60e11b81526001600160a01b0386811660048301526001600160c01b038416602483015291909116906335567e1a90604401602060405180830381865afa15801561114f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107419190614028565b336000908152600560209081526040808320546006835281842063e9ae5c5360e01b80865293529083205491926001600160a01b039182169290911690806111bb8484610497565b915091506111d66f71727de22e5e9d8baf0edac6f37da03290565b6001600160a01b03166111e7611659565b6001600160a01b0316148061121457506111ff611659565b6001600160a01b0316336001600160a01b0316145b61123157604051635629665f60e11b815260040160405180910390fd5b87600881901b3361124382600061170e565b156113a65761125683600160f81b61170e565b156112775789358a01602081019035611270838383612c65565b50506114ff565b61128283600061170e565b156112ea576000803660006112978e8e612cbc565b93509350935093506112e185858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506117e092505050565b505050506114ff565b6112fc836001600160f81b031961170e565b156113815760006113106014828c8e614041565b6113199161406b565b60601c90503660008c8c601490809261133493929190614041565b91509150611379848484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061257392505050565b5050506114ff565b604051632e5bf3f960e21b81526001600160f81b0319841660048201526024016105bd565b6113b482600160f81b61170e565b156114da576113c783600160f81b61170e565b156113e15789358a01602081019035611270838383612d0d565b6113ec83600061170e565b1561144b576000803660006114018e8e612cbc565b93509350935093506112e185858585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612d6492505050565b61145d836001600160f81b031961170e565b156113815760006114716014828c8e614041565b61147a9161406b565b60601c90503660008c8c601490809261149593929190614041565b91509150611379848484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061276892505050565b6040516308c3ee0360e11b81526001600160f81b0319831660048201526024016105bd565b50505061150e84848484610669565b5050505050505050565b33600090815260036020526040812060609190611536818686612e1a565b92509250509250929050565b6f71727de22e5e9d8baf0edac6f37da03261155b611659565b6001600160a01b031614806115885750611573611659565b6001600160a01b0316336001600160a01b0316145b6115a557604051635629665f60e11b815260040160405180910390fd5b6106e684848484611a4e565b6000600182036115c357506001919050565b600282036115d357506001919050565b600382036115e357506001919050565b600482036115f357506001919050565b506000919050565b919050565b604080517f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a794692186020820152469181019190915230606082015260009060800160405160208183030381529060405280519060200120905090565b60131936013560601c90565b60606000856001600160a01b0316635229073f86868660006040518563ffffffff1660e01b815260040161169c94939291906143a7565b6000604051808303816000875af11580156116bb573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526116e391908101906143f2565b925090508061170557604051632b3f6d1160e21b815260040160405180910390fd5b50949350505050565b6001600160f81b031990811691161490565b60606000838360405160240161173792919061443f565b60408051601f198184030181529181526020820180516001600160e01b0316636a22165760e01b17905260008054915192935091611783916001600160a01b031690849060240161443f565b60408051601f19818403018152919052602080820180516001600160e01b031663b4faba0960e01b17815282519293509091600091895afa5060203d036040519350808401604052806020853e50600051610ae957825160208401fd5b60405163468721a760e01b81526000906001600160a01b0386169063468721a7906118159087908790879087906004016143a7565b6020604051808303816000875af1158015611834573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118589190614463565b90508061187857604051632b3f6d1160e21b815260040160405180910390fd5b5050505050565b600061066360023384612fb8565b3360009081526003602052604081206109d78184612ffc565b6000806118b583850185613d67565b3360009081526004602090815260408083206001600160e01b0319909416835292905220546001600160a01b03908116908616149150509392505050565b600080806119038486018661448d565b9150915060006119138383613036565b6001600160a01b039081169088161493505050509392505050565b6060601960f81b600160f81b85858560405160200161194e9291906144b9565b60408051808303601f190181529082905280516020918201206001600160f81b0319958616918301919091529290931660218401526022830152604282015260620160405160208183030381529060405290509392505050565b6000806000803660006119ba876130ce565b8451602086012060405163934f3a1160e01b8152959a5093985091965094509250339163934f3a11916119f5918990879087906004016140a0565b60006040518083038186803b158015611a0d57600080fd5b505afa925050508015611a1e575060015b611a3557611a2e600184866132e3565b9550611a44565b611a41600084866132e3565b95505b5050505050919050565b3360008181526001602052604080822080546001600160a01b0319166001600160a01b03891617905551611ac092918791611a91908690899089906024016144df565b60408051601f198184030181529190526020810180516001600160e01b031663f05c04e160e01b1790526117e0565b6040516001600160a01b0385169033907f9452c8fb077c3ea8f28a77c87488af657b1e44d010ad9a5992d73870da040e9490600090a350505050565b3360009081527fe90b7bceb6e7df5418fb78d8ee546e97c83a08bbccc01a0644d599ccd2a7c2e0602052604090205487906001600160a01b0316611ba957611b45600233611d3f565b60005b81811015611ba357368a8a83818110611b6357611b636142b9565b9050602002810190611b7591906142cf565b9050611b99611b876020830183614238565b611b94602084018461453a565b612065565b5050600101611b48565b50611bca565b8015611bca5760405163d8e3ed1b60e01b81523360048201526024016105bd565b336000908152600360205260409020611be28161331b565b86915060005b82811015611c435736898983818110611c0357611c036142b9565b9050602002810190611c1591906142cf565b9050611c39611c276020830183614238565b611c34602084018461453a565b6120c1565b5050600101611be8565b5084915060005b82811015611ca55736878783818110611c6557611c656142b9565b9050602002810190611c7791906142cf565b9050611c9b611c896020830183614238565b611c96602084018461453a565b61212b565b5050600101611c4a565b5082915060005b82811015611d075736858583818110611cc757611cc76142b9565b9050602002810190611cd991906142cf565b9050611cfd611ceb6020830183614238565b611cf8602084018461453a565b61226c565b5050600101611cac565b5060405133907ff48581d8a62b775b74f2fb67f1d5806a9a356fbcc598040ab3071d3e37af40c290600090a250505050505050505050565b60016000908152602083815260408083206001600160a01b0380861685529252909120541615611d82576040516329e42f3360e11b815260040160405180910390fd5b60016000818152602093845260408082206001600160a01b0394909416825292909352912080546001600160a01b0319169091179055565b6001600160a01b0381161580611dd957506001600160a01b0381166001145b15611e0257604051637c84ecfb60e01b81526001600160a01b03821660048201526024016105bd565b6001600160a01b0381811660009081526020858152604080832086851684529091529020541615611e5157604051631034f46960e21b81526001600160a01b03821660048201526024016105bd565b60016000908152602084815260408083206001600160a01b039586168085528184528285208054968816808752988552838620918652908452919093208054949095166001600160a01b031994851617909455528154169091179055565b606060006001600160a01b038416600114801590611ed55750611ed3868686612fb8565b155b15611efe57604051637c84ecfb60e01b81526001600160a01b03851660048201526024016105bd565b82600003611f1f5760405163f725081760e01b815260040160405180910390fd5b826001600160401b03811115611f3757611f37613f0c565b604051908082528060200260200182016040528015611f60578160200160208202803683370190505b506001600160a01b038086166000908152602089815260408083208a85168452909152812054929450911691505b6001600160a01b03821615801590611fb057506001600160a01b038216600114155b8015611fbb57508381105b156120205781838281518110611fd357611fd36142b9565b6001600160a01b039283166020918202929092018101919091529281166000908152888452604080822089841683529094529290922054909116908061201881614596565b915050611f8e565b6001600160a01b038216600114612058578261203d6001836145af565b8151811061204d5761204d6142b9565b602002602001015191505b8083525094509492505050565b6060836001612074828261281e565b61208060023388611dba565b84848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929998505050505050505050565b60608360026120d0828261281e565b3360009081526003602052604090206120e98188613378565b85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929a9950505050505050505050565b606083600361213a828261281e565b6000808061214a87890189614613565b919450925090506001600160e01b031983166306d61fe760e41b148061218057506001600160e01b03198316638a91b0e360e01b145b156121aa576040516379bd117b60e01b81526001600160e01b0319841660048201526024016105bd565b3360009081526004602090815260408083206001600160e01b0319871684529091529020546001600160a01b031615612202576040516374420d1560e01b81526001600160e01b0319841660048201526024016105bd565b3360009081526004602090815260408083206001600160e01b031990961683529490529290922080546001600160a01b038a166001600160a01b031960f89490941c600160a01b02939093166001600160a81b031990911617919091179055925050509392505050565b606083600461227b828261281e565b6000808061228b87890189614681565b919450925090506000808460018111156122a7576122a76146af565b1480156122bc57506001600160e01b03198316155b156123325750336000908152600560205260409020546001600160a01b031680156123055760405163741cbe0360e01b81526001600160a01b03821660048201526024016105bd565b33600090815260056020526040902080546001600160a01b0319166001600160a01b038c161790556123de565b6001846001811115612346576123466146af565b036123c5576001600160a01b0381161561237e5760405163741cbe0360e01b81526001600160a01b03821660048201526024016105bd565b503360009081526006602090815260408083206001600160e01b031986168452909152902080546001600160a01b038b81166001600160a01b0319831617909255166123de565b604051635691922f60e01b815260040160405180910390fd5b5098975050505050505050565b606082358301602081810191359085810135860180820191903590604088013588019081019035848381146124335760405163b4fa3fb360e01b815260040160405180910390fd5b60005b8181101561252c576000888883818110612452576124526142b9565b905060200201359050600181036124915761248b8d888885818110612479576124796142b9565b9050602002810190611b94919061453a565b50612523565b600281036124c15761248b8d8888858181106124af576124af6142b9565b9050602002810190611c34919061453a565b600381036124f15761248b8d8888858181106124df576124df6142b9565b9050602002810190611c96919061453a565b60048103612523576125218d88888581811061250f5761250f6142b9565b9050602002810190611cf8919061453a565b505b50600101612436565b5082828080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929e9d5050505050505050505050505050565b60405163468721a760e01b81526000906001600160a01b0385169063468721a7906125a9908690859087906001906004016143a7565b6020604051808303816000875af11580156125c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ec9190614463565b9050806106e657604051632b3f6d1160e21b815260040160405180910390fd5b6060600061261c838501856146c5565b9250905061262d600233838861344e565b509392505050565b336000908152600360205260408120606091612653848601866146c5565b93509050610ae9828288613545565b606060006126728385018561470a565b3360009081526004602090815260408083206001600160e01b031990951683529390529190912080546001600160a01b031916905595945050505050565b60606000806126c184860186614681565b9450909250905060008260018111156126dc576126dc6146af565b1480156126f157506001600160e01b03198116155b156127185733600090815260056020526040902080546001600160a01b0319169055610ae9565b600182600181111561272c5761272c6146af565b036123c5573360009081526006602090815260408083206001600160e01b031985168452909152902080546001600160a01b0319169055610ae9565b60405163468721a760e01b81526000906001600160a01b0385169063468721a79061279e908690859087906001906004016143a7565b6020604051808303816000875af11580156127bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127e19190614463565b9050806106e657604080516001600160a01b0386168152600060208201526000805160206149c9833981519152910160405180910390a150505050565b336000908152600160205260409020546001600160a01b031680156128a45760405163529562a160e01b81523360048201526001600160a01b0384811660248301526044820184905282169063529562a19060640160006040518083038186803b15801561288b57600080fd5b505afa15801561289f573d6000803e3d6000fd5b505050505b505050565b60606128b685600061170e565b15612aac576128c984600160f81b61170e565b156128ec57823583016020810190356128e333838361361a565b92505050610741565b6128f784600061170e565b156129ab5760008036600061290c8787612cbc565b6040805160018082528183019092529498509296509094509250816020015b606081526020019060019003908161292b57905050945061298433858585858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061166592505050565b85600081518110612997576129976142b9565b602002602001018190525050505050610741565b6129bd846001600160f81b031961170e565b15612a875760006129d16014828587614041565b6129da9161406b565b60601c90503660006129ef8560148189614041565b604080516001808252818301909252929450909250816020015b6060815260200190600190039081612a09579050509350612a61338484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061369392505050565b84600081518110612a7457612a746142b9565b6020026020010181905250505050610741565b604051632e5bf3f960e21b81526001600160f81b0319851660048201526024016105bd565b612aba85600160f81b61170e565b15612c4057612acd84600160f81b61170e565b15612af25782358301602081019035612ae7338383613734565b935061074192505050565b612afd84600061170e565b15612b8a57600080366000612b128787612cbc565b6040805160018082528183019092529498509296509094509250816020015b6060815260200190600190039081612b3157905050945061298433858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506137b692505050565b612b9c846001600160f81b031961170e565b15612a87576000612bb06014828587614041565b612bb99161406b565b60601c9050366000612bce8560148189614041565b604080516001808252818301909252929450909250816020015b6060815260200190600190039081612be8579050509350612a61338484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061387692505050565b6040516308c3ee0360e11b81526001600160f81b0319861660048201526024016105bd565b6000546040516128a49185916001600160a01b0390911690612c8d9086908690602401614728565b60408051601f198184030181529190526020810180516001600160e01b0316633f707e6b60e01b179052612573565b6000803681612cce6014828789614041565b612cd79161406b565b60601c9350612cea603460148789614041565b612cf3916147d3565b9250612d028560348189614041565b949793965094505050565b6000546040516128a49185916001600160a01b0390911690612d359086908690602401614728565b60408051601f198184030181529190526020810180516001600160e01b0316632864481160e11b179052612768565b60405163468721a760e01b81526000906001600160a01b0386169063468721a790612d999087908790879087906004016143a7565b6020604051808303816000875af1158015612db8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ddc9190614463565b90508061187857604080516001600160a01b0387168152600060208201526000805160206149c9833981519152910160405180910390a15050505050565b606060006001600160a01b038416600114801590612e3f5750612e3d8585612ffc565b155b15612e6857604051637c84ecfb60e01b81526001600160a01b03851660048201526024016105bd565b82600003612e895760405163f725081760e01b815260040160405180910390fd5b826001600160401b03811115612ea157612ea1613f0c565b604051908082528060200260200182016040528015612eca578160200160208202803683370190505b506001600160a01b03808616600090815260208890526040812054929450911691505b6001600160a01b03821615801590612f0f57506001600160a01b038216600114155b8015612f1a57508381105b15612f745781838281518110612f3257612f326142b9565b6001600160a01b039283166020918202929092018101919091529281166000908152928790526040909220549091169080612f6c81614596565b915050612eed565b6001600160a01b038216600114612fac5782612f916001836145af565b81518110612fa157612fa16142b9565b602002602001015191505b80835250935093915050565b600060016001600160a01b038316148015906107415750506001600160a01b0390811660009081526020938452604080822093831682529290935291205416151590565b600060016001600160a01b038316148015906109d75750506001600160a01b03908116600090815260209290925260409091205416151590565b60008083600181111561304b5761304b6146af565b14801561306057506001600160e01b03198216155b156130805750336000908152600560205260409020546001600160a01b03165b6001836001811115613094576130946146af565b0361066357503360009081526006602090815260408083206001600160e01b0319851684529091529020546001600160a01b031692915050565b6060600080368181816130e561010089018961453a565b90925090506130f8600660008385614041565b613101916147f1565b60d01c9550613114600c60068385614041565b61311d916147f1565b60d01c945061312f81600c8185614041565b9350935050506000604051806101c001604052807f84aa190356f56b8c87825f54884392a9907c23ee0f8e1ea86336b763faf021bd60001b8152602001336001600160a01b0316815260200188602001358152602001888060400190613195919061453a565b6040516131a392919061481f565b60405190819003902081526020016131be60608a018a61453a565b6040516131cc92919061481f565b604051809103902081526020016131e289613936565b81526020016131f08961394b565b81526020018860a0013581526020016132088961395b565b815260200161321689613970565b815260200161322860e08a018a61453a565b60405161323692919061481f565b604051809103902081526020018665ffffffffffff1681526020018565ffffffffffff1681526020016132766f71727de22e5e9d8baf0edac6f37da03290565b6001600160a01b031690526101c08120909150601960f81b600160f81b61329b611600565b6040516001600160f81b031993841660208201529290911660218301526022820152604281018290526062016040516020818303038152906040529650505091939590929450565b600060d08265ffffffffffff16901b60a08465ffffffffffff16901b8561330b57600061330e565b60015b60ff161717949350505050565b60016000908152602082905260409020546001600160a01b031615613353576040516329e42f3360e11b815260040160405180910390fd5b60016000818152602092909252604090912080546001600160a01b0319169091179055565b6001600160a01b038116158061339757506001600160a01b0381166001145b156133c057604051637c84ecfb60e01b81526001600160a01b03821660048201526024016105bd565b6001600160a01b03818116600090815260208490526040902054161561340457604051631034f46960e21b81526001600160a01b03821660048201526024016105bd565b60016000818152602093909352604080842080546001600160a01b039485168087529286208054959091166001600160a01b03199586161790559190935280549091169091179055565b6001600160a01b038116158061346d57506001600160a01b0381166001145b1561349657604051637c84ecfb60e01b81526001600160a01b03831660048201526024016105bd565b6001600160a01b0382811660009081526020868152604080832087851684529091529020548116908216146134e957604051637c84ecfb60e01b81526001600160a01b03821660048201526024016105bd565b6001600160a01b039081166000908152602085815260408083209584168084528683528184208054968616855297835281842090845282529091208054939092166001600160a01b031993841617909155919091528154169055565b6001600160a01b038116158061356457506001600160a01b0381166001145b1561358d57604051637c84ecfb60e01b81526001600160a01b03831660048201526024016105bd565b6001600160a01b038281166000908152602085905260409020548116908216146135d557604051637c84ecfb60e01b81526001600160a01b03821660048201526024016105bd565b6001600160a01b0390811660008181526020949094526040808520805494841686529085208054949093166001600160a01b0319948516179092559092528154169055565b60008054604051606092916136749187916001600160a01b0316906136459088908890602401614728565b60408051601f198184030181529190526020810180516001600160e01b0316636108557360e01b179052613693565b90508080602001905181019061368a91906148dc565b95945050505050565b60606000846001600160a01b0316635229073f8560008660016040518563ffffffff1660e01b81526004016136cb94939291906143a7565b6000604051808303816000875af11580156136ea573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261371291908101906143f2565b925090508061262d57604051632b3f6d1160e21b815260040160405180910390fd5b60608060006137938660008054906101000a90046001600160a01b03168787604051602401613764929190614728565b60408051601f198184030181529190526020810180516001600160e01b0316639abb6e1760e01b179052613876565b9050808060200190518101906137a99190614910565b9097909650945050505050565b60606000856001600160a01b0316635229073f86868660006040518563ffffffff1660e01b81526004016137ed94939291906143a7565b6000604051808303816000875af115801561380c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261383491908101906143f2565b925090508061170557604080516001600160a01b0388168152600060208201526000805160206149c9833981519152910160405180910390a150949350505050565b60606000846001600160a01b0316635229073f8560008660016040518563ffffffff1660e01b81526004016138ae94939291906143a7565b6000604051808303816000875af11580156138cd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526138f591908101906143f2565b925090508061262d57604080516001600160a01b0387168152600060208201526000805160206149c9833981519152910160405180910390a1509392505050565b60006001600160801b03608083013516610663565b6000610663826080013560801c90565b60006001600160801b0360c083013516610663565b600060c082013560801c610663565b6001600160a01b038116811461399457600080fd5b50565b80356115fb8161397f565b60008083601f8401126139b457600080fd5b5081356001600160401b038111156139cb57600080fd5b60208301915083602082850101111561054e57600080fd5b600080600080606085870312156139f957600080fd5b843593506020850135613a0b8161397f565b925060408501356001600160401b03811115613a2657600080fd5b613a32878288016139a2565b95989497509550505050565b600080600060408486031215613a5357600080fd5b8335925060208401356001600160401b03811115613a7057600080fd5b613a7c868287016139a2565b9497909650939450505050565b600080600060608486031215613a9e57600080fd5b83356001600160401b03811115613ab457600080fd5b84016101208187031215613ac757600080fd5b95602085013595506040909401359392505050565b60008083601f840112613aee57600080fd5b5081356001600160401b03811115613b0557600080fd5b6020830191508360208260051b850101111561054e57600080fd5b600060608284031215613b3257600080fd5b50919050565b600080600080600080600080600060a08a8c031215613b5657600080fd5b89356001600160401b0380821115613b6d57600080fd5b613b798d838e01613adc565b909b50995060208c0135915080821115613b9257600080fd5b613b9e8d838e01613adc565b909950975060408c0135915080821115613bb757600080fd5b613bc38d838e01613adc565b909750955060608c0135915080821115613bdc57600080fd5b613be88d838e01613adc565b909550935060808c0135915080821115613c0157600080fd5b50613c0e8c828d01613b20565b9150509295985092959850929598565b60008060208385031215613c3157600080fd5b82356001600160401b03811115613c4757600080fd5b613c5385828601613adc565b90969095509350505050565b60008060408385031215613c7257600080fd5b8235613c7d8161397f565b946020939093013593505050565b604080825283519082018190526000906020906060840190828701845b82811015613ccd5781516001600160a01b031684529284019290840190600101613ca8565b5050506001600160a01b039490941660209390930192909252509092915050565b60005b83811015613d09578181015183820152602001613cf1565b50506000910152565b60008151808452613d2a816020860160208601613cee565b601f01601f19169290920160200192915050565b6020815260006109d76020830184613d12565b6001600160e01b03198116811461399457600080fd5b600060208284031215613d7957600080fd5b81356109d781613d51565b600060208284031215613d9657600080fd5b5035919050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b82811015613df457603f19888603018452613de2858351613d12565b94509285019290850190600101613dc6565b5092979650505050505050565b60008060408385031215613e1457600080fd5b8235613e1f8161397f565b91506020830135613e2f8161397f565b809150509250929050565b803560ff811681146115fb57600080fd5b60008060008060608587031215613e6157600080fd5b8435613e6c8161397f565b935060208501356001600160401b03811115613e8757600080fd5b613e9387828801613adc565b9094509250613ea6905060408601613e3a565b905092959194509250565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60018060a01b0385168152836020820152606060408201526000613f02606083018486613eb1565b9695505050505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715613f4a57613f4a613f0c565b604052919050565b60006001600160401b03821115613f6b57613f6b613f0c565b50601f01601f191660200190565b6000613f8c613f8784613f52565b613f22565b9050828152838383011115613fa057600080fd5b6109d7836020830184613cee565b600082601f830112613fbf57600080fd5b6109d783835160208501613f79565b600060208284031215613fe057600080fd5b81516001600160401b03811115613ff657600080fd5b61074184828501613fae565b8284823760609190911b6bffffffffffffffffffffffff19169101908152601401919050565b60006020828403121561403a57600080fd5b5051919050565b6000808585111561405157600080fd5b8386111561405e57600080fd5b5050820193919092039150565b6bffffffffffffffffffffffff1981358181169160148510156140985780818660140360031b1b83161692505b505092915050565b8481526060602082015260006140b96060830186613d12565b82810360408401526140cc818587613eb1565b979650505050505050565b6000602082840312156140e957600080fd5b81516109d781613d51565b6000808335601e1984360301811261410b57600080fd5b83016020810192503590506001600160401b0381111561412a57600080fd5b80360382131561054e57600080fd5b6040815261415a6040820161414d85613997565b6001600160a01b03169052565b60208301356060820152600061417360408501856140f4565b61012080608086015261418b61016086018385613eb1565b925061419a60608801886140f4565b9250603f19808786030160a08801526141b4858584613eb1565b9450608089013560c088015260a089013560e0880152610100935060c0890135848801526141e560e08a018a6140f4565b92508188870301848901526141fb868483613eb1565b95505061420a848a018a6140f4565b9450925080878603016101408801525050614226838383613eb1565b93505050508260208301529392505050565b60006020828403121561424a57600080fd5b81356109d78161397f565b6000808335601e1984360301811261426c57600080fd5b8301803591506001600160401b0382111561428657600080fd5b6020019150600581901b360382131561054e57600080fd5b6000602082840312156142b057600080fd5b6109d782613e3a565b634e487b7160e01b600052603260045260246000fd5b60008235603e198336030181126142e557600080fd5b9190910192915050565b8381526001600160a01b038316602082015260606040820181905260009061368a90830184613d12565b60006020828403121561432b57600080fd5b81516001600160401b0381111561434157600080fd5b8201601f8101841361435257600080fd5b61074184825160208401613f79565b64736166652d60d81b815260008251614381816005850160208701613cee565b6e2e657263373537392e76302e302e3160881b6005939091019283015250601401919050565b60018060a01b03851681528360208201526080604082015260006143ce6080830185613d12565b905060ff8316606083015295945050505050565b805180151581146115fb57600080fd5b6000806040838503121561440557600080fd5b61440e836143e2565b915060208301516001600160401b0381111561442957600080fd5b61443585828601613fae565b9150509250929050565b6001600160a01b038316815260406020820181905260009061074190830184613d12565b60006020828403121561447557600080fd5b6109d7826143e2565b8035600281106115fb57600080fd5b600080604083850312156144a057600080fd5b6144a98361447e565b91506020830135613e2f81613d51565b828152600082516144d1816020850160208701613cee565b919091016020019392505050565b60ff8416815260406020808301829052908201839052600090849060608401835b8681101561452e5783356145138161397f565b6001600160a01b031682529282019290820190600101614500565b50979650505050505050565b6000808335601e1984360301811261455157600080fd5b8301803591506001600160401b0382111561456b57600080fd5b60200191503681900382131561054e57600080fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016145a8576145a8614580565b5060010190565b8181038181111561066357610663614580565b600082601f8301126145d357600080fd5b81356145e1613f8782613f52565b8181528460208386010111156145f657600080fd5b816020850160208301376000918101602001919091529392505050565b60008060006060848603121561462857600080fd5b833561463381613d51565b925060208401356001600160f81b03198116811461465057600080fd5b915060408401356001600160401b0381111561466b57600080fd5b614677868287016145c2565b9150509250925092565b60008060006060848603121561469657600080fd5b61469f8461447e565b9250602084013561465081613d51565b634e487b7160e01b600052602160045260246000fd5b600080604083850312156146d857600080fd5b82356146e38161397f565b915060208301356001600160401b038111156146fe57600080fd5b614435858286016145c2565b6000806040838503121561471d57600080fd5b82356146e381613d51565b60208082528181018390526000906040808401600586901b850182018785805b898110156147c457888403603f190185528235368c9003605e1901811261476d578283fd5b8b016060813561477c8161397f565b6001600160a01b03168652818901358987015261479b888301836140f4565b925081898801526147af8288018483613eb1565b978a0197965050509287019250600101614748565b50919998505050505050505050565b8035602083101561066357600019602084900360031b1b1692915050565b6001600160d01b031981358181169160068510156140985760069490940360031b84901b1690921692915050565b8183823760009101908152919050565b60006001600160401b0382111561484857614848613f0c565b5060051b60200190565b600082601f83011261486357600080fd5b81516020614873613f878361482f565b82815260059290921b8401810191818101908684111561489257600080fd5b8286015b848110156148d15780516001600160401b038111156148b55760008081fd5b6148c38986838b0101613fae565b845250918301918301614896565b509695505050505050565b6000602082840312156148ee57600080fd5b81516001600160401b0381111561490457600080fd5b61074184828501614852565b6000806040838503121561492357600080fd5b82516001600160401b038082111561493a57600080fd5b818501915085601f83011261494e57600080fd5b8151602061495e613f878361482f565b82815260059290921b8401810191818101908984111561497d57600080fd5b948201945b838610156149a257614993866143e2565b82529482019490820190614982565b918801519196509093505050808211156149bb57600080fd5b506144358582860161485256feb8bc84bd77f5eb08210b8eb20fd63b3ec6a7992d277ab94663bae0e066f792aca26469706673582212204c1b68f6eb53965f3e290e9e6a21e9c80395a1ac0fce6394aa58289d799e181864736f6c634300081900336080604052348015600f57600080fd5b506109b98061001f6000396000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c80636a2216571161005b5780636a221657146100df57806378272525146100f25780639517e29f146101055780639abb6e171461011857600080fd5b80633f707e6b1461008257806350c890221461009757806361085573146100bf575b600080fd5b6100956100903660046105c9565b610139565b005b6100aa6100a53660046105c9565b6101a3565b60405190151581526020015b60405180910390f35b6100d26100cd3660046105c9565b610212565b6040516100b691906106c6565b6100956100ed366004610712565b6102cc565b6100956101003660046107d4565b6102ef565b6100956101133660046107d4565b610398565b61012b6101263660046105c9565b610437565b6040516100b692919061085b565b8060005b8181101561019d5736848483818110610158576101586108b5565b905060200281019061016a91906108cb565b905061019361017c60208301836108eb565b602083013561018e6040850185610906565b610561565b505060010161013d565b50505050565b600081815b8181101561020a57368585838181106101c3576101c36108b5565b90506020028101906101d591906108cb565b90506101fe6101e760208301836108eb565b60208301356101f96040850185610906565b610597565b509350506001016101a8565b505092915050565b6060818067ffffffffffffffff81111561022e5761022e6106fc565b60405190808252806020026020018201604052801561026157816020015b606081526020019060019003908161024c5790505b50915060005b8181101561020a5736858583818110610282576102826108b5565b905060200281019061029491906108cb565b90506102a661017c60208301836108eb565b8483815181106102b8576102b86108b5565b602090810291909101015250600101610267565b604051600080835160208501865afa3d6000833e80156102ea573d82f35b503d81fd5b604051638a91b0e360e01b81526001600160a01b03841690638a91b0e39061031d9085908590600401610954565b600060405180830381600087803b15801561033757600080fd5b505af115801561034b573d6000803e3d6000fd5b5050604080518781526001600160a01b03871660208201527f341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e93500190505b60405180910390a150505050565b6040516306d61fe760e41b81526001600160a01b03841690636d61fe70906103c69085908590600401610954565b600060405180830381600087803b1580156103e057600080fd5b505af11580156103f4573d6000803e3d6000fd5b5050604080518781526001600160a01b03871660208201527fd21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef123935001905061038a565b606080828067ffffffffffffffff811115610454576104546106fc565b60405190808252806020026020018201604052801561048757816020015b60608152602001906001900390816104725790505b5091508067ffffffffffffffff8111156104a3576104a36106fc565b6040519080825280602002602001820160405280156104cc578160200160208202803683370190505b50925060005b8181101561055857368686838181106104ed576104ed6108b5565b90506020028101906104ff91906108cb565b90506105116101e760208301836108eb565b868481518110610523576105236108b5565b6020026020010186858151811061053c5761053c6108b5565b60209081029190910101919091529015159052506001016104d2565b50509250929050565b60405181838237600038838387895af161057e573d6000823e3d81fd5b3d8152602081013d6000823e3d01604052949350505050565b604051600090828482376000388483888a5af11591503d8152602081013d6000823e3d81016040525094509492505050565b600080602083850312156105dc57600080fd5b823567ffffffffffffffff808211156105f457600080fd5b818501915085601f83011261060857600080fd5b81358181111561061757600080fd5b8660208260051b850101111561062c57600080fd5b60209290920196919550909350505050565b600082825180855260208086019550808260051b8401018186016000805b858110156106b857601f1980888603018b5283518051808752845b81811015610692578281018901518882018a01528801610677565b5086810188018590529b87019b601f01909116909401850193509184019160010161065c565b509198975050505050505050565b6020815260006106d9602083018461063e565b9392505050565b80356001600160a01b03811681146106f757600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561072557600080fd5b61072e836106e0565b9150602083013567ffffffffffffffff8082111561074b57600080fd5b818501915085601f83011261075f57600080fd5b813581811115610771576107716106fc565b604051601f8201601f19908116603f01168101908382118183101715610799576107996106fc565b816040528281528860208487010111156107b257600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b600080600080606085870312156107ea57600080fd5b843593506107fa602086016106e0565b9250604085013567ffffffffffffffff8082111561081757600080fd5b818701915087601f83011261082b57600080fd5b81358181111561083a57600080fd5b88602082850101111561084c57600080fd5b95989497505060200194505050565b604080825283519082018190526000906020906060840190828701845b82811015610896578151151584529284019290840190600101610878565b50505083810360208501526108ab818661063e565b9695505050505050565b634e487b7160e01b600052603260045260246000fd5b60008235605e198336030181126108e157600080fd5b9190910192915050565b6000602082840312156108fd57600080fd5b6106d9826106e0565b6000808335601e1984360301811261091d57600080fd5b83018035915067ffffffffffffffff82111561093857600080fd5b60200191503681900382131561094d57600080fd5b9250929050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f1916010191905056fea2646970667358221220c249fc39b8532ba357c2c2ee22298a8dea37b717dd88be3754b2eeaaa5e1252664736f6c63430008190033", + "nonce": "0x42", + "chainId": "0xaa36a7" + }, + "additionalContracts": [ + { + "transactionType": "CREATE", + "address": "0x8f942a2377822f6164ea110959f3abb511222b6a", + "initCode": "0x6080604052348015600f57600080fd5b506109b98061001f6000396000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c80636a2216571161005b5780636a221657146100df57806378272525146100f25780639517e29f146101055780639abb6e171461011857600080fd5b80633f707e6b1461008257806350c890221461009757806361085573146100bf575b600080fd5b6100956100903660046105c9565b610139565b005b6100aa6100a53660046105c9565b6101a3565b60405190151581526020015b60405180910390f35b6100d26100cd3660046105c9565b610212565b6040516100b691906106c6565b6100956100ed366004610712565b6102cc565b6100956101003660046107d4565b6102ef565b6100956101133660046107d4565b610398565b61012b6101263660046105c9565b610437565b6040516100b692919061085b565b8060005b8181101561019d5736848483818110610158576101586108b5565b905060200281019061016a91906108cb565b905061019361017c60208301836108eb565b602083013561018e6040850185610906565b610561565b505060010161013d565b50505050565b600081815b8181101561020a57368585838181106101c3576101c36108b5565b90506020028101906101d591906108cb565b90506101fe6101e760208301836108eb565b60208301356101f96040850185610906565b610597565b509350506001016101a8565b505092915050565b6060818067ffffffffffffffff81111561022e5761022e6106fc565b60405190808252806020026020018201604052801561026157816020015b606081526020019060019003908161024c5790505b50915060005b8181101561020a5736858583818110610282576102826108b5565b905060200281019061029491906108cb565b90506102a661017c60208301836108eb565b8483815181106102b8576102b86108b5565b602090810291909101015250600101610267565b604051600080835160208501865afa3d6000833e80156102ea573d82f35b503d81fd5b604051638a91b0e360e01b81526001600160a01b03841690638a91b0e39061031d9085908590600401610954565b600060405180830381600087803b15801561033757600080fd5b505af115801561034b573d6000803e3d6000fd5b5050604080518781526001600160a01b03871660208201527f341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e93500190505b60405180910390a150505050565b6040516306d61fe760e41b81526001600160a01b03841690636d61fe70906103c69085908590600401610954565b600060405180830381600087803b1580156103e057600080fd5b505af11580156103f4573d6000803e3d6000fd5b5050604080518781526001600160a01b03871660208201527fd21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef123935001905061038a565b606080828067ffffffffffffffff811115610454576104546106fc565b60405190808252806020026020018201604052801561048757816020015b60608152602001906001900390816104725790505b5091508067ffffffffffffffff8111156104a3576104a36106fc565b6040519080825280602002602001820160405280156104cc578160200160208202803683370190505b50925060005b8181101561055857368686838181106104ed576104ed6108b5565b90506020028101906104ff91906108cb565b90506105116101e760208301836108eb565b868481518110610523576105236108b5565b6020026020010186858151811061053c5761053c6108b5565b60209081029190910101919091529015159052506001016104d2565b50509250929050565b60405181838237600038838387895af161057e573d6000823e3d81fd5b3d8152602081013d6000823e3d01604052949350505050565b604051600090828482376000388483888a5af11591503d8152602081013d6000823e3d81016040525094509492505050565b600080602083850312156105dc57600080fd5b823567ffffffffffffffff808211156105f457600080fd5b818501915085601f83011261060857600080fd5b81358181111561061757600080fd5b8660208260051b850101111561062c57600080fd5b60209290920196919550909350505050565b600082825180855260208086019550808260051b8401018186016000805b858110156106b857601f1980888603018b5283518051808752845b81811015610692578281018901518882018a01528801610677565b5086810188018590529b87019b601f01909116909401850193509184019160010161065c565b509198975050505050505050565b6020815260006106d9602083018461063e565b9392505050565b80356001600160a01b03811681146106f757600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561072557600080fd5b61072e836106e0565b9150602083013567ffffffffffffffff8082111561074b57600080fd5b818501915085601f83011261075f57600080fd5b813581811115610771576107716106fc565b604051601f8201601f19908116603f01168101908382118183101715610799576107996106fc565b816040528281528860208487010111156107b257600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b600080600080606085870312156107ea57600080fd5b843593506107fa602086016106e0565b9250604085013567ffffffffffffffff8082111561081757600080fd5b818701915087601f83011261082b57600080fd5b81358181111561083a57600080fd5b88602082850101111561084c57600080fd5b95989497505060200194505050565b604080825283519082018190526000906020906060840190828701845b82811015610896578151151584529284019290840190600101610878565b50505083810360208501526108ab818661063e565b9695505050505050565b634e487b7160e01b600052603260045260246000fd5b60008235605e198336030181126108e157600080fd5b9190910192915050565b6000602082840312156108fd57600080fd5b6106d9826106e0565b6000808335601e1984360301811261091d57600080fd5b83018035915067ffffffffffffffff82111561093857600080fd5b60200191503681900382131561094d57600080fd5b9250929050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f1916010191905056fea2646970667358221220c249fc39b8532ba357c2c2ee22298a8dea37b717dd88be3754b2eeaaa5e1252664736f6c63430008190033" + } + ], + "isFixedGasLimit": false + }, + { + "hash": "0x712bc66f8e220d2e1b66ab411af1b28676a89a25c271448467b8aaa10cee0110", + "transactionType": "CREATE2", + "contractName": "Safe7579Launchpad", + "contractAddress": "0xbd3b9ba8162b23bcb0373e265cb07127e5b1b644", + "function": null, + "arguments": [ + "0x0000000071727De22E5E9d8BAf0edAc6f37da032", + "0xe0cde9239d16bEf05e62Bbf7aA93e420f464c826" + ], + "transaction": { + "from": "0x8749313f626b100b822d573c71dfffdaca383032", + "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", + "gas": "0x1ff99e", + "value": "0x0", + "input": "0x000000000000000000000000000000000000000000000000000000000000000060e060405234801561001057600080fd5b506040516119ec3803806119ec83398101604081905261002f91610089565b6001600160a01b03821661005657604051632039d3c960e01b815260040160405180910390fd5b306080526001600160a01b0391821660a0521660c0526100c3565b6001600160a01b038116811461008657600080fd5b50565b6000806040838503121561009c57600080fd5b82516100a781610071565b60208401519092506100b881610071565b809150509250929050565b60805160a05160c0516118e061010c6000396000818160a801526102e901526000818160f90152818161041701526109850152600081816103c2015261075401526118e06000f3fe60806040526004361061008a5760003560e01c80634fff40e1116100595780634fff40e11461016b578063663c87d81461018b578063928107f9146101ab578063c67e2d2a146101cb578063d9ed0e8f146101ed57600080fd5b806306433b1b14610096578063137e051e146100e757806315cca6381461011b57806319822f7c1461013d57600080fd5b3661009157005b600080fd5b3480156100a257600080fd5b506100ca7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100f357600080fd5b506100ca7f000000000000000000000000000000000000000000000000000000000000000081565b34801561012757600080fd5b5061013b610136366004610bdc565b61020d565b005b34801561014957600080fd5b5061015d610158366004610cc0565b6103bc565b6040519081526020016100de565b34801561017757600080fd5b5061013b610186366004610d13565b61074f565b34801561019757600080fd5b506100ca6101a6366004610e9b565b610849565b3480156101b757600080fd5b5061015d6101c6366004611092565b610928565b3480156101d757600080fd5b5060008051602061188b8339815191525461015d565b3480156101f957600080fd5b5061013b6102083660046111a8565b61097a565b33301461022d57604051630a57d61d60e01b815260040160405180910390fd5b60405163610b592560e01b81526001600160a01b038b166004820152309063610b592590602401600060405180830381600087803b15801561026e57600080fd5b505af1158015610282573d6000803e3d6000fd5b5050604080516000808252602082019092526001600160a01b038e16935063540fb4f99250906102d5565b6040805180820190915260008152606060208201528152602001906001900390816102ad5790505b508b8b8b8b8b8b60405180606001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020018d8d8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050509082525060ff8c166020909101526040516001600160e01b031960e08b901b16815261037e9897969594939291906004016113f7565b600060405180830381600087803b15801561039857600080fd5b505af11580156103ac573d6000803e3d6000fd5b5050505050505050505050505050565b600080547f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161461040c576040516308e3edd160e41b815260040160405180910390fd5b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461045557604051632039d3c960e01b815260040160405180910390fd5b6104626060850185611497565b610471916004916000916114dd565b61047a91611507565b6001600160e01b03191663d9ed0e8f60e01b146104aa5760405163c3d40f7760e01b815260040160405180910390fd5b60006104b96060860186611497565b6104c79160049082906114dd565b8101906104d49190611092565b90506104ec60008051602061188b8339815191525490565b6104f582610928565b146105135760405163278328b160e21b815260040160405180910390fd5b60a081015160c0820151604051636a5e151560e01b81526020880135606081901c9390926001600160a01b0390911691636a5e15159161055591600401611537565b600060405180830381600087803b15801561056f57600080fd5b505af1158015610583573d6000803e3d6000fd5b50505060c08401515160009150815b818110156106a95760008660c0015182815181106105b2576105b261154a565b6020026020010151600001519050806001600160a01b0316636d61fe708860c0015184815181106105e5576105e561154a565b6020026020010151602001516040518263ffffffff1660e01b815260040161060d9190611560565b600060405180830381600087803b15801561062757600080fd5b505af115801561063b573d6000803e3d6000fd5b505060408051600181526001600160a01b03851660208201527fd21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef123935001905060405180910390a1856001600160a01b0316816001600160a01b0316036106a057600193505b50600101610592565b50816106bd57600195505050505050610748565b604051639700320360e01b81526001600160a01b038516906397003203906106eb908c908c90600401611573565b6020604051808303816000875af115801561070a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061072e9190611672565b95508615610742576000806000808a335af1505b50505050505b9392505050565b6000547f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161461079e576040516308e3edd160e41b815260040160405180910390fd5b6107b48460008051602061188b83398151915255565b6001600160a01b03831615610843576000836001600160a01b031683836040516107df92919061168b565b600060405180830381855af49150503d806000811461081a576040519150601f19603f3d011682016040523d82523d6000602084013e61081f565b606091505b505090508061084157604051631f57fed560e31b815260040160405180910390fd5b505b50505050565b600081805190602001208360405160200161086e929190918252602082015260400190565b60405160208183030381529060405280519060200120925060ff60f81b858486896001600160a01b03166040516020016108a992919061169b565b6040516020818303038152906040528051906020012060405160200161090694939291906001600160f81b031994909416845260609290921b6bffffffffffffffffffffffff191660018401526015830152603582015260550190565b60408051601f1981840301815291905280516020909101209695505050505050565b80516020808301516040808501516060860151608087015160a088015160c0890151945160009861095d9890979691016116bd565b604051602081830303815290604052805190602001209050919050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146109c357604051632039d3c960e01b815260040160405180910390fd5b6109d0602082018261172a565b600080546001600160a01b0319166001600160a01b03929092169190911790553063b63e800d610a036020840184611747565b6040850135610a18608087016060880161172a565b610a256080880188611497565b610a3560c08a0160a08b0161172a565b60008060006040518b63ffffffff1660e01b8152600401610a5f9a99989796959493929190611790565b600060405180830381600087803b158015610a7957600080fd5b505af1158015610a8d573d6000803e3d6000fd5b5050600060008051602061188b8339815191525550610aa99050565b600080610abc60c0840160a0850161172a565b6001600160a01b0316610ad260e0850185611497565b30604051602001610ae593929190611848565b60408051601f1981840301815290829052610aff9161186e565b6000604051808303816000865af19150503d8060008114610b3c576040519150601f19603f3d011682016040523d82523d6000602084013e610b41565b606091505b509150915081610b5357805160208201fd5b505050565b6001600160a01b0381168114610b6d57600080fd5b50565b8035610b7b81610b58565b919050565b60008083601f840112610b9257600080fd5b5081356001600160401b03811115610ba957600080fd5b6020830191508360208260051b8501011115610bc457600080fd5b9250929050565b803560ff81168114610b7b57600080fd5b60008060008060008060008060008060c08b8d031215610bfb57600080fd5b610c048b610b70565b995060208b01356001600160401b0380821115610c2057600080fd5b610c2c8e838f01610b80565b909b50995060408d0135915080821115610c4557600080fd5b610c518e838f01610b80565b909950975060608d0135915080821115610c6a57600080fd5b610c768e838f01610b80565b909750955060808d0135915080821115610c8f57600080fd5b50610c9c8d828e01610b80565b9094509250610caf905060a08c01610bcb565b90509295989b9194979a5092959850565b600080600060608486031215610cd557600080fd5b83356001600160401b03811115610ceb57600080fd5b84016101208187031215610cfe57600080fd5b95602085013595506040909401359392505050565b60008060008060608587031215610d2957600080fd5b843593506020850135610d3b81610b58565b925060408501356001600160401b0380821115610d5757600080fd5b818701915087601f830112610d6b57600080fd5b813581811115610d7a57600080fd5b886020828501011115610d8c57600080fd5b95989497505060200194505050565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715610dd357610dd3610d9b565b60405290565b60405161010081016001600160401b0381118282101715610dd357610dd3610d9b565b604051601f8201601f191681016001600160401b0381118282101715610e2457610e24610d9b565b604052919050565b600082601f830112610e3d57600080fd5b81356001600160401b03811115610e5657610e56610d9b565b610e69601f8201601f1916602001610dfc565b818152846020838601011115610e7e57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a08688031215610eb357600080fd5b8535610ebe81610b58565b94506020860135610ece81610b58565b935060408601356001600160401b0380821115610eea57600080fd5b610ef689838a01610e2c565b9450606088013593506080880135915080821115610f1357600080fd5b50610f2088828901610e2c565b9150509295509295909350565b60006001600160401b03821115610f4657610f46610d9b565b5060051b60200190565b600082601f830112610f6157600080fd5b81356020610f76610f7183610f2d565b610dfc565b8083825260208201915060208460051b870101935086841115610f9857600080fd5b602086015b84811015610fbd578035610fb081610b58565b8352918301918301610f9d565b509695505050505050565b600082601f830112610fd957600080fd5b81356020610fe9610f7183610f2d565b82815260059290921b8401810191818101908684111561100857600080fd5b8286015b84811015610fbd5780356001600160401b038082111561102c5760008081fd5b908801906040828b03601f19018113156110465760008081fd5b61104e610db1565b8784013561105b81610b58565b81529083013590828211156110705760008081fd5b61107e8c8984870101610e2c565b81890152865250505091830191830161100c565b6000602082840312156110a457600080fd5b81356001600160401b03808211156110bb57600080fd5b9083019061010082860312156110d057600080fd5b6110d8610dd9565b6110e183610b70565b81526020830135828111156110f557600080fd5b61110187828601610f50565b6020830152506040830135604082015261111d60608401610b70565b606082015260808301358281111561113457600080fd5b61114087828601610e2c565b60808301525061115260a08401610b70565b60a082015260c08301358281111561116957600080fd5b61117587828601610fc8565b60c08301525060e08301358281111561118d57600080fd5b61119987828601610e2c565b60e08301525095945050505050565b6000602082840312156111ba57600080fd5b81356001600160401b038111156111d057600080fd5b8201610100818503121561074857600080fd5b60005b838110156111fe5781810151838201526020016111e6565b50506000910152565b6000815180845261121f8160208601602086016111e3565b601f01601f19169290920160200192915050565b600082825180855260208086019550808260051b84010181860160005b8481101561129b57858303601f19018952815180516001600160a01b03168452840151604085850181905261128781860183611207565b9a86019a9450505090830190600101611250565b5090979650505050505050565b6000808335601e198436030181126112bf57600080fd5b83016020810192503590506001600160401b038111156112de57600080fd5b803603821315610bc457600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60008383855260208086019550808560051b830101846000805b888110156113a457858403601f19018a52823536899003603e19018112611355578283fd5b88016040813561136481610b58565b6001600160a01b0316865261137b828801836112a8565b9250818888015261138f82880184836112ed565b9c88019c965050509285019250600101611330565b509198975050505050505050565b60008151808452602080850194506020840160005b838110156113ec5781516001600160a01b0316875295820195908201906001016113c7565b509495945050505050565b60a08152600061140a60a083018b611233565b828103602084015261141d818a8c611316565b9050828103604084015261143281888a611316565b90508281036060840152611447818688611316565b9050828103608084015260018060a01b03845116815260208401516060602083015261147660608301826113b2565b905060ff604086015116604083015280925050509998505050505050505050565b6000808335601e198436030181126114ae57600080fd5b8301803591506001600160401b038211156114c857600080fd5b602001915036819003821315610bc457600080fd5b600080858511156114ed57600080fd5b838611156114fa57600080fd5b5050820193919092039150565b6001600160e01b0319813581811691600485101561152f5780818660040360031b1b83161692505b505092915050565b6020815260006107486020830184611233565b634e487b7160e01b600052603260045260246000fd5b6020815260006107486020830184611207565b604081526115946040820161158785610b70565b6001600160a01b03169052565b6020830135606082015260006115ad60408501856112a8565b6101208060808601526115c5610160860183856112ed565b92506115d460608801886112a8565b9250603f19808786030160a08801526115ee8585846112ed565b9450608089013560c088015260a089013560e0880152610100935060c08901358488015261161f60e08a018a6112a8565b92508188870301848901526116358684836112ed565b955050611644848a018a6112a8565b94509250808786030161014088015250506116608383836112ed565b93505050508260208301529392505050565b60006020828403121561168457600080fd5b5051919050565b8183823760009101908152919050565b600083516116ad8184602088016111e3565b9190910191825250602001919050565b600060018060a01b03808a16835260e060208401526116df60e084018a6113b2565b886040850152818816606085015283810360808501526116ff8188611207565b905081861660a085015283810360c085015261171b8186611233565b9b9a5050505050505050505050565b60006020828403121561173c57600080fd5b813561074881610b58565b6000808335601e1984360301811261175e57600080fd5b8301803591506001600160401b0382111561177857600080fd5b6020019150600581901b3603821315610bc457600080fd5b61010080825281018a9052600061012082018c825b8d8110156117d65781356117b881610b58565b6001600160a01b0316835260209283019291909101906001016117a5565b50508a60208401526117f3604084018b6001600160a01b03169052565b828103606084015261180681898b6112ed565b91505061181e60808301876001600160a01b03169052565b6001600160a01b03851660a08301528360c083015261171b60e08301846001600160a01b03169052565b8284823760609190911b6bffffffffffffffffffffffff19169101908152601401919050565b600082516118808184602087016111e3565b919091019291505056fe982e06ee6a56dfc0f1ac189a5d23506361ca0a3ce45a9c7b8d33d65d43746a24a2646970667358221220c1919b1e1e9acac581cfa9d50a4228c3505e3042d626f6d2d2bd2e35aba05bb664736f6c634300081900330000000000000000000000000000000071727de22e5e9d8baf0edac6f37da032000000000000000000000000e0cde9239d16bef05e62bbf7aa93e420f464c826", + "nonce": "0x43", + "chainId": "0xaa36a7" + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "status": "0x1", + "cumulativeGasUsed": "0x13a07ae", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0xadee694915caabe82504b2d1afe5144199b8e1dca581228940b9fdf8966bdd53", + "transactionIndex": "0x3c", + "blockHash": "0x592afb04c687353a664e12162c0469af8fa126363396d4f43113de3b057ea2a1", + "blockNumber": "0x598d1b", + "gasUsed": "0x488ee5", + "effectiveGasPrice": "0x138fe5ea5", + "from": "0x8749313f626b100b822d573c71dfffdaca383032", + "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", + "contractAddress": "0xbaca6f74a5549368568f387fd989c279f940f1a5" + }, + { + "status": "0x1", + "cumulativeGasUsed": "0x15361eb", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0x712bc66f8e220d2e1b66ab411af1b28676a89a25c271448467b8aaa10cee0110", + "transactionIndex": "0x3e", + "blockHash": "0x592afb04c687353a664e12162c0469af8fa126363396d4f43113de3b057ea2a1", + "blockNumber": "0x598d1b", + "gasUsed": "0x15dea5", + "effectiveGasPrice": "0x138fe5ea5", + "from": "0x8749313f626b100b822d573c71dfffdaca383032", + "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", + "contractAddress": "0xbd3b9ba8162b23bcb0373e265cb07127e5b1b644" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1715275639, + "chain": 11155111, + "commit": "7ac113c" +} \ No newline at end of file diff --git a/accounts/safe7579/broadcast/Deploy.s.sol/11155111/run-latest.json b/accounts/safe7579/broadcast/Deploy.s.sol/11155111/run-latest.json new file mode 100644 index 00000000..a78370b5 --- /dev/null +++ b/accounts/safe7579/broadcast/Deploy.s.sol/11155111/run-latest.json @@ -0,0 +1,91 @@ +{ + "transactions": [ + { + "hash": "0xadee694915caabe82504b2d1afe5144199b8e1dca581228940b9fdf8966bdd53", + "transactionType": "CREATE2", + "contractName": "Safe7579", + "contractAddress": "0xbaca6f74a5549368568f387fd989c279f940f1a5", + "function": null, + "arguments": null, + "transaction": { + "from": "0x8749313f626b100b822d573c71dfffdaca383032", + "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", + "gas": "0x64306b", + "value": "0x0", + "input": "0x00000000000000000000000000000000000000000000000000000000000000006080604052348015600f57600080fd5b50604051601a90605a565b604051809103906000f0801580156035573d6000803e3d6000fd5b50600080546001600160a01b0319166001600160a01b03929092169190911790556067565b6109d880614a9483390190565b614a1e806100766000396000f3fe6080604052600436106101235760003560e01c8063b0d691fe116100a0578063e9ae5c5311610064578063e9ae5c531461040f578063ea5f61d014610422578063eab77e1714610442578063f2dc691d14610462578063f698da25146104825761012a565b8063b0d691fe14610340578063b875d5d814610363578063d03c7914146103af578063d691c964146103cf578063d828435d146103ef5761012a565b80636a5e1515116100e75780636a5e1515146102b757806385571368146102ca5780639517e29f146102f85780639cfd7cff1461030b578063a71763a81461032d5761012a565b80630a664dba146101d4578063112d3a7d146102185780631626ba7e1461024857806319822f7c14610281578063540fb4f9146102a25761012a565b3661012a57005b600036606060003560e01c63bc197c81811463f23a6e6182141763150b7a028214171561015b57806020526020603cf35b5033600090815260056020908152604080832054600683528184206001600160e01b031985351680865293529083205491926001600160a01b039182169290911690806101a88484610497565b915091506101b68888610555565b95506101c484848484610669565b5050505050915050805190602001f35b3480156101e057600080fd5b50336000908152600560205260409020546001600160a01b03165b6040516001600160a01b0390911681526020015b60405180910390f35b34801561022457600080fd5b506102386102333660046139e3565b6106ec565b604051901515815260200161020f565b34801561025457600080fd5b50610268610263366004613a3e565b610749565b6040516001600160e01b0319909116815260200161020f565b61029461028f366004613a89565b6109de565b60405190815260200161020f565b6102b56102b0366004613b38565b610af2565b005b6102b56102c5366004613c1e565b610b3f565b3480156102d657600080fd5b506102ea6102e5366004613c5f565b610ba0565b60405161020f929190613c8b565b6102b56103063660046139e3565b610bbc565b34801561031757600080fd5b50610320610d61565b60405161020f9190613d3e565b6102b561033b3660046139e3565b610df3565b34801561034c57600080fd5b506f71727de22e5e9d8baf0edac6f37da0326101fb565b34801561036f57600080fd5b506101fb61037e366004613d67565b3360009081526006602090815260408083206001600160e01b0319909416835292905220546001600160a01b031690565b3480156103bb57600080fd5b506102386103ca366004613d84565b610f5f565b6103e26103dd366004613a3e565b611007565b60405161020f9190613d9d565b3480156103fb57600080fd5b5061029461040a366004613e01565b6110d3565b6102b561041d366004613a3e565b611173565b34801561042e57600080fd5b506102ea61043d366004613c5f565b611518565b34801561044e57600080fd5b506102b561045d366004613e4b565b611542565b34801561046e57600080fd5b5061023861047d366004613d84565b6115b1565b34801561048e57600080fd5b50610294611600565b6060806001600160a01b03841615610517576104fe338560006104b8611659565b346000366040516024016104cf9493929190613eda565b60408051601f198184030181529190526020810180516001600160e01b031663d68f602560e01b179052611665565b9150818060200190518101906105149190613fce565b91505b6001600160a01b0383161561054e57610535338460006104b8611659565b90508080602001905181019061054b9190613fce565b90505b9250929050565b3360009081526004602090815260408083206001600160e01b0319843516845290915290208054606091906001600160a01b03811690600160a01b900460f81b816105c657604051632464e76d60e11b81526001600160e01b03196000351660048201526024015b60405180910390fd5b6105d481607f60f91b61170e565b156106185761060e338388886105e8611659565b6040516020016105fa93929190614002565b604051602081830303815290604052611720565b9350505050610663565b61062381600061170e565b1561065f5761060e338360008989610639611659565b60405160200161064b93929190614002565b604051602081830303815290604052611665565b5050505b92915050565b6001600160a01b038416156106bf576106bf33856000856040516024016106909190613d3e565b60408051601f198184030181529190526020810180516001600160e01b0316630b9dfbed60e11b1790526117e0565b6001600160a01b038316156106e6576106e633846000846040516024016106909190613d3e565b50505050565b600060018503610706576106ff8461187f565b9050610741565b60028503610717576106ff8461188d565b6003850361072a576106ff8484846118a6565b6004850361073d576106ff8484846118f3565b5060005b949350505050565b600033821580156107c15750604051635ae6bd3760e01b8152600481018690526001600160a01b03821690635ae6bd3790602401602060405180830381865afa15801561079a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107be9190614028565b15155b156107d65750630b135d3f60e11b90506109d7565b60006107e56014828688614041565b6107ee9161406b565b60601c905080158061080657506108048161187f565b155b1561095c5760006108d1836001600160a01b031663f698da256040518163ffffffff1660e01b8152600401602060405180830381865afa15801561084e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108729190614028565b60408051602081018b90527f60b3cbf8b4a223d68d641b3b6ddf9a298e7f33710cf3d3a9d1146b5a6150fbca910160408051601f198184030181528282528051602091820120908301520160405160208183030381529060405261192e565b805160208201209091506001600160a01b03841663934f3a1182846108f98a6014818e614041565b6040518563ffffffff1660e01b815260040161091894939291906140a0565b60006040518083038186803b15801561093057600080fd5b505afa158015610944573d6000803e3d6000fd5b50630b135d3f60e11b97506109d79650505050505050565b60006109bb338361096b611659565b8a6109798a6014818e614041565b60405160240161098c9493929190613eda565b60408051601f198184030181529190526020810180516001600160e01b0316637aa8f17760e11b179052611720565b9050808060200190518101906109d191906140d7565b93505050505b9392505050565b60006f71727de22e5e9d8baf0edac6f37da0326109f9611659565b6001600160a01b031614610a2057604051635629665f60e11b815260040160405180910390fd5b6020840135606081901c90811580610a3e5750610a3c8261187f565b155b15610a5357610a4c866119a8565b9250610ab8565b6000610a9e338460008a8a604051602401610a6f929190614139565b60408051601f198184030181529190526020810180516001600160e01b0316639700320360e01b179052611665565b905080806020019051810190610ab49190614028565b9350505b8315610ae957610ae9336f71727de22e5e9d8baf0edac6f37da03286604051806020016040528060008152506117e0565b50509392505050565b610b24610b026020830183614238565b610b0f6020840184614255565b610b1f606086016040870161429e565b611a4e565b610b348989898989898989611afc565b505050505050505050565b610b4a600233611d3f565b8060005b818110156106e65736848483818110610b6957610b696142b9565b9050602002810190610b7b91906142cf565b9050610b9733610b8e6020840184614238565b60029190611dba565b50600101610b4e565b60606000610bb16002338686611eaf565b915091509250929050565b3360009081526005602090815260408083205460068352818420639517e29f60e01b80865293529083205491926001600160a01b03918216929091169080610c048484610497565b91509150610c1f6f71727de22e5e9d8baf0edac6f37da03290565b6001600160a01b0316610c30611659565b6001600160a01b03161480610c5d5750610c48611659565b6001600160a01b0316336001600160a01b0316145b610c7a57604051635629665f60e11b815260040160405180910390fd5b606060018a03610c9657610c8f898989612065565b9050610cfb565b60028a03610ca957610c8f8989896120c1565b60038a03610cbc57610c8f89898961212b565b60048a03610ccf57610c8f89898961226c565b89610cdf57610c8f8989896123eb565b60405163041c38b360e41b8152600481018b90526024016105bd565b600054604051610d549133916001600160a01b0390911690610d25908e908e9087906024016142ef565b60408051601f198184030181529190526020810180516001600160e01b0316639517e29f60e01b179052612573565b50610b3484848484610669565b60606000336001600160a01b031663ffa1ad746040518163ffffffff1660e01b8152600401600060405180830381865afa158015610da3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610dcb9190810190614319565b905080604051602001610dde9190614361565b60405160208183030381529060405291505090565b33600090815260056020908152604080832054600683528184206314e2ec7560e31b80865293529083205491926001600160a01b03918216929091169080610e3b8484610497565b91509150610e566f71727de22e5e9d8baf0edac6f37da03290565b6001600160a01b0316610e67611659565b6001600160a01b03161480610e945750610e7f611659565b6001600160a01b0316336001600160a01b0316145b610eb157604051635629665f60e11b815260040160405180910390fd5b606060018a03610ecd57610ec689898961260c565b9050610f06565b60028a03610ee057610ec6898989612635565b60038a03610ef357610ec6898989612662565b60048a03610cdf57610ec68989896126b0565b600054604051610d549133916001600160a01b0390911690610f30908e908e9087906024016142ef565b60408051601f198184030181529190526020810180516001600160e01b0316637827252560e01b179052612768565b600081600881901b610f7582600160f81b61170e565b15610f835760019250610fc6565b610f8e82600061170e565b15610f9c5760019250610fc6565b610fae826001600160f81b031961170e565b15610fbc5760019250610fc6565b5060009392505050565b828015610fd95750610fd981600061170e565b15610fe5575050919050565b828015610ffb5750610ffb81600160f81b61170e565b15610fbc575050919050565b6060611019611014611659565b61188d565b61104a57611025611659565b604051635c93ff2f60e11b81526001600160a01b0390911660048201526024016105bd565b33600090815260056020908152604080832054600683528184206335a4725960e21b80865293529083205491926001600160a01b039182169290911690806110928484610497565b915091503360026110a3828261281e565b8a600881901b6110b581838e8e6128a9565b9950505050506110c784848484610669565b50505050509392505050565b6000602082901b640100000000600160c01b03166f71727de22e5e9d8baf0edac6f37da032604051631aab3f0d60e11b81526001600160a01b0386811660048301526001600160c01b038416602483015291909116906335567e1a90604401602060405180830381865afa15801561114f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107419190614028565b336000908152600560209081526040808320546006835281842063e9ae5c5360e01b80865293529083205491926001600160a01b039182169290911690806111bb8484610497565b915091506111d66f71727de22e5e9d8baf0edac6f37da03290565b6001600160a01b03166111e7611659565b6001600160a01b0316148061121457506111ff611659565b6001600160a01b0316336001600160a01b0316145b61123157604051635629665f60e11b815260040160405180910390fd5b87600881901b3361124382600061170e565b156113a65761125683600160f81b61170e565b156112775789358a01602081019035611270838383612c65565b50506114ff565b61128283600061170e565b156112ea576000803660006112978e8e612cbc565b93509350935093506112e185858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506117e092505050565b505050506114ff565b6112fc836001600160f81b031961170e565b156113815760006113106014828c8e614041565b6113199161406b565b60601c90503660008c8c601490809261133493929190614041565b91509150611379848484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061257392505050565b5050506114ff565b604051632e5bf3f960e21b81526001600160f81b0319841660048201526024016105bd565b6113b482600160f81b61170e565b156114da576113c783600160f81b61170e565b156113e15789358a01602081019035611270838383612d0d565b6113ec83600061170e565b1561144b576000803660006114018e8e612cbc565b93509350935093506112e185858585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612d6492505050565b61145d836001600160f81b031961170e565b156113815760006114716014828c8e614041565b61147a9161406b565b60601c90503660008c8c601490809261149593929190614041565b91509150611379848484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061276892505050565b6040516308c3ee0360e11b81526001600160f81b0319831660048201526024016105bd565b50505061150e84848484610669565b5050505050505050565b33600090815260036020526040812060609190611536818686612e1a565b92509250509250929050565b6f71727de22e5e9d8baf0edac6f37da03261155b611659565b6001600160a01b031614806115885750611573611659565b6001600160a01b0316336001600160a01b0316145b6115a557604051635629665f60e11b815260040160405180910390fd5b6106e684848484611a4e565b6000600182036115c357506001919050565b600282036115d357506001919050565b600382036115e357506001919050565b600482036115f357506001919050565b506000919050565b919050565b604080517f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a794692186020820152469181019190915230606082015260009060800160405160208183030381529060405280519060200120905090565b60131936013560601c90565b60606000856001600160a01b0316635229073f86868660006040518563ffffffff1660e01b815260040161169c94939291906143a7565b6000604051808303816000875af11580156116bb573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526116e391908101906143f2565b925090508061170557604051632b3f6d1160e21b815260040160405180910390fd5b50949350505050565b6001600160f81b031990811691161490565b60606000838360405160240161173792919061443f565b60408051601f198184030181529181526020820180516001600160e01b0316636a22165760e01b17905260008054915192935091611783916001600160a01b031690849060240161443f565b60408051601f19818403018152919052602080820180516001600160e01b031663b4faba0960e01b17815282519293509091600091895afa5060203d036040519350808401604052806020853e50600051610ae957825160208401fd5b60405163468721a760e01b81526000906001600160a01b0386169063468721a7906118159087908790879087906004016143a7565b6020604051808303816000875af1158015611834573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118589190614463565b90508061187857604051632b3f6d1160e21b815260040160405180910390fd5b5050505050565b600061066360023384612fb8565b3360009081526003602052604081206109d78184612ffc565b6000806118b583850185613d67565b3360009081526004602090815260408083206001600160e01b0319909416835292905220546001600160a01b03908116908616149150509392505050565b600080806119038486018661448d565b9150915060006119138383613036565b6001600160a01b039081169088161493505050509392505050565b6060601960f81b600160f81b85858560405160200161194e9291906144b9565b60408051808303601f190181529082905280516020918201206001600160f81b0319958616918301919091529290931660218401526022830152604282015260620160405160208183030381529060405290509392505050565b6000806000803660006119ba876130ce565b8451602086012060405163934f3a1160e01b8152959a5093985091965094509250339163934f3a11916119f5918990879087906004016140a0565b60006040518083038186803b158015611a0d57600080fd5b505afa925050508015611a1e575060015b611a3557611a2e600184866132e3565b9550611a44565b611a41600084866132e3565b95505b5050505050919050565b3360008181526001602052604080822080546001600160a01b0319166001600160a01b03891617905551611ac092918791611a91908690899089906024016144df565b60408051601f198184030181529190526020810180516001600160e01b031663f05c04e160e01b1790526117e0565b6040516001600160a01b0385169033907f9452c8fb077c3ea8f28a77c87488af657b1e44d010ad9a5992d73870da040e9490600090a350505050565b3360009081527fe90b7bceb6e7df5418fb78d8ee546e97c83a08bbccc01a0644d599ccd2a7c2e0602052604090205487906001600160a01b0316611ba957611b45600233611d3f565b60005b81811015611ba357368a8a83818110611b6357611b636142b9565b9050602002810190611b7591906142cf565b9050611b99611b876020830183614238565b611b94602084018461453a565b612065565b5050600101611b48565b50611bca565b8015611bca5760405163d8e3ed1b60e01b81523360048201526024016105bd565b336000908152600360205260409020611be28161331b565b86915060005b82811015611c435736898983818110611c0357611c036142b9565b9050602002810190611c1591906142cf565b9050611c39611c276020830183614238565b611c34602084018461453a565b6120c1565b5050600101611be8565b5084915060005b82811015611ca55736878783818110611c6557611c656142b9565b9050602002810190611c7791906142cf565b9050611c9b611c896020830183614238565b611c96602084018461453a565b61212b565b5050600101611c4a565b5082915060005b82811015611d075736858583818110611cc757611cc76142b9565b9050602002810190611cd991906142cf565b9050611cfd611ceb6020830183614238565b611cf8602084018461453a565b61226c565b5050600101611cac565b5060405133907ff48581d8a62b775b74f2fb67f1d5806a9a356fbcc598040ab3071d3e37af40c290600090a250505050505050505050565b60016000908152602083815260408083206001600160a01b0380861685529252909120541615611d82576040516329e42f3360e11b815260040160405180910390fd5b60016000818152602093845260408082206001600160a01b0394909416825292909352912080546001600160a01b0319169091179055565b6001600160a01b0381161580611dd957506001600160a01b0381166001145b15611e0257604051637c84ecfb60e01b81526001600160a01b03821660048201526024016105bd565b6001600160a01b0381811660009081526020858152604080832086851684529091529020541615611e5157604051631034f46960e21b81526001600160a01b03821660048201526024016105bd565b60016000908152602084815260408083206001600160a01b039586168085528184528285208054968816808752988552838620918652908452919093208054949095166001600160a01b031994851617909455528154169091179055565b606060006001600160a01b038416600114801590611ed55750611ed3868686612fb8565b155b15611efe57604051637c84ecfb60e01b81526001600160a01b03851660048201526024016105bd565b82600003611f1f5760405163f725081760e01b815260040160405180910390fd5b826001600160401b03811115611f3757611f37613f0c565b604051908082528060200260200182016040528015611f60578160200160208202803683370190505b506001600160a01b038086166000908152602089815260408083208a85168452909152812054929450911691505b6001600160a01b03821615801590611fb057506001600160a01b038216600114155b8015611fbb57508381105b156120205781838281518110611fd357611fd36142b9565b6001600160a01b039283166020918202929092018101919091529281166000908152888452604080822089841683529094529290922054909116908061201881614596565b915050611f8e565b6001600160a01b038216600114612058578261203d6001836145af565b8151811061204d5761204d6142b9565b602002602001015191505b8083525094509492505050565b6060836001612074828261281e565b61208060023388611dba565b84848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929998505050505050505050565b60608360026120d0828261281e565b3360009081526003602052604090206120e98188613378565b85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929a9950505050505050505050565b606083600361213a828261281e565b6000808061214a87890189614613565b919450925090506001600160e01b031983166306d61fe760e41b148061218057506001600160e01b03198316638a91b0e360e01b145b156121aa576040516379bd117b60e01b81526001600160e01b0319841660048201526024016105bd565b3360009081526004602090815260408083206001600160e01b0319871684529091529020546001600160a01b031615612202576040516374420d1560e01b81526001600160e01b0319841660048201526024016105bd565b3360009081526004602090815260408083206001600160e01b031990961683529490529290922080546001600160a01b038a166001600160a01b031960f89490941c600160a01b02939093166001600160a81b031990911617919091179055925050509392505050565b606083600461227b828261281e565b6000808061228b87890189614681565b919450925090506000808460018111156122a7576122a76146af565b1480156122bc57506001600160e01b03198316155b156123325750336000908152600560205260409020546001600160a01b031680156123055760405163741cbe0360e01b81526001600160a01b03821660048201526024016105bd565b33600090815260056020526040902080546001600160a01b0319166001600160a01b038c161790556123de565b6001846001811115612346576123466146af565b036123c5576001600160a01b0381161561237e5760405163741cbe0360e01b81526001600160a01b03821660048201526024016105bd565b503360009081526006602090815260408083206001600160e01b031986168452909152902080546001600160a01b038b81166001600160a01b0319831617909255166123de565b604051635691922f60e01b815260040160405180910390fd5b5098975050505050505050565b606082358301602081810191359085810135860180820191903590604088013588019081019035848381146124335760405163b4fa3fb360e01b815260040160405180910390fd5b60005b8181101561252c576000888883818110612452576124526142b9565b905060200201359050600181036124915761248b8d888885818110612479576124796142b9565b9050602002810190611b94919061453a565b50612523565b600281036124c15761248b8d8888858181106124af576124af6142b9565b9050602002810190611c34919061453a565b600381036124f15761248b8d8888858181106124df576124df6142b9565b9050602002810190611c96919061453a565b60048103612523576125218d88888581811061250f5761250f6142b9565b9050602002810190611cf8919061453a565b505b50600101612436565b5082828080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929e9d5050505050505050505050505050565b60405163468721a760e01b81526000906001600160a01b0385169063468721a7906125a9908690859087906001906004016143a7565b6020604051808303816000875af11580156125c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ec9190614463565b9050806106e657604051632b3f6d1160e21b815260040160405180910390fd5b6060600061261c838501856146c5565b9250905061262d600233838861344e565b509392505050565b336000908152600360205260408120606091612653848601866146c5565b93509050610ae9828288613545565b606060006126728385018561470a565b3360009081526004602090815260408083206001600160e01b031990951683529390529190912080546001600160a01b031916905595945050505050565b60606000806126c184860186614681565b9450909250905060008260018111156126dc576126dc6146af565b1480156126f157506001600160e01b03198116155b156127185733600090815260056020526040902080546001600160a01b0319169055610ae9565b600182600181111561272c5761272c6146af565b036123c5573360009081526006602090815260408083206001600160e01b031985168452909152902080546001600160a01b0319169055610ae9565b60405163468721a760e01b81526000906001600160a01b0385169063468721a79061279e908690859087906001906004016143a7565b6020604051808303816000875af11580156127bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127e19190614463565b9050806106e657604080516001600160a01b0386168152600060208201526000805160206149c9833981519152910160405180910390a150505050565b336000908152600160205260409020546001600160a01b031680156128a45760405163529562a160e01b81523360048201526001600160a01b0384811660248301526044820184905282169063529562a19060640160006040518083038186803b15801561288b57600080fd5b505afa15801561289f573d6000803e3d6000fd5b505050505b505050565b60606128b685600061170e565b15612aac576128c984600160f81b61170e565b156128ec57823583016020810190356128e333838361361a565b92505050610741565b6128f784600061170e565b156129ab5760008036600061290c8787612cbc565b6040805160018082528183019092529498509296509094509250816020015b606081526020019060019003908161292b57905050945061298433858585858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061166592505050565b85600081518110612997576129976142b9565b602002602001018190525050505050610741565b6129bd846001600160f81b031961170e565b15612a875760006129d16014828587614041565b6129da9161406b565b60601c90503660006129ef8560148189614041565b604080516001808252818301909252929450909250816020015b6060815260200190600190039081612a09579050509350612a61338484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061369392505050565b84600081518110612a7457612a746142b9565b6020026020010181905250505050610741565b604051632e5bf3f960e21b81526001600160f81b0319851660048201526024016105bd565b612aba85600160f81b61170e565b15612c4057612acd84600160f81b61170e565b15612af25782358301602081019035612ae7338383613734565b935061074192505050565b612afd84600061170e565b15612b8a57600080366000612b128787612cbc565b6040805160018082528183019092529498509296509094509250816020015b6060815260200190600190039081612b3157905050945061298433858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506137b692505050565b612b9c846001600160f81b031961170e565b15612a87576000612bb06014828587614041565b612bb99161406b565b60601c9050366000612bce8560148189614041565b604080516001808252818301909252929450909250816020015b6060815260200190600190039081612be8579050509350612a61338484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061387692505050565b6040516308c3ee0360e11b81526001600160f81b0319861660048201526024016105bd565b6000546040516128a49185916001600160a01b0390911690612c8d9086908690602401614728565b60408051601f198184030181529190526020810180516001600160e01b0316633f707e6b60e01b179052612573565b6000803681612cce6014828789614041565b612cd79161406b565b60601c9350612cea603460148789614041565b612cf3916147d3565b9250612d028560348189614041565b949793965094505050565b6000546040516128a49185916001600160a01b0390911690612d359086908690602401614728565b60408051601f198184030181529190526020810180516001600160e01b0316632864481160e11b179052612768565b60405163468721a760e01b81526000906001600160a01b0386169063468721a790612d999087908790879087906004016143a7565b6020604051808303816000875af1158015612db8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ddc9190614463565b90508061187857604080516001600160a01b0387168152600060208201526000805160206149c9833981519152910160405180910390a15050505050565b606060006001600160a01b038416600114801590612e3f5750612e3d8585612ffc565b155b15612e6857604051637c84ecfb60e01b81526001600160a01b03851660048201526024016105bd565b82600003612e895760405163f725081760e01b815260040160405180910390fd5b826001600160401b03811115612ea157612ea1613f0c565b604051908082528060200260200182016040528015612eca578160200160208202803683370190505b506001600160a01b03808616600090815260208890526040812054929450911691505b6001600160a01b03821615801590612f0f57506001600160a01b038216600114155b8015612f1a57508381105b15612f745781838281518110612f3257612f326142b9565b6001600160a01b039283166020918202929092018101919091529281166000908152928790526040909220549091169080612f6c81614596565b915050612eed565b6001600160a01b038216600114612fac5782612f916001836145af565b81518110612fa157612fa16142b9565b602002602001015191505b80835250935093915050565b600060016001600160a01b038316148015906107415750506001600160a01b0390811660009081526020938452604080822093831682529290935291205416151590565b600060016001600160a01b038316148015906109d75750506001600160a01b03908116600090815260209290925260409091205416151590565b60008083600181111561304b5761304b6146af565b14801561306057506001600160e01b03198216155b156130805750336000908152600560205260409020546001600160a01b03165b6001836001811115613094576130946146af565b0361066357503360009081526006602090815260408083206001600160e01b0319851684529091529020546001600160a01b031692915050565b6060600080368181816130e561010089018961453a565b90925090506130f8600660008385614041565b613101916147f1565b60d01c9550613114600c60068385614041565b61311d916147f1565b60d01c945061312f81600c8185614041565b9350935050506000604051806101c001604052807f84aa190356f56b8c87825f54884392a9907c23ee0f8e1ea86336b763faf021bd60001b8152602001336001600160a01b0316815260200188602001358152602001888060400190613195919061453a565b6040516131a392919061481f565b60405190819003902081526020016131be60608a018a61453a565b6040516131cc92919061481f565b604051809103902081526020016131e289613936565b81526020016131f08961394b565b81526020018860a0013581526020016132088961395b565b815260200161321689613970565b815260200161322860e08a018a61453a565b60405161323692919061481f565b604051809103902081526020018665ffffffffffff1681526020018565ffffffffffff1681526020016132766f71727de22e5e9d8baf0edac6f37da03290565b6001600160a01b031690526101c08120909150601960f81b600160f81b61329b611600565b6040516001600160f81b031993841660208201529290911660218301526022820152604281018290526062016040516020818303038152906040529650505091939590929450565b600060d08265ffffffffffff16901b60a08465ffffffffffff16901b8561330b57600061330e565b60015b60ff161717949350505050565b60016000908152602082905260409020546001600160a01b031615613353576040516329e42f3360e11b815260040160405180910390fd5b60016000818152602092909252604090912080546001600160a01b0319169091179055565b6001600160a01b038116158061339757506001600160a01b0381166001145b156133c057604051637c84ecfb60e01b81526001600160a01b03821660048201526024016105bd565b6001600160a01b03818116600090815260208490526040902054161561340457604051631034f46960e21b81526001600160a01b03821660048201526024016105bd565b60016000818152602093909352604080842080546001600160a01b039485168087529286208054959091166001600160a01b03199586161790559190935280549091169091179055565b6001600160a01b038116158061346d57506001600160a01b0381166001145b1561349657604051637c84ecfb60e01b81526001600160a01b03831660048201526024016105bd565b6001600160a01b0382811660009081526020868152604080832087851684529091529020548116908216146134e957604051637c84ecfb60e01b81526001600160a01b03821660048201526024016105bd565b6001600160a01b039081166000908152602085815260408083209584168084528683528184208054968616855297835281842090845282529091208054939092166001600160a01b031993841617909155919091528154169055565b6001600160a01b038116158061356457506001600160a01b0381166001145b1561358d57604051637c84ecfb60e01b81526001600160a01b03831660048201526024016105bd565b6001600160a01b038281166000908152602085905260409020548116908216146135d557604051637c84ecfb60e01b81526001600160a01b03821660048201526024016105bd565b6001600160a01b0390811660008181526020949094526040808520805494841686529085208054949093166001600160a01b0319948516179092559092528154169055565b60008054604051606092916136749187916001600160a01b0316906136459088908890602401614728565b60408051601f198184030181529190526020810180516001600160e01b0316636108557360e01b179052613693565b90508080602001905181019061368a91906148dc565b95945050505050565b60606000846001600160a01b0316635229073f8560008660016040518563ffffffff1660e01b81526004016136cb94939291906143a7565b6000604051808303816000875af11580156136ea573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261371291908101906143f2565b925090508061262d57604051632b3f6d1160e21b815260040160405180910390fd5b60608060006137938660008054906101000a90046001600160a01b03168787604051602401613764929190614728565b60408051601f198184030181529190526020810180516001600160e01b0316639abb6e1760e01b179052613876565b9050808060200190518101906137a99190614910565b9097909650945050505050565b60606000856001600160a01b0316635229073f86868660006040518563ffffffff1660e01b81526004016137ed94939291906143a7565b6000604051808303816000875af115801561380c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261383491908101906143f2565b925090508061170557604080516001600160a01b0388168152600060208201526000805160206149c9833981519152910160405180910390a150949350505050565b60606000846001600160a01b0316635229073f8560008660016040518563ffffffff1660e01b81526004016138ae94939291906143a7565b6000604051808303816000875af11580156138cd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526138f591908101906143f2565b925090508061262d57604080516001600160a01b0387168152600060208201526000805160206149c9833981519152910160405180910390a1509392505050565b60006001600160801b03608083013516610663565b6000610663826080013560801c90565b60006001600160801b0360c083013516610663565b600060c082013560801c610663565b6001600160a01b038116811461399457600080fd5b50565b80356115fb8161397f565b60008083601f8401126139b457600080fd5b5081356001600160401b038111156139cb57600080fd5b60208301915083602082850101111561054e57600080fd5b600080600080606085870312156139f957600080fd5b843593506020850135613a0b8161397f565b925060408501356001600160401b03811115613a2657600080fd5b613a32878288016139a2565b95989497509550505050565b600080600060408486031215613a5357600080fd5b8335925060208401356001600160401b03811115613a7057600080fd5b613a7c868287016139a2565b9497909650939450505050565b600080600060608486031215613a9e57600080fd5b83356001600160401b03811115613ab457600080fd5b84016101208187031215613ac757600080fd5b95602085013595506040909401359392505050565b60008083601f840112613aee57600080fd5b5081356001600160401b03811115613b0557600080fd5b6020830191508360208260051b850101111561054e57600080fd5b600060608284031215613b3257600080fd5b50919050565b600080600080600080600080600060a08a8c031215613b5657600080fd5b89356001600160401b0380821115613b6d57600080fd5b613b798d838e01613adc565b909b50995060208c0135915080821115613b9257600080fd5b613b9e8d838e01613adc565b909950975060408c0135915080821115613bb757600080fd5b613bc38d838e01613adc565b909750955060608c0135915080821115613bdc57600080fd5b613be88d838e01613adc565b909550935060808c0135915080821115613c0157600080fd5b50613c0e8c828d01613b20565b9150509295985092959850929598565b60008060208385031215613c3157600080fd5b82356001600160401b03811115613c4757600080fd5b613c5385828601613adc565b90969095509350505050565b60008060408385031215613c7257600080fd5b8235613c7d8161397f565b946020939093013593505050565b604080825283519082018190526000906020906060840190828701845b82811015613ccd5781516001600160a01b031684529284019290840190600101613ca8565b5050506001600160a01b039490941660209390930192909252509092915050565b60005b83811015613d09578181015183820152602001613cf1565b50506000910152565b60008151808452613d2a816020860160208601613cee565b601f01601f19169290920160200192915050565b6020815260006109d76020830184613d12565b6001600160e01b03198116811461399457600080fd5b600060208284031215613d7957600080fd5b81356109d781613d51565b600060208284031215613d9657600080fd5b5035919050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b82811015613df457603f19888603018452613de2858351613d12565b94509285019290850190600101613dc6565b5092979650505050505050565b60008060408385031215613e1457600080fd5b8235613e1f8161397f565b91506020830135613e2f8161397f565b809150509250929050565b803560ff811681146115fb57600080fd5b60008060008060608587031215613e6157600080fd5b8435613e6c8161397f565b935060208501356001600160401b03811115613e8757600080fd5b613e9387828801613adc565b9094509250613ea6905060408601613e3a565b905092959194509250565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60018060a01b0385168152836020820152606060408201526000613f02606083018486613eb1565b9695505050505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715613f4a57613f4a613f0c565b604052919050565b60006001600160401b03821115613f6b57613f6b613f0c565b50601f01601f191660200190565b6000613f8c613f8784613f52565b613f22565b9050828152838383011115613fa057600080fd5b6109d7836020830184613cee565b600082601f830112613fbf57600080fd5b6109d783835160208501613f79565b600060208284031215613fe057600080fd5b81516001600160401b03811115613ff657600080fd5b61074184828501613fae565b8284823760609190911b6bffffffffffffffffffffffff19169101908152601401919050565b60006020828403121561403a57600080fd5b5051919050565b6000808585111561405157600080fd5b8386111561405e57600080fd5b5050820193919092039150565b6bffffffffffffffffffffffff1981358181169160148510156140985780818660140360031b1b83161692505b505092915050565b8481526060602082015260006140b96060830186613d12565b82810360408401526140cc818587613eb1565b979650505050505050565b6000602082840312156140e957600080fd5b81516109d781613d51565b6000808335601e1984360301811261410b57600080fd5b83016020810192503590506001600160401b0381111561412a57600080fd5b80360382131561054e57600080fd5b6040815261415a6040820161414d85613997565b6001600160a01b03169052565b60208301356060820152600061417360408501856140f4565b61012080608086015261418b61016086018385613eb1565b925061419a60608801886140f4565b9250603f19808786030160a08801526141b4858584613eb1565b9450608089013560c088015260a089013560e0880152610100935060c0890135848801526141e560e08a018a6140f4565b92508188870301848901526141fb868483613eb1565b95505061420a848a018a6140f4565b9450925080878603016101408801525050614226838383613eb1565b93505050508260208301529392505050565b60006020828403121561424a57600080fd5b81356109d78161397f565b6000808335601e1984360301811261426c57600080fd5b8301803591506001600160401b0382111561428657600080fd5b6020019150600581901b360382131561054e57600080fd5b6000602082840312156142b057600080fd5b6109d782613e3a565b634e487b7160e01b600052603260045260246000fd5b60008235603e198336030181126142e557600080fd5b9190910192915050565b8381526001600160a01b038316602082015260606040820181905260009061368a90830184613d12565b60006020828403121561432b57600080fd5b81516001600160401b0381111561434157600080fd5b8201601f8101841361435257600080fd5b61074184825160208401613f79565b64736166652d60d81b815260008251614381816005850160208701613cee565b6e2e657263373537392e76302e302e3160881b6005939091019283015250601401919050565b60018060a01b03851681528360208201526080604082015260006143ce6080830185613d12565b905060ff8316606083015295945050505050565b805180151581146115fb57600080fd5b6000806040838503121561440557600080fd5b61440e836143e2565b915060208301516001600160401b0381111561442957600080fd5b61443585828601613fae565b9150509250929050565b6001600160a01b038316815260406020820181905260009061074190830184613d12565b60006020828403121561447557600080fd5b6109d7826143e2565b8035600281106115fb57600080fd5b600080604083850312156144a057600080fd5b6144a98361447e565b91506020830135613e2f81613d51565b828152600082516144d1816020850160208701613cee565b919091016020019392505050565b60ff8416815260406020808301829052908201839052600090849060608401835b8681101561452e5783356145138161397f565b6001600160a01b031682529282019290820190600101614500565b50979650505050505050565b6000808335601e1984360301811261455157600080fd5b8301803591506001600160401b0382111561456b57600080fd5b60200191503681900382131561054e57600080fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016145a8576145a8614580565b5060010190565b8181038181111561066357610663614580565b600082601f8301126145d357600080fd5b81356145e1613f8782613f52565b8181528460208386010111156145f657600080fd5b816020850160208301376000918101602001919091529392505050565b60008060006060848603121561462857600080fd5b833561463381613d51565b925060208401356001600160f81b03198116811461465057600080fd5b915060408401356001600160401b0381111561466b57600080fd5b614677868287016145c2565b9150509250925092565b60008060006060848603121561469657600080fd5b61469f8461447e565b9250602084013561465081613d51565b634e487b7160e01b600052602160045260246000fd5b600080604083850312156146d857600080fd5b82356146e38161397f565b915060208301356001600160401b038111156146fe57600080fd5b614435858286016145c2565b6000806040838503121561471d57600080fd5b82356146e381613d51565b60208082528181018390526000906040808401600586901b850182018785805b898110156147c457888403603f190185528235368c9003605e1901811261476d578283fd5b8b016060813561477c8161397f565b6001600160a01b03168652818901358987015261479b888301836140f4565b925081898801526147af8288018483613eb1565b978a0197965050509287019250600101614748565b50919998505050505050505050565b8035602083101561066357600019602084900360031b1b1692915050565b6001600160d01b031981358181169160068510156140985760069490940360031b84901b1690921692915050565b8183823760009101908152919050565b60006001600160401b0382111561484857614848613f0c565b5060051b60200190565b600082601f83011261486357600080fd5b81516020614873613f878361482f565b82815260059290921b8401810191818101908684111561489257600080fd5b8286015b848110156148d15780516001600160401b038111156148b55760008081fd5b6148c38986838b0101613fae565b845250918301918301614896565b509695505050505050565b6000602082840312156148ee57600080fd5b81516001600160401b0381111561490457600080fd5b61074184828501614852565b6000806040838503121561492357600080fd5b82516001600160401b038082111561493a57600080fd5b818501915085601f83011261494e57600080fd5b8151602061495e613f878361482f565b82815260059290921b8401810191818101908984111561497d57600080fd5b948201945b838610156149a257614993866143e2565b82529482019490820190614982565b918801519196509093505050808211156149bb57600080fd5b506144358582860161485256feb8bc84bd77f5eb08210b8eb20fd63b3ec6a7992d277ab94663bae0e066f792aca26469706673582212204c1b68f6eb53965f3e290e9e6a21e9c80395a1ac0fce6394aa58289d799e181864736f6c634300081900336080604052348015600f57600080fd5b506109b98061001f6000396000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c80636a2216571161005b5780636a221657146100df57806378272525146100f25780639517e29f146101055780639abb6e171461011857600080fd5b80633f707e6b1461008257806350c890221461009757806361085573146100bf575b600080fd5b6100956100903660046105c9565b610139565b005b6100aa6100a53660046105c9565b6101a3565b60405190151581526020015b60405180910390f35b6100d26100cd3660046105c9565b610212565b6040516100b691906106c6565b6100956100ed366004610712565b6102cc565b6100956101003660046107d4565b6102ef565b6100956101133660046107d4565b610398565b61012b6101263660046105c9565b610437565b6040516100b692919061085b565b8060005b8181101561019d5736848483818110610158576101586108b5565b905060200281019061016a91906108cb565b905061019361017c60208301836108eb565b602083013561018e6040850185610906565b610561565b505060010161013d565b50505050565b600081815b8181101561020a57368585838181106101c3576101c36108b5565b90506020028101906101d591906108cb565b90506101fe6101e760208301836108eb565b60208301356101f96040850185610906565b610597565b509350506001016101a8565b505092915050565b6060818067ffffffffffffffff81111561022e5761022e6106fc565b60405190808252806020026020018201604052801561026157816020015b606081526020019060019003908161024c5790505b50915060005b8181101561020a5736858583818110610282576102826108b5565b905060200281019061029491906108cb565b90506102a661017c60208301836108eb565b8483815181106102b8576102b86108b5565b602090810291909101015250600101610267565b604051600080835160208501865afa3d6000833e80156102ea573d82f35b503d81fd5b604051638a91b0e360e01b81526001600160a01b03841690638a91b0e39061031d9085908590600401610954565b600060405180830381600087803b15801561033757600080fd5b505af115801561034b573d6000803e3d6000fd5b5050604080518781526001600160a01b03871660208201527f341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e93500190505b60405180910390a150505050565b6040516306d61fe760e41b81526001600160a01b03841690636d61fe70906103c69085908590600401610954565b600060405180830381600087803b1580156103e057600080fd5b505af11580156103f4573d6000803e3d6000fd5b5050604080518781526001600160a01b03871660208201527fd21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef123935001905061038a565b606080828067ffffffffffffffff811115610454576104546106fc565b60405190808252806020026020018201604052801561048757816020015b60608152602001906001900390816104725790505b5091508067ffffffffffffffff8111156104a3576104a36106fc565b6040519080825280602002602001820160405280156104cc578160200160208202803683370190505b50925060005b8181101561055857368686838181106104ed576104ed6108b5565b90506020028101906104ff91906108cb565b90506105116101e760208301836108eb565b868481518110610523576105236108b5565b6020026020010186858151811061053c5761053c6108b5565b60209081029190910101919091529015159052506001016104d2565b50509250929050565b60405181838237600038838387895af161057e573d6000823e3d81fd5b3d8152602081013d6000823e3d01604052949350505050565b604051600090828482376000388483888a5af11591503d8152602081013d6000823e3d81016040525094509492505050565b600080602083850312156105dc57600080fd5b823567ffffffffffffffff808211156105f457600080fd5b818501915085601f83011261060857600080fd5b81358181111561061757600080fd5b8660208260051b850101111561062c57600080fd5b60209290920196919550909350505050565b600082825180855260208086019550808260051b8401018186016000805b858110156106b857601f1980888603018b5283518051808752845b81811015610692578281018901518882018a01528801610677565b5086810188018590529b87019b601f01909116909401850193509184019160010161065c565b509198975050505050505050565b6020815260006106d9602083018461063e565b9392505050565b80356001600160a01b03811681146106f757600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561072557600080fd5b61072e836106e0565b9150602083013567ffffffffffffffff8082111561074b57600080fd5b818501915085601f83011261075f57600080fd5b813581811115610771576107716106fc565b604051601f8201601f19908116603f01168101908382118183101715610799576107996106fc565b816040528281528860208487010111156107b257600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b600080600080606085870312156107ea57600080fd5b843593506107fa602086016106e0565b9250604085013567ffffffffffffffff8082111561081757600080fd5b818701915087601f83011261082b57600080fd5b81358181111561083a57600080fd5b88602082850101111561084c57600080fd5b95989497505060200194505050565b604080825283519082018190526000906020906060840190828701845b82811015610896578151151584529284019290840190600101610878565b50505083810360208501526108ab818661063e565b9695505050505050565b634e487b7160e01b600052603260045260246000fd5b60008235605e198336030181126108e157600080fd5b9190910192915050565b6000602082840312156108fd57600080fd5b6106d9826106e0565b6000808335601e1984360301811261091d57600080fd5b83018035915067ffffffffffffffff82111561093857600080fd5b60200191503681900382131561094d57600080fd5b9250929050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f1916010191905056fea2646970667358221220c249fc39b8532ba357c2c2ee22298a8dea37b717dd88be3754b2eeaaa5e1252664736f6c63430008190033", + "nonce": "0x42", + "chainId": "0xaa36a7" + }, + "additionalContracts": [ + { + "transactionType": "CREATE", + "address": "0x8f942a2377822f6164ea110959f3abb511222b6a", + "initCode": "0x6080604052348015600f57600080fd5b506109b98061001f6000396000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c80636a2216571161005b5780636a221657146100df57806378272525146100f25780639517e29f146101055780639abb6e171461011857600080fd5b80633f707e6b1461008257806350c890221461009757806361085573146100bf575b600080fd5b6100956100903660046105c9565b610139565b005b6100aa6100a53660046105c9565b6101a3565b60405190151581526020015b60405180910390f35b6100d26100cd3660046105c9565b610212565b6040516100b691906106c6565b6100956100ed366004610712565b6102cc565b6100956101003660046107d4565b6102ef565b6100956101133660046107d4565b610398565b61012b6101263660046105c9565b610437565b6040516100b692919061085b565b8060005b8181101561019d5736848483818110610158576101586108b5565b905060200281019061016a91906108cb565b905061019361017c60208301836108eb565b602083013561018e6040850185610906565b610561565b505060010161013d565b50505050565b600081815b8181101561020a57368585838181106101c3576101c36108b5565b90506020028101906101d591906108cb565b90506101fe6101e760208301836108eb565b60208301356101f96040850185610906565b610597565b509350506001016101a8565b505092915050565b6060818067ffffffffffffffff81111561022e5761022e6106fc565b60405190808252806020026020018201604052801561026157816020015b606081526020019060019003908161024c5790505b50915060005b8181101561020a5736858583818110610282576102826108b5565b905060200281019061029491906108cb565b90506102a661017c60208301836108eb565b8483815181106102b8576102b86108b5565b602090810291909101015250600101610267565b604051600080835160208501865afa3d6000833e80156102ea573d82f35b503d81fd5b604051638a91b0e360e01b81526001600160a01b03841690638a91b0e39061031d9085908590600401610954565b600060405180830381600087803b15801561033757600080fd5b505af115801561034b573d6000803e3d6000fd5b5050604080518781526001600160a01b03871660208201527f341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e93500190505b60405180910390a150505050565b6040516306d61fe760e41b81526001600160a01b03841690636d61fe70906103c69085908590600401610954565b600060405180830381600087803b1580156103e057600080fd5b505af11580156103f4573d6000803e3d6000fd5b5050604080518781526001600160a01b03871660208201527fd21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef123935001905061038a565b606080828067ffffffffffffffff811115610454576104546106fc565b60405190808252806020026020018201604052801561048757816020015b60608152602001906001900390816104725790505b5091508067ffffffffffffffff8111156104a3576104a36106fc565b6040519080825280602002602001820160405280156104cc578160200160208202803683370190505b50925060005b8181101561055857368686838181106104ed576104ed6108b5565b90506020028101906104ff91906108cb565b90506105116101e760208301836108eb565b868481518110610523576105236108b5565b6020026020010186858151811061053c5761053c6108b5565b60209081029190910101919091529015159052506001016104d2565b50509250929050565b60405181838237600038838387895af161057e573d6000823e3d81fd5b3d8152602081013d6000823e3d01604052949350505050565b604051600090828482376000388483888a5af11591503d8152602081013d6000823e3d81016040525094509492505050565b600080602083850312156105dc57600080fd5b823567ffffffffffffffff808211156105f457600080fd5b818501915085601f83011261060857600080fd5b81358181111561061757600080fd5b8660208260051b850101111561062c57600080fd5b60209290920196919550909350505050565b600082825180855260208086019550808260051b8401018186016000805b858110156106b857601f1980888603018b5283518051808752845b81811015610692578281018901518882018a01528801610677565b5086810188018590529b87019b601f01909116909401850193509184019160010161065c565b509198975050505050505050565b6020815260006106d9602083018461063e565b9392505050565b80356001600160a01b03811681146106f757600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561072557600080fd5b61072e836106e0565b9150602083013567ffffffffffffffff8082111561074b57600080fd5b818501915085601f83011261075f57600080fd5b813581811115610771576107716106fc565b604051601f8201601f19908116603f01168101908382118183101715610799576107996106fc565b816040528281528860208487010111156107b257600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b600080600080606085870312156107ea57600080fd5b843593506107fa602086016106e0565b9250604085013567ffffffffffffffff8082111561081757600080fd5b818701915087601f83011261082b57600080fd5b81358181111561083a57600080fd5b88602082850101111561084c57600080fd5b95989497505060200194505050565b604080825283519082018190526000906020906060840190828701845b82811015610896578151151584529284019290840190600101610878565b50505083810360208501526108ab818661063e565b9695505050505050565b634e487b7160e01b600052603260045260246000fd5b60008235605e198336030181126108e157600080fd5b9190910192915050565b6000602082840312156108fd57600080fd5b6106d9826106e0565b6000808335601e1984360301811261091d57600080fd5b83018035915067ffffffffffffffff82111561093857600080fd5b60200191503681900382131561094d57600080fd5b9250929050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f1916010191905056fea2646970667358221220c249fc39b8532ba357c2c2ee22298a8dea37b717dd88be3754b2eeaaa5e1252664736f6c63430008190033" + } + ], + "isFixedGasLimit": false + }, + { + "hash": "0x712bc66f8e220d2e1b66ab411af1b28676a89a25c271448467b8aaa10cee0110", + "transactionType": "CREATE2", + "contractName": "Safe7579Launchpad", + "contractAddress": "0xbd3b9ba8162b23bcb0373e265cb07127e5b1b644", + "function": null, + "arguments": [ + "0x0000000071727De22E5E9d8BAf0edAc6f37da032", + "0xe0cde9239d16bEf05e62Bbf7aA93e420f464c826" + ], + "transaction": { + "from": "0x8749313f626b100b822d573c71dfffdaca383032", + "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", + "gas": "0x1ff99e", + "value": "0x0", + "input": "0x000000000000000000000000000000000000000000000000000000000000000060e060405234801561001057600080fd5b506040516119ec3803806119ec83398101604081905261002f91610089565b6001600160a01b03821661005657604051632039d3c960e01b815260040160405180910390fd5b306080526001600160a01b0391821660a0521660c0526100c3565b6001600160a01b038116811461008657600080fd5b50565b6000806040838503121561009c57600080fd5b82516100a781610071565b60208401519092506100b881610071565b809150509250929050565b60805160a05160c0516118e061010c6000396000818160a801526102e901526000818160f90152818161041701526109850152600081816103c2015261075401526118e06000f3fe60806040526004361061008a5760003560e01c80634fff40e1116100595780634fff40e11461016b578063663c87d81461018b578063928107f9146101ab578063c67e2d2a146101cb578063d9ed0e8f146101ed57600080fd5b806306433b1b14610096578063137e051e146100e757806315cca6381461011b57806319822f7c1461013d57600080fd5b3661009157005b600080fd5b3480156100a257600080fd5b506100ca7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100f357600080fd5b506100ca7f000000000000000000000000000000000000000000000000000000000000000081565b34801561012757600080fd5b5061013b610136366004610bdc565b61020d565b005b34801561014957600080fd5b5061015d610158366004610cc0565b6103bc565b6040519081526020016100de565b34801561017757600080fd5b5061013b610186366004610d13565b61074f565b34801561019757600080fd5b506100ca6101a6366004610e9b565b610849565b3480156101b757600080fd5b5061015d6101c6366004611092565b610928565b3480156101d757600080fd5b5060008051602061188b8339815191525461015d565b3480156101f957600080fd5b5061013b6102083660046111a8565b61097a565b33301461022d57604051630a57d61d60e01b815260040160405180910390fd5b60405163610b592560e01b81526001600160a01b038b166004820152309063610b592590602401600060405180830381600087803b15801561026e57600080fd5b505af1158015610282573d6000803e3d6000fd5b5050604080516000808252602082019092526001600160a01b038e16935063540fb4f99250906102d5565b6040805180820190915260008152606060208201528152602001906001900390816102ad5790505b508b8b8b8b8b8b60405180606001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020018d8d8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050509082525060ff8c166020909101526040516001600160e01b031960e08b901b16815261037e9897969594939291906004016113f7565b600060405180830381600087803b15801561039857600080fd5b505af11580156103ac573d6000803e3d6000fd5b5050505050505050505050505050565b600080547f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161461040c576040516308e3edd160e41b815260040160405180910390fd5b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461045557604051632039d3c960e01b815260040160405180910390fd5b6104626060850185611497565b610471916004916000916114dd565b61047a91611507565b6001600160e01b03191663d9ed0e8f60e01b146104aa5760405163c3d40f7760e01b815260040160405180910390fd5b60006104b96060860186611497565b6104c79160049082906114dd565b8101906104d49190611092565b90506104ec60008051602061188b8339815191525490565b6104f582610928565b146105135760405163278328b160e21b815260040160405180910390fd5b60a081015160c0820151604051636a5e151560e01b81526020880135606081901c9390926001600160a01b0390911691636a5e15159161055591600401611537565b600060405180830381600087803b15801561056f57600080fd5b505af1158015610583573d6000803e3d6000fd5b50505060c08401515160009150815b818110156106a95760008660c0015182815181106105b2576105b261154a565b6020026020010151600001519050806001600160a01b0316636d61fe708860c0015184815181106105e5576105e561154a565b6020026020010151602001516040518263ffffffff1660e01b815260040161060d9190611560565b600060405180830381600087803b15801561062757600080fd5b505af115801561063b573d6000803e3d6000fd5b505060408051600181526001600160a01b03851660208201527fd21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef123935001905060405180910390a1856001600160a01b0316816001600160a01b0316036106a057600193505b50600101610592565b50816106bd57600195505050505050610748565b604051639700320360e01b81526001600160a01b038516906397003203906106eb908c908c90600401611573565b6020604051808303816000875af115801561070a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061072e9190611672565b95508615610742576000806000808a335af1505b50505050505b9392505050565b6000547f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161461079e576040516308e3edd160e41b815260040160405180910390fd5b6107b48460008051602061188b83398151915255565b6001600160a01b03831615610843576000836001600160a01b031683836040516107df92919061168b565b600060405180830381855af49150503d806000811461081a576040519150601f19603f3d011682016040523d82523d6000602084013e61081f565b606091505b505090508061084157604051631f57fed560e31b815260040160405180910390fd5b505b50505050565b600081805190602001208360405160200161086e929190918252602082015260400190565b60405160208183030381529060405280519060200120925060ff60f81b858486896001600160a01b03166040516020016108a992919061169b565b6040516020818303038152906040528051906020012060405160200161090694939291906001600160f81b031994909416845260609290921b6bffffffffffffffffffffffff191660018401526015830152603582015260550190565b60408051601f1981840301815291905280516020909101209695505050505050565b80516020808301516040808501516060860151608087015160a088015160c0890151945160009861095d9890979691016116bd565b604051602081830303815290604052805190602001209050919050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146109c357604051632039d3c960e01b815260040160405180910390fd5b6109d0602082018261172a565b600080546001600160a01b0319166001600160a01b03929092169190911790553063b63e800d610a036020840184611747565b6040850135610a18608087016060880161172a565b610a256080880188611497565b610a3560c08a0160a08b0161172a565b60008060006040518b63ffffffff1660e01b8152600401610a5f9a99989796959493929190611790565b600060405180830381600087803b158015610a7957600080fd5b505af1158015610a8d573d6000803e3d6000fd5b5050600060008051602061188b8339815191525550610aa99050565b600080610abc60c0840160a0850161172a565b6001600160a01b0316610ad260e0850185611497565b30604051602001610ae593929190611848565b60408051601f1981840301815290829052610aff9161186e565b6000604051808303816000865af19150503d8060008114610b3c576040519150601f19603f3d011682016040523d82523d6000602084013e610b41565b606091505b509150915081610b5357805160208201fd5b505050565b6001600160a01b0381168114610b6d57600080fd5b50565b8035610b7b81610b58565b919050565b60008083601f840112610b9257600080fd5b5081356001600160401b03811115610ba957600080fd5b6020830191508360208260051b8501011115610bc457600080fd5b9250929050565b803560ff81168114610b7b57600080fd5b60008060008060008060008060008060c08b8d031215610bfb57600080fd5b610c048b610b70565b995060208b01356001600160401b0380821115610c2057600080fd5b610c2c8e838f01610b80565b909b50995060408d0135915080821115610c4557600080fd5b610c518e838f01610b80565b909950975060608d0135915080821115610c6a57600080fd5b610c768e838f01610b80565b909750955060808d0135915080821115610c8f57600080fd5b50610c9c8d828e01610b80565b9094509250610caf905060a08c01610bcb565b90509295989b9194979a5092959850565b600080600060608486031215610cd557600080fd5b83356001600160401b03811115610ceb57600080fd5b84016101208187031215610cfe57600080fd5b95602085013595506040909401359392505050565b60008060008060608587031215610d2957600080fd5b843593506020850135610d3b81610b58565b925060408501356001600160401b0380821115610d5757600080fd5b818701915087601f830112610d6b57600080fd5b813581811115610d7a57600080fd5b886020828501011115610d8c57600080fd5b95989497505060200194505050565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715610dd357610dd3610d9b565b60405290565b60405161010081016001600160401b0381118282101715610dd357610dd3610d9b565b604051601f8201601f191681016001600160401b0381118282101715610e2457610e24610d9b565b604052919050565b600082601f830112610e3d57600080fd5b81356001600160401b03811115610e5657610e56610d9b565b610e69601f8201601f1916602001610dfc565b818152846020838601011115610e7e57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a08688031215610eb357600080fd5b8535610ebe81610b58565b94506020860135610ece81610b58565b935060408601356001600160401b0380821115610eea57600080fd5b610ef689838a01610e2c565b9450606088013593506080880135915080821115610f1357600080fd5b50610f2088828901610e2c565b9150509295509295909350565b60006001600160401b03821115610f4657610f46610d9b565b5060051b60200190565b600082601f830112610f6157600080fd5b81356020610f76610f7183610f2d565b610dfc565b8083825260208201915060208460051b870101935086841115610f9857600080fd5b602086015b84811015610fbd578035610fb081610b58565b8352918301918301610f9d565b509695505050505050565b600082601f830112610fd957600080fd5b81356020610fe9610f7183610f2d565b82815260059290921b8401810191818101908684111561100857600080fd5b8286015b84811015610fbd5780356001600160401b038082111561102c5760008081fd5b908801906040828b03601f19018113156110465760008081fd5b61104e610db1565b8784013561105b81610b58565b81529083013590828211156110705760008081fd5b61107e8c8984870101610e2c565b81890152865250505091830191830161100c565b6000602082840312156110a457600080fd5b81356001600160401b03808211156110bb57600080fd5b9083019061010082860312156110d057600080fd5b6110d8610dd9565b6110e183610b70565b81526020830135828111156110f557600080fd5b61110187828601610f50565b6020830152506040830135604082015261111d60608401610b70565b606082015260808301358281111561113457600080fd5b61114087828601610e2c565b60808301525061115260a08401610b70565b60a082015260c08301358281111561116957600080fd5b61117587828601610fc8565b60c08301525060e08301358281111561118d57600080fd5b61119987828601610e2c565b60e08301525095945050505050565b6000602082840312156111ba57600080fd5b81356001600160401b038111156111d057600080fd5b8201610100818503121561074857600080fd5b60005b838110156111fe5781810151838201526020016111e6565b50506000910152565b6000815180845261121f8160208601602086016111e3565b601f01601f19169290920160200192915050565b600082825180855260208086019550808260051b84010181860160005b8481101561129b57858303601f19018952815180516001600160a01b03168452840151604085850181905261128781860183611207565b9a86019a9450505090830190600101611250565b5090979650505050505050565b6000808335601e198436030181126112bf57600080fd5b83016020810192503590506001600160401b038111156112de57600080fd5b803603821315610bc457600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60008383855260208086019550808560051b830101846000805b888110156113a457858403601f19018a52823536899003603e19018112611355578283fd5b88016040813561136481610b58565b6001600160a01b0316865261137b828801836112a8565b9250818888015261138f82880184836112ed565b9c88019c965050509285019250600101611330565b509198975050505050505050565b60008151808452602080850194506020840160005b838110156113ec5781516001600160a01b0316875295820195908201906001016113c7565b509495945050505050565b60a08152600061140a60a083018b611233565b828103602084015261141d818a8c611316565b9050828103604084015261143281888a611316565b90508281036060840152611447818688611316565b9050828103608084015260018060a01b03845116815260208401516060602083015261147660608301826113b2565b905060ff604086015116604083015280925050509998505050505050505050565b6000808335601e198436030181126114ae57600080fd5b8301803591506001600160401b038211156114c857600080fd5b602001915036819003821315610bc457600080fd5b600080858511156114ed57600080fd5b838611156114fa57600080fd5b5050820193919092039150565b6001600160e01b0319813581811691600485101561152f5780818660040360031b1b83161692505b505092915050565b6020815260006107486020830184611233565b634e487b7160e01b600052603260045260246000fd5b6020815260006107486020830184611207565b604081526115946040820161158785610b70565b6001600160a01b03169052565b6020830135606082015260006115ad60408501856112a8565b6101208060808601526115c5610160860183856112ed565b92506115d460608801886112a8565b9250603f19808786030160a08801526115ee8585846112ed565b9450608089013560c088015260a089013560e0880152610100935060c08901358488015261161f60e08a018a6112a8565b92508188870301848901526116358684836112ed565b955050611644848a018a6112a8565b94509250808786030161014088015250506116608383836112ed565b93505050508260208301529392505050565b60006020828403121561168457600080fd5b5051919050565b8183823760009101908152919050565b600083516116ad8184602088016111e3565b9190910191825250602001919050565b600060018060a01b03808a16835260e060208401526116df60e084018a6113b2565b886040850152818816606085015283810360808501526116ff8188611207565b905081861660a085015283810360c085015261171b8186611233565b9b9a5050505050505050505050565b60006020828403121561173c57600080fd5b813561074881610b58565b6000808335601e1984360301811261175e57600080fd5b8301803591506001600160401b0382111561177857600080fd5b6020019150600581901b3603821315610bc457600080fd5b61010080825281018a9052600061012082018c825b8d8110156117d65781356117b881610b58565b6001600160a01b0316835260209283019291909101906001016117a5565b50508a60208401526117f3604084018b6001600160a01b03169052565b828103606084015261180681898b6112ed565b91505061181e60808301876001600160a01b03169052565b6001600160a01b03851660a08301528360c083015261171b60e08301846001600160a01b03169052565b8284823760609190911b6bffffffffffffffffffffffff19169101908152601401919050565b600082516118808184602087016111e3565b919091019291505056fe982e06ee6a56dfc0f1ac189a5d23506361ca0a3ce45a9c7b8d33d65d43746a24a2646970667358221220c1919b1e1e9acac581cfa9d50a4228c3505e3042d626f6d2d2bd2e35aba05bb664736f6c634300081900330000000000000000000000000000000071727de22e5e9d8baf0edac6f37da032000000000000000000000000e0cde9239d16bef05e62bbf7aa93e420f464c826", + "nonce": "0x43", + "chainId": "0xaa36a7" + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "status": "0x1", + "cumulativeGasUsed": "0x13a07ae", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0xadee694915caabe82504b2d1afe5144199b8e1dca581228940b9fdf8966bdd53", + "transactionIndex": "0x3c", + "blockHash": "0x592afb04c687353a664e12162c0469af8fa126363396d4f43113de3b057ea2a1", + "blockNumber": "0x598d1b", + "gasUsed": "0x488ee5", + "effectiveGasPrice": "0x138fe5ea5", + "from": "0x8749313f626b100b822d573c71dfffdaca383032", + "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", + "contractAddress": "0xbaca6f74a5549368568f387fd989c279f940f1a5" + }, + { + "status": "0x1", + "cumulativeGasUsed": "0x15361eb", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0x712bc66f8e220d2e1b66ab411af1b28676a89a25c271448467b8aaa10cee0110", + "transactionIndex": "0x3e", + "blockHash": "0x592afb04c687353a664e12162c0469af8fa126363396d4f43113de3b057ea2a1", + "blockNumber": "0x598d1b", + "gasUsed": "0x15dea5", + "effectiveGasPrice": "0x138fe5ea5", + "from": "0x8749313f626b100b822d573c71dfffdaca383032", + "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", + "contractAddress": "0xbd3b9ba8162b23bcb0373e265cb07127e5b1b644" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1715275639, + "chain": 11155111, + "commit": "7ac113c" +} \ No newline at end of file diff --git a/accounts/safe7579/script/Deploy.s.sol b/accounts/safe7579/script/Deploy.s.sol new file mode 100644 index 00000000..a76f4b73 --- /dev/null +++ b/accounts/safe7579/script/Deploy.s.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import { Script } from "forge-std/Script.sol"; +import { Safe7579 } from "src/Safe7579.sol"; +import { Safe7579Launchpad } from "src/Safe7579Launchpad.sol"; +import { IERC7484 } from "src/interfaces/IERC7484.sol"; + +/** + * @title Deploy + * @author @kopy-kat + */ +contract DeployScript is Script { + function run() public { + bytes32 salt = bytes32(uint256(0)); + + address entryPoint = address(0x0000000071727De22E5E9d8BAf0edAc6f37da032); + IERC7484 registry = IERC7484(0xe0cde9239d16bEf05e62Bbf7aA93e420f464c826); + + vm.startBroadcast(vm.envUint("PK")); + + new Safe7579{ salt: salt }(); + new Safe7579Launchpad{ salt: salt }(entryPoint, registry); + + vm.stopBroadcast(); + } +}