Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert "chore: rename to reflect SSO interface" #189

Merged
merged 1 commit into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading