Skip to content

Commit

Permalink
Revert "chore: rename to reflect SSO interface" (#189)
Browse files Browse the repository at this point in the history
Revert "chore: rename to reflect SSO interface (#185)"

This reverts commit 58126c7.
  • Loading branch information
cpb8010 authored Nov 20, 2024
1 parent 9e9c446 commit 0bf91c6
Show file tree
Hide file tree
Showing 21 changed files with 660 additions and 64 deletions.
4 changes: 2 additions & 2 deletions packages/auth-server/stores/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ export const contractsByChain: Record<SupportedChainId, ChainContracts> = {
},
[zksyncInMemoryNode.id]: {
session: "0x8543528a4561E3a5EC7d51Bfd3776457b0E7b7dc",
passkey: "0x975df0c7f5CB728ae9F96480491Ec5d1E17296f4",
passkey: "0x07734BA326b6AD13BfC0115b0903EB14268F1617",
accountFactory: "0xaAF5f437fB0524492886fbA64D703df15BF619AE",
accountPaymaster: "0x351cB880A2B9E1Cf3060ea58Ec5280CBCe87579A",
accountPaymaster: "0x2879853afd8d066ca66e224A8E85621aC43d6F59",
},
};

Expand Down
16 changes: 4 additions & 12 deletions packages/contracts/src/AAFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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,
Expand Down Expand Up @@ -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");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand All @@ -32,15 +32,15 @@ import "./helpers/Logger.sol";
* @author https://getclave.io
*/

contract SsoAccount is
contract ClaveAccount is
Initializable,
UpgradeManager,
HookManager,
ModuleManager,
ERC1271Handler,
TokenCallbackHandler,
BatchCaller,
ISsoAccount
IClaveAccount
{
// Helper library for the Transaction struct
using TransactionHelper for Transaction;
Expand Down Expand Up @@ -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(
Expand Down
289 changes: 289 additions & 0 deletions packages/contracts/src/ERC7579Account.sol
Original file line number Diff line number Diff line change
@@ -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";
}
}
Loading

0 comments on commit 0bf91c6

Please sign in to comment.