From 9f7b0a83a62e7367d67ccd5c9765caae58010dae Mon Sep 17 00:00:00 2001 From: cpb8010 Date: Tue, 19 Nov 2024 19:09:42 -0800 Subject: [PATCH] Revert "chore: rename to reflect SSO interface (#185)" This reverts commit 58126c77c668056af59ab996395ad10f06e5c8ac. --- packages/auth-server/stores/client.ts | 4 +- packages/contracts/src/AAFactory.sol | 16 +- .../src/{SsoAccount.sol => ClaveAccount.sol} | 10 +- packages/contracts/src/ERC7579Account.sol | 289 ++++++++++++++++++ packages/contracts/src/helpers/Execution.sol | 152 +++++++++ .../{ISsoAccount.sol => IClaveAccount.sol} | 8 +- .../src/interfaces/IERC7579Account.sol | 112 +++++++ .../src/interfaces/IERC7579Validator.sol | 26 ++ .../{SsoStorage.sol => ClaveStorage.sol} | 7 +- .../contracts/src/libraries/ERC7579Mode.sol | 1 + packages/contracts/src/libraries/Errors.sol | 2 +- .../contracts/src/managers/HookManager.sol | 8 +- .../contracts/src/managers/ModuleManager.sol | 34 ++- .../contracts/src/managers/OwnerManager.sol | 8 +- .../src/managers/ValidatorManager.sol | 8 +- .../src/test/ExampleAuthServerPaymaster.sol | 4 +- packages/contracts/test/BasicTest.ts | 8 +- packages/contracts/test/SessionKeyTest.ts | 12 +- packages/contracts/test/utils.ts | 11 +- packages/sdk/src/abi/Factory.ts | 2 +- packages/sdk/src/client/actions/account.ts | 2 +- 21 files changed, 660 insertions(+), 64 deletions(-) rename packages/contracts/src/{SsoAccount.sol => ClaveAccount.sol} (97%) create mode 100644 packages/contracts/src/ERC7579Account.sol create mode 100644 packages/contracts/src/helpers/Execution.sol rename packages/contracts/src/interfaces/{ISsoAccount.sol => IClaveAccount.sol} (90%) create mode 100644 packages/contracts/src/interfaces/IERC7579Account.sol create mode 100644 packages/contracts/src/interfaces/IERC7579Validator.sol rename packages/contracts/src/libraries/{SsoStorage.sol => ClaveStorage.sol} (89%) diff --git a/packages/auth-server/stores/client.ts b/packages/auth-server/stores/client.ts index fe2b8a84..b258c17d 100644 --- a/packages/auth-server/stores/client.ts +++ b/packages/auth-server/stores/client.ts @@ -28,9 +28,9 @@ export const contractsByChain: Record = { }, [zksyncInMemoryNode.id]: { session: "0x8543528a4561E3a5EC7d51Bfd3776457b0E7b7dc", - passkey: "0x975df0c7f5CB728ae9F96480491Ec5d1E17296f4", + passkey: "0x07734BA326b6AD13BfC0115b0903EB14268F1617", accountFactory: "0xaAF5f437fB0524492886fbA64D703df15BF619AE", - accountPaymaster: "0x351cB880A2B9E1Cf3060ea58Ec5280CBCe87579A", + accountPaymaster: "0x2879853afd8d066ca66e224A8E85621aC43d6F59", }, }; diff --git a/packages/contracts/src/AAFactory.sol b/packages/contracts/src/AAFactory.sol index 442b2dca..ed24634d 100644 --- a/packages/contracts/src/AAFactory.sol +++ b/packages/contracts/src/AAFactory.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.24; import "@matterlabs/zksync-contracts/l2/system-contracts/Constants.sol"; import "@matterlabs/zksync-contracts/l2/system-contracts/libraries/SystemContractsCaller.sol"; -import { ISsoAccount } from "./interfaces/ISsoAccount.sol"; +import { IClaveAccount } from "./interfaces/IClaveAccount.sol"; import { UpgradeableBeacon } from "./UpgradeableBeacon.sol"; import "./helpers/Logger.sol"; @@ -19,17 +19,9 @@ contract AAFactory is UpgradeableBeacon { beaconProxyBytecodeHash = _beaconProxyBytecodeHash; } - function deployProxy7579Account( - bytes32 salt, - string calldata uniqueAccountId, - bytes[] calldata initialValidators, - bytes[] calldata initialModules, - address[] calldata initialK1Owners - ) external returns (address) { - return this.deployProxySsoAccount(salt, uniqueAccountId, initialValidators, initialModules, initialK1Owners); - } + function addNewUniqueId(bytes32 uniqueAccountId) external {} - function deployProxySsoAccount( + function deployProxy7579Account( bytes32 salt, string calldata uniqueAccountId, bytes[] calldata initialValidators, @@ -58,7 +50,7 @@ contract AAFactory is UpgradeableBeacon { Logger.logAddress(accountAddress); // add session-key/spend-limit module (similar code) - ISsoAccount(accountAddress).initialize(initialValidators, initialModules, initialK1Owners); + IClaveAccount(accountAddress).initialize(initialValidators, initialModules, initialK1Owners); if (accountMappings[uniqueAccountId] != address(0)) { revert("Account already exists"); diff --git a/packages/contracts/src/SsoAccount.sol b/packages/contracts/src/ClaveAccount.sol similarity index 97% rename from packages/contracts/src/SsoAccount.sol rename to packages/contracts/src/ClaveAccount.sol index 0fb78d04..f98414c0 100644 --- a/packages/contracts/src/SsoAccount.sol +++ b/packages/contracts/src/ClaveAccount.sol @@ -23,7 +23,7 @@ import { ModeCode } from "./libraries/ERC7579Mode.sol"; import { ERC1271Handler } from "./handlers/ERC1271Handler.sol"; import { BatchCaller } from "./batch/BatchCaller.sol"; -import { ISsoAccount } from "./interfaces/ISsoAccount.sol"; +import { IClaveAccount } from "./interfaces/IClaveAccount.sol"; import "./helpers/Logger.sol"; @@ -32,7 +32,7 @@ import "./helpers/Logger.sol"; * @author https://getclave.io */ -contract SsoAccount is +contract ClaveAccount is Initializable, UpgradeManager, HookManager, @@ -40,7 +40,7 @@ contract SsoAccount is ERC1271Handler, TokenCallbackHandler, BatchCaller, - ISsoAccount + IClaveAccount { // Helper library for the Transaction struct using TransactionHelper for Transaction; @@ -201,9 +201,9 @@ contract SsoAccount is transaction.processPaymasterInput(); } - /// @dev type(ISsoAccount).interfaceId indicates SSO accounts + /// @dev type(IClave).interfaceId indicates Clave accounts function supportsInterface(bytes4 interfaceId) public view override(IERC165, TokenCallbackHandler) returns (bool) { - return interfaceId == type(ISsoAccount).interfaceId || super.supportsInterface(interfaceId); + return interfaceId == type(IClaveAccount).interfaceId || super.supportsInterface(interfaceId); } function _validateTransaction( diff --git a/packages/contracts/src/ERC7579Account.sol b/packages/contracts/src/ERC7579Account.sol new file mode 100644 index 00000000..0ea9de20 --- /dev/null +++ b/packages/contracts/src/ERC7579Account.sol @@ -0,0 +1,289 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import "./libraries/ERC7579Mode.sol"; + +import "./interfaces/IERC7579Module.sol"; +import "./interfaces/IERC7579Validator.sol"; + +import { BOOTLOADER_FORMAL_ADDRESS } from "@matterlabs/zksync-contracts/l2/system-contracts/Constants.sol"; +import { IAccount } from "@matterlabs/zksync-contracts/l2/system-contracts/interfaces/IAccount.sol"; +import { EfficientCall } from "@matterlabs/zksync-contracts/l2/system-contracts/libraries/EfficientCall.sol"; + +import { SignatureChecker } from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol"; + +import { Call } from "./batch/BatchCaller.sol"; + +import { IERC7579Account } from "./interfaces/IERC7579Account.sol"; +import { ModuleManager } from "./managers/ModuleManager.sol"; +import { HookManager } from "./managers/HookManager.sol"; +import { ExecutionHelper } from "./helpers/Execution.sol"; + +import { ClaveAccount } from "./ClaveAccount.sol"; +import { PackedUserOperation } from "./interfaces/PackedUserOperation.sol"; + +/** + * @author zeroknots.eth | rhinestone.wtf + * Reference implementation of a very simple ERC7579 Account. + * This account implements CallType: SINGLE, BATCH and DELEGATECALL. + * This account implements ExecType: DEFAULT and TRY. + * Hook support is implemented + */ +contract ERC7579Account is IERC7579Account, HookManager, ModuleManager, ExecutionHelper, ClaveAccount { + using ModeLib for ModeCode; + error AccountAccessUnauthorized(); + // 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(); + // Error thrown when account installs/unistalls module with mismatched input `moduleTypeId` + error MismatchModuleTypeId(uint256 moduleTypeId); + + bytes4 constant EIP1271_SUCCESS_RETURN_VALUE = 0x1626ba7e; + address private _factory = address(0); + + ///////////////////////////////////////////////////// + // Access Control + //////////////////////////////////////////////////// + + modifier onlyEntryPointOrSelf() virtual { + if (!(msg.sender == BOOTLOADER_FORMAL_ADDRESS || msg.sender == address(this) || msg.sender == _factory)) { + revert AccountAccessUnauthorized(); + } + _; + } + + modifier onlyEntryPoint() virtual { + if (msg.sender != BOOTLOADER_FORMAL_ADDRESS) { + revert AccountAccessUnauthorized(); + } + _; + } + + /** + * @inheritdoc IERC7579Account + * @dev this function is only callable by the entry point or the account itself + * @dev this function demonstrates how to implement + * CallType SINGLE and BATCH and ExecType DEFAULT and TRY + * @dev this function demonstrates how to implement hook support (modifier) + */ + function execute(ModeCode mode, bytes calldata executionCalldata) external payable onlyEntryPointOrSelf withHook { + (CallType callType, ExecType execType, , ) = mode.decode(); + + // check if calltype is batch or single + if (keccak256(abi.encodePacked(callType)) == keccak256(abi.encodePacked(CALLTYPE_BATCH))) { + // destructure executionCallData according to batched exec + Execution[] calldata executions = decodeBatch(executionCalldata); + // check if execType is revert or try + if (ExecType.unwrap(execType) == ExecType.unwrap(EXECTYPE_DEFAULT)) _execute(executions); + else if (ExecType.unwrap(execType) == ExecType.unwrap(EXECTYPE_TRY)) _tryExecute(executions); + else revert UnsupportedExecType(execType); + } else if (CallType.unwrap(callType) == CallType.unwrap(CALLTYPE_SINGLE)) { + // destructure executionCallData according to single exec + (address target, uint256 value, bytes calldata callData) = decodeSingle(executionCalldata); + // check if execType is revert or try + if (ExecType.unwrap(execType) == ExecType.unwrap(EXECTYPE_DEFAULT)) + _execute(target, value, callData); + // TODO: implement event emission for tryExecute singleCall + else if (ExecType.unwrap(execType) == ExecType.unwrap(EXECTYPE_TRY)) _tryExecute(target, value, callData); + else revert UnsupportedExecType(execType); + } else if (CallType.unwrap(callType) == CallType.unwrap(CALLTYPE_DELEGATECALL)) { + // destructure executionCallData according to single exec + address delegate = address(uint160(bytes20(executionCalldata[0:20]))); + bytes calldata callData = executionCalldata[20:]; + // check if execType is revert or try + if (ExecType.unwrap(execType) == ExecType.unwrap(EXECTYPE_DEFAULT)) _executeDelegatecall(delegate, callData); + else if (ExecType.unwrap(execType) == ExecType.unwrap(EXECTYPE_TRY)) _tryExecuteDelegatecall(delegate, callData); + else revert UnsupportedExecType(execType); + } else { + revert UnsupportedCallType(callType); + } + } + + /** + * @inheritdoc IERC7579Account + * @dev this function is only callable by an installed executor module + * @dev this function demonstrates how to implement + * CallType SINGLE and BATCH and ExecType DEFAULT and TRY + * @dev this function demonstrates how to implement hook support (modifier) + */ + function executeFromExecutor( + ModeCode mode, + bytes calldata executionCalldata + ) + external + payable + withHook + returns ( + bytes[] memory returnData // TODO returnData is not used + ) + { + (CallType callType, ExecType execType, , ) = mode.decode(); + + // check if calltype is batch or single + if (CallType.unwrap(callType) == CallType.unwrap(CALLTYPE_BATCH)) { + // destructure executionCallData according to batched exec + Execution[] calldata executions = decodeBatch(executionCalldata); + // check if execType is revert or try + if (ExecType.unwrap(execType) == ExecType.unwrap(EXECTYPE_DEFAULT)) returnData = _execute(executions); + else if (ExecType.unwrap(execType) == ExecType.unwrap(EXECTYPE_TRY)) returnData = _tryExecute(executions); + else revert UnsupportedExecType(execType); + } else if (CallType.unwrap(callType) == CallType.unwrap(CALLTYPE_SINGLE)) { + // destructure executionCallData according to single exec + (address target, uint256 value, bytes calldata callData) = decodeSingle(executionCalldata); + returnData = new bytes[](1); + bool success; + // check if execType is revert or try + if (ExecType.unwrap(execType) == ExecType.unwrap(EXECTYPE_DEFAULT)) { + returnData[0] = _execute(target, value, callData); + } + // TODO: implement event emission for tryExecute singleCall + else if (ExecType.unwrap(execType) == ExecType.unwrap(EXECTYPE_TRY)) { + (success, returnData[0]) = _tryExecute(target, value, callData); + if (!success) emit TryExecuteUnsuccessful(0, returnData[0]); + } else { + revert UnsupportedExecType(execType); + } + } else if (CallType.unwrap(callType) == CallType.unwrap(CALLTYPE_DELEGATECALL)) { + // destructure executionCallData according to single exec + address delegate = address(uint160(bytes20(executionCalldata[0:20]))); + bytes calldata callData = executionCalldata[20:]; + // check if execType is revert or try + if (ExecType.unwrap(execType) == ExecType.unwrap(EXECTYPE_DEFAULT)) _executeDelegatecall(delegate, callData); + else if (ExecType.unwrap(execType) == ExecType.unwrap(EXECTYPE_TRY)) _tryExecuteDelegatecall(delegate, callData); + else revert UnsupportedExecType(execType); + } else { + revert UnsupportedCallType(callType); + } + } + + /** + * @inheritdoc IERC7579Account + */ + function installModule( + uint256 moduleTypeId, + address module, + bytes calldata initData + ) external payable onlyEntryPointOrSelf withHook { + if (!IERC7579Module(module).isModuleType(moduleTypeId)) revert MismatchModuleTypeId(moduleTypeId); + + if (moduleTypeId == MODULE_TYPE_VALIDATOR) _addUserOpValidator(module, initData); + else if (moduleTypeId == MODULE_TYPE_EXECUTOR) _addExternalExecutorPermission(module, initData); + else if (moduleTypeId == MODULE_TYPE_FALLBACK) _addFallbackModule(module, initData); + else if (moduleTypeId == MODULE_TYPE_HOOK) _installHook(module, initData); + else revert UnsupportedModuleType(moduleTypeId); + emit ModuleInstalled(moduleTypeId, module); + } + + /** + * @inheritdoc IERC7579Account + */ + function uninstallModule( + uint256 moduleTypeId, + address module, + bytes calldata deInitData + ) external payable onlyEntryPointOrSelf withHook { + if (moduleTypeId == MODULE_TYPE_VALIDATOR) { + _uninstallValidator(module, deInitData); + } else if (moduleTypeId == MODULE_TYPE_EXECUTOR) { + _removeExternalExecutorModule(module, deInitData); + } else if (moduleTypeId == MODULE_TYPE_FALLBACK) { + _removeFallbackModule(module, deInitData); + } else if (moduleTypeId == MODULE_TYPE_HOOK) { + _uninstallHook(module, deInitData); + } else { + revert UnsupportedModuleType(moduleTypeId); + } + emit ModuleUninstalled(moduleTypeId, module); + } + + /** + * @dev ERC-4337 validateUserOp according to ERC-4337 v0.7 + * This function is intended to be called by ERC-4337 EntryPoint.sol + * this validation function should decode / sload the validator module to validate the userOp + * and call it. + * + * @dev MSA MUST implement this function signature. + * @param userOp PackedUserOperation struct (see ERC-4337 v0.7+) + */ + function validateUserOp( + PackedUserOperation calldata userOp, + bytes32 userOpHash, + uint256 missingAccountFunds + ) external payable virtual onlyEntryPoint returns (uint256 validSignature) { + address validator; + // @notice validator encoding in nonce is just an example! + // @notice this is not part of the standard! + // Account Vendors may choose any other way to implement validator selection + uint256 nonce = userOp.nonce; + assembly { + validator := shr(96, nonce) + } + + // bubble up the return value of the validator module + validSignature = IUserOpValidator(validator).validateUserOp(userOp, userOpHash); + } + + /** + * @inheritdoc IERC7579Account + */ + function isModuleInstalled( + uint256 moduleTypeId, + address module, + bytes calldata additionalContext + ) external view override returns (bool) { + if (moduleTypeId == MODULE_TYPE_VALIDATOR) { + return _isModule(module); + } else if (moduleTypeId == MODULE_TYPE_EXECUTOR) { + return _isModule(module); + } else if (moduleTypeId == MODULE_TYPE_FALLBACK) { + return _isModule(module); + } else if (moduleTypeId == MODULE_TYPE_HOOK) { + return _isHook(module); + } else { + return false; + } + } + + /** + * @inheritdoc IERC7579Account + */ + function supportsExecutionMode(ModeCode mode) external view virtual override returns (bool isSupported) { + (CallType callType, ExecType execType, , ) = mode.decode(); + if (CallType.unwrap(callType) == CallType.unwrap(CALLTYPE_BATCH)) isSupported = true; + else if (CallType.unwrap(callType) == CallType.unwrap(CALLTYPE_SINGLE)) isSupported = true; + else if (CallType.unwrap(callType) == CallType.unwrap(CALLTYPE_DELEGATECALL)) + isSupported = true; + // if callType is not single, batch or delegatecall return false + else return false; + + if (ExecType.unwrap(execType) == ExecType.unwrap(EXECTYPE_DEFAULT)) isSupported = true; + else if (ExecType.unwrap(execType) == ExecType.unwrap(EXECTYPE_TRY)) + isSupported = true; + // if execType is not default or try, return false + else return false; + } + + /** + * @inheritdoc IERC7579Account + */ + function supportsModule(uint256 moduleTypeId) external view virtual override returns (bool) { + if (moduleTypeId == MODULE_TYPE_VALIDATOR) return true; + else if (moduleTypeId == MODULE_TYPE_EXECUTOR) return true; + else if (moduleTypeId == MODULE_TYPE_FALLBACK) return true; + else if (moduleTypeId == MODULE_TYPE_HOOK) return true; + else return false; + } + + /** + * @inheritdoc IERC7579Account + */ + function accountId() external view virtual override returns (string memory) { + // vendor.flavour.SemVer + return "zksync.default.v0.1"; + } +} diff --git a/packages/contracts/src/helpers/Execution.sol b/packages/contracts/src/helpers/Execution.sol new file mode 100644 index 00000000..70575169 --- /dev/null +++ b/packages/contracts/src/helpers/Execution.sol @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import { Execution } from "../interfaces/IERC7579Account.sol"; + +/** + * @title Execution + * @dev This contract executes calls in the context of this contract. + * @author zeroknots.eth | rhinestone.wtf + * shoutout to solady (vectorized, ross) for this code + * https://github.com/Vectorized/solady/blob/main/src/accounts/ERC4337.sol + */ +contract ExecutionHelper { + error ExecutionFailed(); + + event TryExecuteUnsuccessful(uint256 batchExecutionindex, bytes result); + + 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); + } + + function _execute(Execution[] calldata executions) internal 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 _tryExecute(Execution[] calldata executions) internal 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); + if (!success) emit TryExecuteUnsuccessful(i, result[i]); + } + } + + 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 := 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. + } + } + + /// @dev Execute a delegatecall with `delegate` on this account. + function _executeDelegatecall(address delegate, bytes calldata callData) internal returns (bytes memory result) { + /// @solidity memory-safe-assembly + assembly { + result := mload(0x40) + calldatacopy(result, callData.offset, callData.length) + // Forwards the `data` to `delegate` via delegatecall. + if iszero(delegatecall(gas(), delegate, 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. + } + } + + /// @dev Execute a delegatecall with `delegate` on this account and catch reverts. + function _tryExecuteDelegatecall( + address delegate, + bytes calldata callData + ) internal returns (bool success, bytes memory result) { + /// @solidity memory-safe-assembly + assembly { + result := mload(0x40) + calldatacopy(result, callData.offset, callData.length) + // Forwards the `data` to `delegate` via delegatecall. + success := delegatecall(gas(), delegate, 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. + } + } +} diff --git a/packages/contracts/src/interfaces/ISsoAccount.sol b/packages/contracts/src/interfaces/IClaveAccount.sol similarity index 90% rename from packages/contracts/src/interfaces/ISsoAccount.sol rename to packages/contracts/src/interfaces/IClaveAccount.sol index 774e0a6e..e5a4904f 100644 --- a/packages/contracts/src/interfaces/ISsoAccount.sol +++ b/packages/contracts/src/interfaces/IClaveAccount.sol @@ -15,11 +15,11 @@ import { IUpgradeManager } from "./IUpgradeManager.sol"; import { IValidatorManager } from "./IValidatorManager.sol"; /** - * @title ISsoAccount - * @notice Interface for the SSO contract - * @dev Implementations of this interface are contract that can be used as an SSO account (it's no longer Clave compatible) + * @title IClaveAccount + * @notice Interface for the Clave contract + * @dev Implementations of this interface are contract that can be used as a Clave */ -interface ISsoAccount is +interface IClaveAccount is IERC1271Upgradeable, IERC721Receiver, IERC1155Receiver, diff --git a/packages/contracts/src/interfaces/IERC7579Account.sol b/packages/contracts/src/interfaces/IERC7579Account.sol new file mode 100644 index 00000000..ad22ff9d --- /dev/null +++ b/packages/contracts/src/interfaces/IERC7579Account.sol @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import { CallType, ExecType, ModeCode } from "../libraries/ERC7579Mode.sol"; + +struct Execution { + address target; + uint256 value; + bytes callData; +} + +interface IERC7579Account { + event ModuleInstalled(uint256 moduleTypeId, address module); + event ModuleUninstalled(uint256 moduleTypeId, address module); + + /** + * @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 (included with openzeppelin) + * 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 view returns (bytes4); + */ + + /** + * @dev installs a Module of a certain type on the smart account + * @dev Implement Authorization control of your choosing + * @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 cho0sing + * @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 + * identify 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/packages/contracts/src/interfaces/IERC7579Validator.sol b/packages/contracts/src/interfaces/IERC7579Validator.sol new file mode 100644 index 00000000..8ae2a0e9 --- /dev/null +++ b/packages/contracts/src/interfaces/IERC7579Validator.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import { IERC7579Module } from "./IERC7579Module.sol"; +import { PackedUserOperation } from "./PackedUserOperation.sol"; + +interface IUserOpValidator is IERC7579Module { + 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 validation phase + * Note: solely relying on bytes32 hash and signature is not sufficient 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); +} diff --git a/packages/contracts/src/libraries/SsoStorage.sol b/packages/contracts/src/libraries/ClaveStorage.sol similarity index 89% rename from packages/contracts/src/libraries/SsoStorage.sol rename to packages/contracts/src/libraries/ClaveStorage.sol index f9ea5ae4..790b874b 100644 --- a/packages/contracts/src/libraries/SsoStorage.sol +++ b/packages/contracts/src/libraries/ClaveStorage.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.24; -library SsoStorage { +library ClaveStorage { //keccak256('clave.contracts.ClaveStorage') - 1 - bytes32 private constant SSO_STORAGE_SLOT = 0x3248da1aeae8bd923cbf26901dc4bfc6bb48bb0fbc5b6102f1151fe7012884f4; + bytes32 private constant CLAVE_STORAGE_SLOT = 0x3248da1aeae8bd923cbf26901dc4bfc6bb48bb0fbc5b6102f1151fe7012884f4; struct Layout { // ┌───────────────────┐ @@ -24,6 +24,7 @@ library SsoStorage { // │ Validation │ mapping(address => address) r1Validators; mapping(address => address) k1Validators; + mapping(address => address) userOpValidators; mapping(address => address) moduleValidators; uint256[50] __gap_2; // └───────────────────┘ @@ -45,7 +46,7 @@ library SsoStorage { } function layout() internal pure returns (Layout storage l) { - bytes32 slot = SSO_STORAGE_SLOT; + bytes32 slot = CLAVE_STORAGE_SLOT; assembly { l.slot := slot } diff --git a/packages/contracts/src/libraries/ERC7579Mode.sol b/packages/contracts/src/libraries/ERC7579Mode.sol index 171c1d50..c06189fa 100644 --- a/packages/contracts/src/libraries/ERC7579Mode.sol +++ b/packages/contracts/src/libraries/ERC7579Mode.sol @@ -49,6 +49,7 @@ pragma solidity ^0.8.24; * 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; diff --git a/packages/contracts/src/libraries/Errors.sol b/packages/contracts/src/libraries/Errors.sol index e368e954..0f1c2bf1 100644 --- a/packages/contracts/src/libraries/Errors.sol +++ b/packages/contracts/src/libraries/Errors.sol @@ -115,7 +115,7 @@ library Errors { error INVALID_MARKUP(); error USER_LIMIT_REACHED(); error INVALID_USER_LIMIT(); - error NOT_SSO_ACCOUNT(); + error NOT_CLAVE_ACCOUNT(); error EXCEEDS_MAX_SPONSORED_ETH(); /*////////////////////////////////////////////////////////////// diff --git a/packages/contracts/src/managers/HookManager.sol b/packages/contracts/src/managers/HookManager.sol index a187703a..575e6c48 100644 --- a/packages/contracts/src/managers/HookManager.sol +++ b/packages/contracts/src/managers/HookManager.sol @@ -6,7 +6,7 @@ import { Transaction } from "@matterlabs/zksync-contracts/l2/system-contracts/li import { ExcessivelySafeCall } from "@nomad-xyz/excessively-safe-call/src/ExcessivelySafeCall.sol"; import { Auth } from "../auth/Auth.sol"; -import { SsoStorage } from "../libraries/SsoStorage.sol"; +import { ClaveStorage } from "../libraries/ClaveStorage.sol"; import { AddressLinkedList } from "../libraries/LinkedList.sol"; import { Errors } from "../libraries/Errors.sol"; import { IExecutionHook, IValidationHook } from "../interfaces/IHook.sol"; @@ -245,15 +245,15 @@ abstract contract HookManager is IHookManager, Auth { } function _validationHooksLinkedList() private view returns (mapping(address => address) storage validationHooks) { - validationHooks = SsoStorage.layout().validationHooks; + validationHooks = ClaveStorage.layout().validationHooks; } function _executionHooksLinkedList() private view returns (mapping(address => address) storage executionHooks) { - executionHooks = SsoStorage.layout().executionHooks; + executionHooks = ClaveStorage.layout().executionHooks; } function _hookDataStore() private view returns (mapping(address => mapping(bytes32 => bytes)) storage hookDataStore) { - hookDataStore = SsoStorage.layout().hookDataStore; + hookDataStore = ClaveStorage.layout().hookDataStore; } function _supportsHook(address hook, bool isValidation) internal view returns (bool) { diff --git a/packages/contracts/src/managers/ModuleManager.sol b/packages/contracts/src/managers/ModuleManager.sol index e27bb876..b617338c 100644 --- a/packages/contracts/src/managers/ModuleManager.sol +++ b/packages/contracts/src/managers/ModuleManager.sol @@ -4,14 +4,15 @@ pragma solidity ^0.8.24; import { ERC165Checker } from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol"; import { ExcessivelySafeCall } from "@nomad-xyz/excessively-safe-call/src/ExcessivelySafeCall.sol"; -import { SsoStorage } from "../libraries/SsoStorage.sol"; +import { ClaveStorage } from "../libraries/ClaveStorage.sol"; import { Auth } from "../auth/Auth.sol"; import { AddressLinkedList } from "../libraries/LinkedList.sol"; import { Errors } from "../libraries/Errors.sol"; import { IModule } from "../interfaces/IModule.sol"; import { IInitable } from "../interfaces/IInitable.sol"; -import { ISsoAccount } from "../interfaces/ISsoAccount.sol"; +import { IClaveAccount } from "../interfaces/IClaveAccount.sol"; import { IModuleManager } from "../interfaces/IModuleManager.sol"; +import { IUserOpValidator } from "../interfaces/IERC7579Validator.sol"; import { IERC7579Module, IExecutor } from "../interfaces/IERC7579Module.sol"; /** @@ -92,6 +93,15 @@ abstract contract ModuleManager is IModuleManager, Auth { emit AddModule(moduleAddress); } + function _addUserOpValidator(address module, bytes calldata data) internal virtual { + // Could do more validation on the validator (like does it exist already) + _userOpValidators().add(module); + + IUserOpValidator(module).onInstall(data); + + emit AddModule(module); + } + function _addExternalExecutorPermission(address module, bytes calldata data) internal virtual { _externalExecutorModule().add(module); @@ -101,7 +111,7 @@ abstract contract ModuleManager is IModuleManager, Auth { } function _addFallbackModule(address module, bytes calldata data) internal virtual { - SsoStorage.layout().fallbackContractBySelector[bytes4(data[0:4])] = module; + ClaveStorage.layout().fallbackContractBySelector[bytes4(data[0:4])] = module; IERC7579Module(module).onInstall(data); @@ -109,7 +119,7 @@ abstract contract ModuleManager is IModuleManager, Auth { } function _removeFallbackModule(address module, bytes calldata data) internal virtual { - SsoStorage.layout().fallbackContractBySelector[bytes4(data[0:4])] = address(0); + ClaveStorage.layout().fallbackContractBySelector[bytes4(data[0:4])] = address(0); IERC7579Module(module).onUninstall(data); @@ -130,11 +140,23 @@ abstract contract ModuleManager is IModuleManager, Auth { } function _modulesLinkedList() private view returns (mapping(address => address) storage modules) { - modules = SsoStorage.layout().modules; + modules = ClaveStorage.layout().modules; + } + + function _userOpValidators() private view returns (mapping(address => address) storage modules) { + modules = ClaveStorage.layout().userOpValidators; + } + + function _uninstallValidator(address validator, bytes calldata data) internal { + _userOpValidators().remove(validator); + + IUserOpValidator(validator).onUninstall(data); + + emit RemoveModule(validator); } function _externalExecutorModule() private view returns (mapping(address => address) storage modules) { - modules = SsoStorage.layout().execModules; + modules = ClaveStorage.layout().execModules; } function _removeExternalExecutorModule(address module, bytes calldata data) internal { diff --git a/packages/contracts/src/managers/OwnerManager.sol b/packages/contracts/src/managers/OwnerManager.sol index fa5a764c..1f05bf33 100644 --- a/packages/contracts/src/managers/OwnerManager.sol +++ b/packages/contracts/src/managers/OwnerManager.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.24; -import { SsoStorage } from "../libraries/SsoStorage.sol"; +import { ClaveStorage } from "../libraries/ClaveStorage.sol"; import { BytesLinkedList, AddressLinkedList } from "../libraries/LinkedList.sol"; import { Errors } from "../libraries/Errors.sol"; import { Auth } from "../auth/Auth.sol"; -import { ISsoAccount } from "../interfaces/ISsoAccount.sol"; +import { IClaveAccount } from "../interfaces/IClaveAccount.sol"; import { IOwnerManager } from "../interfaces/IOwnerManager.sol"; /** @@ -113,11 +113,11 @@ abstract contract OwnerManager is IOwnerManager, Auth { } function _r1OwnersLinkedList() internal view returns (mapping(bytes => bytes) storage r1Owners) { - r1Owners = SsoStorage.layout().r1Owners; + r1Owners = ClaveStorage.layout().r1Owners; } function _k1OwnersLinkedList() internal view returns (mapping(address => address) storage k1Owners) { - k1Owners = SsoStorage.layout().k1Owners; + k1Owners = ClaveStorage.layout().k1Owners; } function _r1ClearOwners() private { diff --git a/packages/contracts/src/managers/ValidatorManager.sol b/packages/contracts/src/managers/ValidatorManager.sol index 94c8f540..16fb1b4d 100644 --- a/packages/contracts/src/managers/ValidatorManager.sol +++ b/packages/contracts/src/managers/ValidatorManager.sol @@ -5,7 +5,7 @@ import { ERC165Checker } from "@openzeppelin/contracts/utils/introspection/ERC16 import { Auth } from "../auth/Auth.sol"; import { Errors } from "../libraries/Errors.sol"; -import { SsoStorage } from "../libraries/SsoStorage.sol"; +import { ClaveStorage } from "../libraries/ClaveStorage.sol"; import { AddressLinkedList } from "../libraries/LinkedList.sol"; import { IR1Validator, IK1Validator } from "../interfaces/IValidator.sol"; import { IValidatorManager } from "../interfaces/IValidatorManager.sol"; @@ -160,14 +160,14 @@ abstract contract ValidatorManager is IValidatorManager, Auth { } function _r1ValidatorsLinkedList() private view returns (mapping(address => address) storage r1Validators) { - r1Validators = SsoStorage.layout().r1Validators; + r1Validators = ClaveStorage.layout().r1Validators; } function _moduleValidatorsLinkedList() private view returns (mapping(address => address) storage moduleValidators) { - moduleValidators = SsoStorage.layout().moduleValidators; + moduleValidators = ClaveStorage.layout().moduleValidators; } function _k1ValidatorsLinkedList() private view returns (mapping(address => address) storage k1Validators) { - k1Validators = SsoStorage.layout().k1Validators; + k1Validators = ClaveStorage.layout().k1Validators; } } diff --git a/packages/contracts/src/test/ExampleAuthServerPaymaster.sol b/packages/contracts/src/test/ExampleAuthServerPaymaster.sol index 6037b7a1..3495df79 100644 --- a/packages/contracts/src/test/ExampleAuthServerPaymaster.sol +++ b/packages/contracts/src/test/ExampleAuthServerPaymaster.sol @@ -16,7 +16,7 @@ import { SessionKeyValidator } from "../validators/SessionKeyValidator.sol"; contract ExampleAuthServerPaymaster is IPaymaster, Ownable { address public immutable AA_FACTORY_CONTRACT_ADDRESS; address public immutable SESSION_KEY_VALIDATOR_CONTRACT_ADDRESS; - bytes4 constant DEPLOY_ACCOUNT_SELECTOR = AAFactory.deployProxySsoAccount.selector; + bytes4 constant DEPLOY_ACCOUNT_SELECTOR = AAFactory.deployProxy7579Account.selector; bytes4 constant CREATE_SESSION_SELECTOR = SessionKeyValidator.createSession.selector; modifier onlyBootloader() { @@ -46,7 +46,7 @@ contract ExampleAuthServerPaymaster is IPaymaster, Ownable { "Unsupported contract address" ); - // Ensure the transaction is calling either the deployProxySsoAccount or createSession functions + // Ensure the transaction is calling either the deployProxy7579Account or createSession functions require(_transaction.data.length >= 4, "Transaction data is too short"); bytes4 methodSelector = bytes4(_transaction.data[0:4]); if (to == AA_FACTORY_CONTRACT_ADDRESS) { diff --git a/packages/contracts/test/BasicTest.ts b/packages/contracts/test/BasicTest.ts index f93672fe..7488c7a7 100644 --- a/packages/contracts/test/BasicTest.ts +++ b/packages/contracts/test/BasicTest.ts @@ -4,7 +4,7 @@ import { Wallet, ZeroAddress } from "ethers"; import { it } from "mocha"; import { SmartAccount, utils } from "zksync-ethers"; -import { SsoAccount__factory } from "../typechain-types"; +import { ERC7579Account__factory } from "../typechain-types"; import { CallStruct } from "../typechain-types/src/batch/BatchCaller"; import { ContractFixtures, getProvider } from "./utils"; @@ -36,7 +36,7 @@ describe("Basic tests", function () { const aaFactoryContract = await fixtures.getAaFactory(); assert(aaFactoryContract != null, "No AA Factory deployed"); - const deployTx = await aaFactoryContract.deployProxySsoAccount( + const deployTx = await aaFactoryContract.deployProxy7579Account( randomBytes(32), "id", [], @@ -48,7 +48,7 @@ describe("Basic tests", function () { expect(proxyAccountAddress, "the proxy account location via logs").to.not.equal(ZeroAddress, "be a valid address"); - const account = SsoAccount__factory.connect(proxyAccountAddress, provider); + const account = ERC7579Account__factory.connect(proxyAccountAddress, provider); assert(await account.k1IsOwner(fixtures.wallet.address)); }); @@ -109,7 +109,7 @@ describe("Basic tests", function () { }, ]; - const account = SsoAccount__factory.connect(proxyAccountAddress, provider); + const account = ERC7579Account__factory.connect(proxyAccountAddress, provider); const aaTx = { ...await aaTxTemplate(), diff --git a/packages/contracts/test/SessionKeyTest.ts b/packages/contracts/test/SessionKeyTest.ts index 770b5645..e03bc5fa 100644 --- a/packages/contracts/test/SessionKeyTest.ts +++ b/packages/contracts/test/SessionKeyTest.ts @@ -6,7 +6,7 @@ import { it } from "mocha"; import { SmartAccount, utils } from "zksync-ethers"; import type { ERC20 } from "../typechain-types"; -import { AAFactory__factory, SsoAccount__factory } from "../typechain-types"; +import { AAFactory__factory, ERC7579Account__factory } from "../typechain-types"; import type { AAFactory } from "../typechain-types/src/AAFactory"; import type { SessionLib } from "../typechain-types/src/validators/SessionKeyValidator"; import { ContractFixtures, getProvider, logInfo } from "./utils"; @@ -250,8 +250,8 @@ describe("SessionKeyModule tests", function () { assert(verifierContract != null, "No verifier deployed"); const sessionModuleContract = await fixtures.getSessionKeyContract(); assert(sessionModuleContract != null, "No session module deployed"); - const ssoContract = await fixtures.getAccountImplContract(); - assert(ssoContract != null, "No SSO Account deployed"); + const erc7579Contract = await fixtures.getAccountImplContract(); + assert(erc7579Contract != null, "No ERC7579 deployed"); const factoryContract = await fixtures.getAaFactory(); assert(factoryContract != null, "No AA Factory deployed"); const authServerPaymaster = await fixtures.deployExampleAuthServerPaymaster( @@ -263,7 +263,7 @@ describe("SessionKeyModule tests", function () { logInfo(`Session Address : ${await sessionModuleContract.getAddress()}`); logInfo(`Passkey Address : ${await verifierContract.getAddress()}`); logInfo(`Account Factory Address : ${await factoryContract.getAddress()}`); - // logInfo(`Account Implementation Address : ${await ssoContract.getAddress()}`); + // logInfo(`Account Implementation Address : ${await erc7579Contract.getAddress()}`); logInfo(`Auth Server Paymaster Address : ${await authServerPaymaster.getAddress()}`); }); @@ -272,7 +272,7 @@ describe("SessionKeyModule tests", function () { const sessionKeyModuleAddress = await fixtures.getSessionKeyModuleAddress(); const sessionKeyPayload = abiCoder.encode(["address", "bytes"], [sessionKeyModuleAddress, "0x"]); - const deployTx = await factoryContract.deployProxySsoAccount( + const deployTx = await factoryContract.deployProxy7579Account( randomBytes(32), "id", [], @@ -287,7 +287,7 @@ describe("SessionKeyModule tests", function () { const fundTx = await fixtures.wallet.sendTransaction({ value: parseEther("1"), to: proxyAccountAddress }); await fundTx.wait(); - const account = SsoAccount__factory.connect(proxyAccountAddress, provider); + const account = ERC7579Account__factory.connect(proxyAccountAddress, provider); assert(await account.k1IsOwner(fixtures.wallet.address)); assert(await account.isHook(sessionKeyModuleAddress), "session key module should be a hook"); assert(await account.isModuleValidator(sessionKeyModuleAddress), "session key module should be a validator"); diff --git a/packages/contracts/test/utils.ts b/packages/contracts/test/utils.ts index e1994bca..93cb1606 100644 --- a/packages/contracts/test/utils.ts +++ b/packages/contracts/test/utils.ts @@ -9,8 +9,8 @@ import * as hre from "hardhat"; import { ContractFactory, Provider, utils, Wallet } from "zksync-ethers"; import { base64UrlToUint8Array, getPublicKeyBytesFromPasskeySignature, unwrapEC2Signature } from "zksync-sso/utils"; -import { AAFactory, ERC20, ExampleAuthServerPaymaster, SessionKeyValidator, SsoAccount, WebAuthValidator } from "../typechain-types"; -import { AAFactory__factory, ERC20__factory, ExampleAuthServerPaymaster__factory, SessionKeyValidator__factory, SsoAccount__factory, WebAuthValidator__factory } from "../typechain-types"; +import { AAFactory, ERC20, ERC7579Account, ExampleAuthServerPaymaster, SessionKeyValidator, WebAuthValidator } from "../typechain-types"; +import { AAFactory__factory, ERC20__factory, ERC7579Account__factory, ExampleAuthServerPaymaster__factory, SessionKeyValidator__factory, WebAuthValidator__factory } from "../typechain-types"; export class ContractFixtures { readonly wallet: Wallet = getWallet(LOCAL_RICH_WALLETS[0].privateKey); @@ -67,11 +67,12 @@ export class ContractFixtures { return this._passkeyModuleAddress; } - private _accountImplContract: SsoAccount; + private _accountImplContract: ERC7579Account; + // wraps the clave account async getAccountImplContract() { if (!this._accountImplContract) { - const contract = await create2("SsoAccount", this.wallet, this.ethersStaticSalt); - this._accountImplContract = SsoAccount__factory.connect(await contract.getAddress(), this.wallet); + const contract = await create2("ERC7579Account", this.wallet, this.ethersStaticSalt); + this._accountImplContract = ERC7579Account__factory.connect(await contract.getAddress(), this.wallet); } return this._accountImplContract; } diff --git a/packages/sdk/src/abi/Factory.ts b/packages/sdk/src/abi/Factory.ts index 292dd32e..c941ee42 100644 --- a/packages/sdk/src/abi/Factory.ts +++ b/packages/sdk/src/abi/Factory.ts @@ -120,7 +120,7 @@ export const FactoryAbi = [ type: "address[]", }, ], - name: "deployProxySsoAccount", + name: "deployProxy7579Account", outputs: [ { internalType: "address", diff --git a/packages/sdk/src/client/actions/account.ts b/packages/sdk/src/client/actions/account.ts index 7ce80977..e1e6cbdb 100644 --- a/packages/sdk/src/client/actions/account.ts +++ b/packages/sdk/src/client/actions/account.ts @@ -88,7 +88,7 @@ export const deployAccount = async < chain: client.chain!, address: args.contracts.accountFactory, abi: FactoryAbi, - functionName: "deployProxySsoAccount", + functionName: "deployProxy7579Account", args: [ toHex(args.salt), accountId,