-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'feat/oidc-account-recovery' into matias/test-key-registry
- Loading branch information
Showing
12 changed files
with
857 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ pragma solidity ^0.8.24; | |
import { DEPLOYER_SYSTEM_CONTRACT } from "@matterlabs/zksync-contracts/l2/system-contracts/Constants.sol"; | ||
import { IContractDeployer } from "@matterlabs/zksync-contracts/l2/system-contracts/interfaces/IContractDeployer.sol"; | ||
import { SystemContractsCaller } from "@matterlabs/zksync-contracts/l2/system-contracts/libraries/SystemContractsCaller.sol"; | ||
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; | ||
|
||
import { ISsoAccount } from "./interfaces/ISsoAccount.sol"; | ||
|
||
|
@@ -12,6 +13,8 @@ import { ISsoAccount } from "./interfaces/ISsoAccount.sol"; | |
/// @custom:security-contact [email protected] | ||
/// @dev This contract is used to deploy SSO accounts as beacon proxies. | ||
contract AAFactory { | ||
using Strings for string; | ||
|
||
/// @notice Emitted when a new account is successfully created. | ||
/// @param accountAddress The address of the newly created account. | ||
/// @param uniqueAccountId A unique identifier for the account. | ||
|
@@ -24,6 +27,17 @@ contract AAFactory { | |
/// @notice A mapping from unique account IDs to their corresponding deployed account addresses. | ||
mapping(string => address) public accountMappings; | ||
|
||
/// @notice A mapping from account addresses to their corresponding unique account IDs. | ||
mapping(address => string) public accountIds; | ||
|
||
/// @notice A mapping that marks account IDs as being used for recovery. | ||
/// @dev This is used to prevent the same account ID from being used for recovery, deployment and future uses. | ||
mapping(string => address) public recoveryAccountIds; | ||
|
||
error AccountAlreadyRegistered(string uniqueAccountId, address accountAddress); | ||
error AccountNotRegistered(string uniqueAccountId, address accountAddress); | ||
error AccountUsedForRecovery(string uniqueAccountId, address accountAddress); | ||
|
||
/// @notice Constructor that initializes the factory with a beacon proxy bytecode hash and implementation contract address. | ||
/// @param _beaconProxyBytecodeHash The bytecode hash of the beacon proxy. | ||
/// @param _beacon The address of the UpgradeableBeacon contract used for the SSO accounts' beacon proxies. | ||
|
@@ -49,8 +63,6 @@ contract AAFactory { | |
bytes[] calldata _initialValidators, | ||
address[] calldata _initialK1Owners | ||
) external returns (address accountAddress) { | ||
require(accountMappings[_uniqueAccountId] == address(0), "Account already exists"); | ||
|
||
(bool success, bytes memory returnData) = SystemContractsCaller.systemCallWithReturndata( | ||
uint32(gasleft()), | ||
address(DEPLOYER_SYSTEM_CONTRACT), | ||
|
@@ -63,11 +75,113 @@ contract AAFactory { | |
require(success, "Deployment failed"); | ||
(accountAddress) = abi.decode(returnData, (address)); | ||
|
||
accountMappings[_uniqueAccountId] = accountAddress; | ||
// Check if the account is already registered | ||
// Note: this check is done at this point, to use `accountAddress` to process the error message. | ||
require( | ||
accountMappings[_uniqueAccountId] == address(0), | ||
AccountAlreadyRegistered(_uniqueAccountId, accountAddress) | ||
); | ||
require(accountIds[accountAddress].equal(""), AccountAlreadyRegistered(_uniqueAccountId, accountAddress)); | ||
require( | ||
recoveryAccountIds[_uniqueAccountId] == address(0), | ||
AccountUsedForRecovery(_uniqueAccountId, accountAddress) | ||
); | ||
|
||
// Initialize the newly deployed account with validators, hooks and K1 owners. | ||
ISsoAccount(accountAddress).initialize(_initialValidators, _initialK1Owners); | ||
|
||
_registerAccount(_uniqueAccountId, accountAddress); | ||
|
||
emit AccountCreated(accountAddress, _uniqueAccountId); | ||
} | ||
|
||
/// @notice Registers an account with a given account ID. | ||
/// @dev Can only be called by the account's validators. | ||
/// @param _uniqueAccountId The unique identifier for the account. | ||
/// @param _accountAddress The address of the account to register. | ||
function registerAccount( | ||
string calldata _uniqueAccountId, | ||
address _accountAddress | ||
) external onlyAccountValidator(_accountAddress) { | ||
require( | ||
accountMappings[_uniqueAccountId] == address(0), | ||
AccountAlreadyRegistered(_uniqueAccountId, _accountAddress) | ||
); | ||
require(accountIds[_accountAddress].equal(""), AccountAlreadyRegistered(_uniqueAccountId, _accountAddress)); | ||
require( | ||
recoveryAccountIds[_uniqueAccountId] == address(0), | ||
AccountUsedForRecovery(_uniqueAccountId, _accountAddress) | ||
); | ||
|
||
_registerAccount(_uniqueAccountId, _accountAddress); | ||
} | ||
|
||
function _registerAccount(string calldata _uniqueAccountId, address _accountAddress) internal { | ||
accountMappings[_uniqueAccountId] = _accountAddress; | ||
accountIds[_accountAddress] = _uniqueAccountId; | ||
} | ||
|
||
/// @notice Unregisters an account from the factory. | ||
/// @dev Can only be called by the account's validators. | ||
/// @param _uniqueAccountId The unique identifier for the account. | ||
/// @param _accountAddress The address of the account to unregister. | ||
function unregisterAccount( | ||
string memory _uniqueAccountId, | ||
address _accountAddress | ||
) external onlyAccountValidator(_accountAddress) { | ||
require( | ||
accountMappings[_uniqueAccountId] == _accountAddress, | ||
AccountNotRegistered(_uniqueAccountId, _accountAddress) | ||
); | ||
require( | ||
accountIds[_accountAddress].equal(_uniqueAccountId), | ||
AccountNotRegistered(_uniqueAccountId, _accountAddress) | ||
); | ||
|
||
accountMappings[_uniqueAccountId] = address(0); | ||
accountIds[_accountAddress] = ""; | ||
} | ||
|
||
/// @notice Updates the account mapping for a given account ID during recovery. | ||
/// @dev Can only be called by the account's validators. | ||
/// @param _uniqueAccountId The unique identifier for the account. | ||
/// @param _accountAddress The address of the account to update the mapping for. | ||
function registerRecoveryBlockedAccount( | ||
string calldata _uniqueAccountId, | ||
address _accountAddress | ||
) external onlyAccountValidator(_accountAddress) { | ||
require( | ||
accountMappings[_uniqueAccountId] == address(0), | ||
AccountAlreadyRegistered(_uniqueAccountId, _accountAddress) | ||
); | ||
require( | ||
recoveryAccountIds[_uniqueAccountId] == address(0), | ||
AccountUsedForRecovery(_uniqueAccountId, _accountAddress) | ||
); | ||
|
||
recoveryAccountIds[_uniqueAccountId] = _accountAddress; | ||
} | ||
|
||
/// @notice Unregisters a recovery blocked account from the factory. | ||
/// @dev Can only be called by the account's validators. | ||
/// @param _uniqueAccountId The unique identifier for the account. | ||
/// @param _accountAddress The address of the account to unregister. | ||
function unregisterRecoveryBlockedAccount( | ||
string calldata _uniqueAccountId, | ||
address _accountAddress | ||
) external onlyAccountValidator(_accountAddress) { | ||
require( | ||
recoveryAccountIds[_uniqueAccountId] == _accountAddress, | ||
AccountNotRegistered(_uniqueAccountId, _accountAddress) | ||
); | ||
|
||
recoveryAccountIds[_uniqueAccountId] = address(0); | ||
} | ||
|
||
/// @notice Modifier that checks if the caller is a validator for the given account. | ||
/// @param _accountAddress The address of the account to check the validator for. | ||
modifier onlyAccountValidator(address _accountAddress) { | ||
require(ISsoAccount(_accountAddress).isModuleValidator(msg.sender), "Unauthorized validator"); | ||
_; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.24; | ||
|
||
import { IModuleValidator } from "./IModuleValidator.sol"; | ||
import { Transaction } from "@matterlabs/zksync-contracts/l2/system-contracts/libraries/TransactionHelper.sol"; | ||
|
||
interface IGuardianRecoveryValidator is IModuleValidator { | ||
struct GuardianConfirmation { | ||
address ssoAccount; | ||
} | ||
|
||
function proposeValidationKey(address externalAccount) external; | ||
|
||
function removeValidationKey(address externalAccount) external; | ||
|
||
function initRecovery(address accountToRecover, bytes memory passkey, string memory accountId) external; | ||
|
||
function addValidationKey(bytes memory key) external returns (bool); | ||
|
||
function validateTransaction( | ||
bytes32 signedHash, | ||
bytes memory signature, | ||
Transaction calldata transaction | ||
) external returns (bool); | ||
|
||
function validateSignature(bytes32 signedHash, bytes memory signature) external view returns (bool); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.