From cd16e2dabfff7183724c3758978f387f9ada321d Mon Sep 17 00:00:00 2001 From: "david.ding" Date: Fri, 19 Apr 2024 17:54:44 +0800 Subject: [PATCH] readme update --- README.md | 21 ++---- .../automation/AaveUsdcSaveAutomation.sol | 19 ++++++ contracts/libraries/Errors.sol | 11 ---- contracts/modules/socialRecovery/README.md | 51 +++++++++++++++ .../socialRecovery/SocialRecoveryModule.sol | 24 ++++++- .../base/BaseSocialRecovery.sol | 61 ++++++++++++++++-- .../socialRecovery/socialReoceryFlow.png | Bin 0 -> 32108 bytes 7 files changed, 151 insertions(+), 36 deletions(-) create mode 100644 contracts/modules/socialRecovery/README.md create mode 100644 contracts/modules/socialRecovery/socialReoceryFlow.png diff --git a/README.md b/README.md index 2afaa503..10992c57 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,6 @@ - Support [ERC-4337: Account Abstraction](https://eips.ethereum.org/EIPS/eip-4337) - [Modular design ](https://hackmd.io/3gbndH7tSl2J1EbNePJ3Yg) -- Implement [asset / keystore](https://hackmd.io/-YY8jD7IQ7qfEZaDepXZsA?view) separation architecture - Upgradability: The smart contract for this wallet can be upgraded in a secure way to add new features or fix vulnerabilities in the future. - Stablecoin pay gas: Users can pay transaction gas fees with stablecoins such as USDC, USDT, DAI, etc. @@ -42,34 +41,22 @@ All contracts are held within the `soul-wallet-contract/contracts` folder. ``` contracts ├── abstract +├── automation ├── dev │ └── tokens ├── factory ├── hooks │ └── 2fa ├── interfaces -├── keystore -│ ├── L1 -│ │ ├── base -│ │ └── interfaces -│ └── interfaces ├── libraries ├── modules │ ├── interfaces -│ ├── keystore -│ │ ├── arbitrum +│ ├── socialRecovery │ │ ├── base -│ │ ├── interfaces -│ │ └── optimism -│ ├── securityControlModule -│ │ └── trustedContractManager -│ │ ├── trustedHookManager -│ │ ├── trustedModuleManager -│ │ └── trustedValidatorManager +│ │ └── interfaces │ └── upgrade ├── paymaster │ └── interfaces -├── proxy └── validator └── libraries ``` @@ -114,7 +101,7 @@ contract NewModule is BaseModule { ### Hook -o integrate a new hook, your contract should inherit `IHook` interface. This interface will define the standard structure and functionalities for your hooks. +To integrate a new hook, your contract should inherit `IHook` interface. This interface will define the standard structure and functionalities for your hooks. ```solidity diff --git a/contracts/automation/AaveUsdcSaveAutomation.sol b/contracts/automation/AaveUsdcSaveAutomation.sol index 9cccf3f7..fde01fac 100644 --- a/contracts/automation/AaveUsdcSaveAutomation.sol +++ b/contracts/automation/AaveUsdcSaveAutomation.sol @@ -7,6 +7,10 @@ interface IAaveV3 { function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external; } +/** + * @title AaveUsdcSaveAutomation + * @dev This contract allows a bot to deposit USDC to Aave on behalf of a user. + */ contract AaveUsdcSaveAutomation is Ownable { using SafeERC20 for IERC20; @@ -18,6 +22,9 @@ contract AaveUsdcSaveAutomation is Ownable { IAaveV3 immutable aave; mapping(address => bool) public bots; + /** + * @dev Modifier to make a function callable only by a bot. + */ modifier onlyBot() { require(bots[msg.sender], "no permission"); _; @@ -29,12 +36,24 @@ contract AaveUsdcSaveAutomation is Ownable { usdcToken.approve(address(aave), 2 ** 256 - 1); } + /** + * @notice Deposits USDC to Aave on behalf of a user + * @dev This function can only be called by a bot + * @param _user The address of the user for whom to deposit USDC + * @param amount The amount of USDC to deposit + */ function depositUsdcToAave(address _user, uint256 amount) public onlyBot { usdcToken.safeTransferFrom(_user, address(this), amount); aave.supply(address(usdcToken), amount, _user, 0); emit UsdcDepositedToAave(_user, amount); } + /** + * @notice Deposits USDC to Aave on behalf of multiple users + * @dev This function can only be called by a bot + * @param _users An array of addresses of the users for whom to deposit USDC + * @param amounts An array of amounts of USDC to deposit for each user + */ function depositUsdcToAaveBatch(address[] calldata _users, uint256[] calldata amounts) public onlyBot { require(_users.length == amounts.length, "invalid input"); for (uint256 i = 0; i < _users.length; i++) { diff --git a/contracts/libraries/Errors.sol b/contracts/libraries/Errors.sol index e926df79..68187534 100644 --- a/contracts/libraries/Errors.sol +++ b/contracts/libraries/Errors.sol @@ -6,35 +6,24 @@ library Errors { error ADDRESS_NOT_EXISTS(); error DATA_ALREADY_EXISTS(); error DATA_NOT_EXISTS(); - error CALLER_MUST_BE_ENTRYPOINT(); error CALLER_MUST_BE_SELF_OR_MODULE(); error CALLER_MUST_BE_MODULE(); error HASH_ALREADY_APPROVED(); error HASH_ALREADY_REJECTED(); error INVALID_ADDRESS(); - error INVALID_GUARD_HOOK_DATA(); error INVALID_SELECTOR(); error INVALID_SIGNTYPE(); - error MODULE_ADDRESS_EMPTY(); - error MODULE_NOT_SUPPORT_INTERFACE(); - error MODULE_SELECTOR_UNAUTHORIZED(); error MODULE_SELECTORS_EMPTY(); error MODULE_EXECUTE_FROM_MODULE_RECURSIVE(); - error NO_OWNER(); error SELECTOR_ALREADY_EXISTS(); error SELECTOR_NOT_EXISTS(); - error UNSUPPORTED_SIGNTYPE(); error INVALID_LOGIC_ADDRESS(); error SAME_LOGIC_ADDRESS(); error UPGRADE_FAILED(); error NOT_IMPLEMENTED(); error INVALID_SIGNATURE(); - error ALERADY_INITIALIZED(); - error INVALID_KEY(); - error NOT_INITIALIZED(); error INVALID_TIME_RANGE(); error UNAUTHORIZED(); error INVALID_DATA(); error GUARDIAN_SIGNATURE_INVALID(); - error UNTRUSTED_KEYSTORE_LOGIC(); } diff --git a/contracts/modules/socialRecovery/README.md b/contracts/modules/socialRecovery/README.md new file mode 100644 index 00000000..589909a2 --- /dev/null +++ b/contracts/modules/socialRecovery/README.md @@ -0,0 +1,51 @@ +# SocialRecoveryModule + +The `SocialRecoveryModule` is a Solidity contract that can be installed in wallets to enable a social recovery mechanism. This module allows a user to designate a list of guardians for their wallet and establish a recovery threshold. If a wallet is lost or compromised, the guardians can initiate a recovery process by signing a special EIP712 signature. However, this recovery process is subject to a user-defined time lock period, and the guardians can only execute the recovery after this period has passed. This mechanism ensures that the user's assets remain secure and recoverable, even in unforeseen circumstances. + +## Recovery flow + +![social recovery flow](socialReoceryFlow.png) + +- Step 1: Users install the Social Recovery Module in their SoulWallet. They need to configure the guardian hash and the execution delay period when installing the module. The guardian hash refers to the keccak256 hash of the GuardianData, ensuring the privacy of guardian identities. Others cannot check your guardians' settings on-chain and they are only revealed when the user initiates the social recovery process. + + ```solidity + struct GuardianData { + address[] guardians; + uint256 threshold; + uint256 salt; + } + ``` + +- Step 2: When users want to recover their wallet using the guardians, they have to contact the guardians to sign an EIP-712 based signature and use the following scheme: + + - EIP712Domain + + ```json + { + "EIP712Domain": [ + { "type": "uint256", "name": "chainId" }, + { "type": "address", "name": "SocialRecovery" } + ] + } + ``` + + - SocialRecovery + + ```json + { + "SocialRecovery": [ + { "type": "address", "name": "wallet" }, + { "type": "uint256", "name": "nonce" }, + { "type": "bytes32[]", "name": "newOwners" } + ] + } + ``` + + Once the signatures are collected and the threshold is met, it can call scheduleRecovery to enter the waiting queue for recovery. + +- Step 3: If the timelock period has passed, one can call `executeRecovery` to perform the recovery. The social recovery module will then reset the owners based on the previous setting. + +## Considerations + +- Users can call `cancelAllRecovery` to invalidate transactions in the pending queue. +- Users can call `setGuardian` to change guardians' settings without a timelock. diff --git a/contracts/modules/socialRecovery/SocialRecoveryModule.sol b/contracts/modules/socialRecovery/SocialRecoveryModule.sol index a4d53d19..94a35c9a 100644 --- a/contracts/modules/socialRecovery/SocialRecoveryModule.sol +++ b/contracts/modules/socialRecovery/SocialRecoveryModule.sol @@ -1,8 +1,14 @@ -pragma solidity ^0.8.17; +pragma solidity ^0.8.20; import "../BaseModule.sol"; import "./base/BaseSocialRecovery.sol"; +/** + * @title SocialRecoveryModule + * @dev This contract extends BaseModule and BaseSocialRecovery to provide social recovery functionality for a wallet. + * It allows a wallet owner to set a list of guardians and a recovery delay period. If the wallet is lost or compromised, + * the guardians can recover the wallet after the delay period has passed. + */ contract SocialRecoveryModule is BaseModule, BaseSocialRecovery { bytes4 private constant _FUNC_RESET_OWNER = bytes4(keccak256("resetOwner(bytes32)")); bytes4 private constant _FUNC_RESET_OWNERS = bytes4(keccak256("resetOwners(bytes32[])")); @@ -10,12 +16,19 @@ contract SocialRecoveryModule is BaseModule, BaseSocialRecovery { constructor() EIP712("SocialRecovery", "1") {} + /** + * @dev De-initializes the social recovery settings for the sender's wallet. + */ function _deInit() internal override { address _sender = sender(); _clearWalletSocialRecoveryInfo(_sender); walletInited[_sender] = false; } + /** + * @dev Initializes the social recovery settings for the sender's wallet. + * @param _data The encoded guardian hash and delay period. + */ function _init(bytes calldata _data) internal override { address _sender = sender(); (bytes32 guardianHash, uint256 delayPeroid) = abi.decode(_data, (bytes32, uint256)); @@ -24,10 +37,19 @@ contract SocialRecoveryModule is BaseModule, BaseSocialRecovery { walletInited[_sender] = true; } + /** + * @dev Checks if the social recovery settings for a wallet have been initialized. + * @param wallet The address of the wallet. + * @return A boolean indicating whether the social recovery settings for the wallet have been initialized. + */ function inited(address wallet) internal view override returns (bool) { return walletInited[wallet]; } + /** + * @dev Returns the list of functions required by this module. + * @return An array of function selectors. + */ function requiredFunctions() external pure override returns (bytes4[] memory) { bytes4[] memory functions = new bytes4[](2); functions[0] = _FUNC_RESET_OWNER; diff --git a/contracts/modules/socialRecovery/base/BaseSocialRecovery.sol b/contracts/modules/socialRecovery/base/BaseSocialRecovery.sol index 32a6c8a8..3ec49a99 100644 --- a/contracts/modules/socialRecovery/base/BaseSocialRecovery.sol +++ b/contracts/modules/socialRecovery/base/BaseSocialRecovery.sol @@ -7,6 +7,15 @@ import "@openzeppelin/contracts/interfaces/IERC1271.sol"; import "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; +/** + * @title BaseSocialRecovery + * @dev This abstract contract provides the base implementation for the social recovery functionality. + * It implements the ISocialRecovery interface and extends the EIP712 contract. + * It allows a user to designate a list of guardians for their wallet and establish a recovery threshold. + * If a wallet is lost or compromised, the guardians can initiate a recovery process by signing a special EIP712 signature. + * However, this recovery process is subject to a user-defined time lock period, and can only execute the recovery after this period has passed. + * This mechanism ensures that the user's assets remain secure and recoverable, even in unforeseen circumstances. + */ abstract contract BaseSocialRecovery is ISocialRecovery, EIP712 { using ECDSA for bytes32; @@ -61,26 +70,26 @@ abstract contract BaseSocialRecovery is ISocialRecovery, EIP712 { return OperationState.Ready; } } + /** * @dev Returns whether an operation is pending or not. Note that a "pending" operation may also be "ready". */ - function isOperationPending(address wallet, bytes32 id) public view returns (bool) { OperationState state = getOperationState(wallet, id); return state == OperationState.Waiting || state == OperationState.Ready; } + /** * @dev Returns whether an operation is ready for execution. Note that a "ready" operation is also "pending". */ - function isOperationReady(address wallet, bytes32 id) public view returns (bool) { return getOperationState(wallet, id) == OperationState.Ready; } + /** * @dev Returns whether an id corresponds to a registered operation. This * includes both Waiting, Ready, and Done operations. */ - function isOperationSet(address wallet, bytes32 id) public view returns (bool) { return getOperationState(wallet, id) != OperationState.Unset; } @@ -89,6 +98,11 @@ abstract contract BaseSocialRecovery is ISocialRecovery, EIP712 { return socialRecoveryInfo[wallet].operationValidAt[id]; } + /** + * @notice modify the guardian hash for a wallet + * @dev Emits a GuardianSet event + * @param newGuardianHash The new guardian hash + */ function setGuardian(bytes32 newGuardianHash) external { address wallet = _msgSender(); socialRecoveryInfo[wallet].guardianHash = newGuardianHash; @@ -96,6 +110,11 @@ abstract contract BaseSocialRecovery is ISocialRecovery, EIP712 { emit GuardianSet(wallet, newGuardianHash); } + /** + * @notice Sets the recovery time lock period for a wallet + * @dev Emits a DelayPeriodSet event + * @param newDelay The new delay period + */ function setDelayPeriod(uint256 newDelay) external { address wallet = _msgSender(); socialRecoveryInfo[wallet].delayPeriod = newDelay; @@ -108,10 +127,14 @@ abstract contract BaseSocialRecovery is ISocialRecovery, EIP712 { _increaseNonce(wallet); emit RecoveryCancelled(wallet, 0); } + /** - * @dev Considering that not all contract are EIP-1271 compatible + * @notice Approves a hash for the sender + * the hash is the eip712 hash of the recover operation for guardian to sign + * @dev Considering that not all contracts are EIP-1271 compatible, this function could be called by the guardian if the guardian is a smart contract. + * It emits an ApproveHash event. + * @param hash The hash to be approved */ - function approveHash(bytes32 hash) external { bytes32 key = _approveKey(msg.sender, hash); if (approvedHashes[key] == 1) { @@ -120,6 +143,14 @@ abstract contract BaseSocialRecovery is ISocialRecovery, EIP712 { approvedHashes[key] = 1; emit ApproveHash(msg.sender, hash); } + /** + * + * @notice Rejects a hash for the sender + * the hash is the eip712 hash of the recover operation for guardian to sign + * @dev Considering that not all contracts are EIP-1271 compatible, this function could be called by the guardian if the guardian is a smart contract. + * It emits a RejectHash event. + * @param hash The hash to be rejected + */ function rejectHash(bytes32 hash) external { bytes32 key = _approveKey(msg.sender, hash); @@ -130,6 +161,14 @@ abstract contract BaseSocialRecovery is ISocialRecovery, EIP712 { emit RejectHash(msg.sender, hash); } + /** + * @notice Schedules a recovery operation for a wallet + * @param wallet The address of the wallet + * @param newOwners The new owners to be set for the wallet + * @param rawGuardian The raw guardian data + * @param guardianSignature The signature of the guardian + * @return recoveryId The ID of the recovery operation + */ function scheduleRecovery( address wallet, bytes32[] calldata newOwners, @@ -147,15 +186,19 @@ abstract contract BaseSocialRecovery is ISocialRecovery, EIP712 { emit RecoveryScheduled(wallet, recoveryId, scheduleTime); } + /** + * @notice Executes a recovery operation for a wallet + * @param wallet The address of the wallet + * @param newOwners The new owners to be set for the wallet + */ function executeRecovery(address wallet, bytes32[] calldata newOwners) external override { bytes32 recoveryId = hashOperation(wallet, walletNonce(wallet), abi.encode(newOwners)); if (!isOperationReady(wallet, recoveryId)) { revert UNEXPECTED_OPERATION_STATE(wallet, recoveryId, _encodeStateBitmap(OperationState.Ready)); } - _recoveryOwner(wallet, newOwners); - _setRecoveryDone(wallet, recoveryId); _increaseNonce(wallet); + _recoveryOwner(wallet, newOwners); emit RecoveryExecuted(wallet, recoveryId); } @@ -168,6 +211,10 @@ abstract contract BaseSocialRecovery is ISocialRecovery, EIP712 { soulwallet.resetOwners(newOwners); } + /** + * @notice Verifies the guardian's signature + * @dev This function checks the signature type and verifies it accordingly. It supports EIP-1271 signatures for smart contract wallet, approved hashes, and EOA signatures. + */ function _verifyGuardianSignature( address wallet, uint256 nonce, diff --git a/contracts/modules/socialRecovery/socialReoceryFlow.png b/contracts/modules/socialRecovery/socialReoceryFlow.png new file mode 100644 index 0000000000000000000000000000000000000000..80189deef17d4ec2876b23e89ed3cf0d86cbb433 GIT binary patch literal 32108 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 K&!nC*x%)5f#{7Q( literal 0 HcmV?d00001