From f8469dcfe122f30d719f6763e0c308f5ecc3b83f Mon Sep 17 00:00:00 2001 From: CJ42 Date: Fri, 10 Jan 2025 11:56:44 +0100 Subject: [PATCH] refactor: change import for LSP11 in lsp-smart-contracts to use latest version of LSP11 --- .prettierignore | 3 +- foundry.toml | 10 +- package-lock.json | 1 - packages/lsp-smart-contracts/constants.ts | 3 +- .../ILSP11BasicSocialRecovery.sol | 179 --- .../LSP11BasicSocialRecovery.sol | 25 - .../LSP11BasicSocialRecoveryCore.sol | 340 ----- .../LSP11BasicSocialRecoveryInit.sol | 30 - .../LSP11BasicSocialRecoveryInitAbstract.sol | 29 - .../LSP11Constants.sol | 6 - .../LSP11BasicSocialRecovery/LSP11Errors.sol | 63 - .../ILSP11SocialRecovery.sol | 4 + .../LSP11SocialRecovery/LSP11Constants.sol | 4 + .../LSP11SocialRecovery/LSP11Errors.sol | 4 + .../LSP11SocialRecovery.sol | 4 + .../LSP4DigitalAssetMetadata/LSP4Utils.sol | 2 +- .../contracts/Mocks/ERC165Interfaces.sol | 27 +- .../LSP11BasicSocialRecovery.behaviour.ts | 1135 ----------------- .../LSP11BasicSocialRecovery.test.ts | 71 -- .../LSP11BasicSocialRecoveryInit.test.ts | 111 -- .../tests/Mocks/ERC165Interfaces.test.ts | 2 +- .../LSP11BasicSocialRecovery.t.sol | 75 -- .../LSP11BasicSocialRecovery/LSP11Mock.sol | 41 - .../contracts/LSP11SocialRecovery.sol | 22 +- ....sol => LSP11AccountFunctionalities.t.sol} | 0 packages/lsp11-contracts/package.json | 1 - .../lsp4-contracts/contracts/LSP4Utils.sol | 2 +- publish.mjs | 12 +- 28 files changed, 65 insertions(+), 2141 deletions(-) delete mode 100644 packages/lsp-smart-contracts/contracts/LSP11BasicSocialRecovery/ILSP11BasicSocialRecovery.sol delete mode 100644 packages/lsp-smart-contracts/contracts/LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.sol delete mode 100644 packages/lsp-smart-contracts/contracts/LSP11BasicSocialRecovery/LSP11BasicSocialRecoveryCore.sol delete mode 100644 packages/lsp-smart-contracts/contracts/LSP11BasicSocialRecovery/LSP11BasicSocialRecoveryInit.sol delete mode 100644 packages/lsp-smart-contracts/contracts/LSP11BasicSocialRecovery/LSP11BasicSocialRecoveryInitAbstract.sol delete mode 100644 packages/lsp-smart-contracts/contracts/LSP11BasicSocialRecovery/LSP11Constants.sol delete mode 100644 packages/lsp-smart-contracts/contracts/LSP11BasicSocialRecovery/LSP11Errors.sol create mode 100644 packages/lsp-smart-contracts/contracts/LSP11SocialRecovery/ILSP11SocialRecovery.sol create mode 100644 packages/lsp-smart-contracts/contracts/LSP11SocialRecovery/LSP11Constants.sol create mode 100644 packages/lsp-smart-contracts/contracts/LSP11SocialRecovery/LSP11Errors.sol create mode 100644 packages/lsp-smart-contracts/contracts/LSP11SocialRecovery/LSP11SocialRecovery.sol delete mode 100644 packages/lsp-smart-contracts/tests/LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.behaviour.ts delete mode 100644 packages/lsp-smart-contracts/tests/LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.test.ts delete mode 100644 packages/lsp-smart-contracts/tests/LSP11BasicSocialRecovery/LSP11BasicSocialRecoveryInit.test.ts delete mode 100644 packages/lsp-smart-contracts/tests/foundry/LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.t.sol delete mode 100644 packages/lsp-smart-contracts/tests/foundry/LSP11BasicSocialRecovery/LSP11Mock.sol rename packages/lsp11-contracts/foundry/{LSP11UniversalRecovery.t.sol => LSP11AccountFunctionalities.t.sol} (100%) diff --git a/.prettierignore b/.prettierignore index cc34a39c8..b394cac03 100644 --- a/.prettierignore +++ b/.prettierignore @@ -12,4 +12,5 @@ /package /module packages/*/types/ -packages/*/artifacts/ \ No newline at end of file +packages/*/artifacts/ +packages/*/CHANGELOG.md diff --git a/foundry.toml b/foundry.toml index 2873a92a8..cb15bda7d 100644 --- a/foundry.toml +++ b/foundry.toml @@ -21,16 +21,16 @@ src = 'packages/lsp2-contracts/contracts' test = 'packages/lsp2-contracts/foundry' out = 'packages/lsp2-contracts/contracts/foundry_artifacts' -[profile.lsp11] -src = 'packages/lsp11-contracts/contracts' -test = 'packages/lsp11-contracts/foundry' -out = 'packages/lsp11-contracts/contracts/foundry_artifacts' - [profile.lsp6] src = 'packages/lsp6-contracts/contracts' test = 'packages/lsp6-contracts/foundry' out = 'packages/lsp6-contracts/contracts/foundry_artifacts' +[profile.lsp11] +src = 'packages/lsp11-contracts/contracts' +test = 'packages/lsp11-contracts/foundry' +out = 'packages/lsp11-contracts/contracts/foundry_artifacts' + [profile.lsp16] src = 'packages/lsp16-contracts/contracts' test = 'packages/lsp16-contracts/foundry' diff --git a/package-lock.json b/package-lock.json index deecc59a0..f3d486f23 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18256,7 +18256,6 @@ "version": "0.1.0", "license": "Apache-2.0", "dependencies": { - "@erc725/smart-contracts": "^7.0.0", "@lukso/lsp25-contracts": "~0.15.0", "@openzeppelin/contracts": "^4.9.6" } diff --git a/packages/lsp-smart-contracts/constants.ts b/packages/lsp-smart-contracts/constants.ts index d78844d9e..488d57a39 100644 --- a/packages/lsp-smart-contracts/constants.ts +++ b/packages/lsp-smart-contracts/constants.ts @@ -43,6 +43,7 @@ import { INTERFACE_ID_LSP6 } from '@lukso/lsp6-contracts'; import { INTERFACE_ID_LSP7 } from '@lukso/lsp7-contracts'; import { INTERFACE_ID_LSP8 } from '@lukso/lsp8-contracts'; import { INTERFACE_ID_LSP9 } from '@lukso/lsp9-contracts'; +import { INTERFACE_ID_LSP11 } from '@lukso/lsp11-contracts'; import { INTERFACE_ID_LSP14 } from '@lukso/lsp14-contracts'; import { INTERFACE_ID_LSP17Extendable, @@ -111,12 +112,12 @@ export const INTERFACE_IDS = { LSP7DigitalAsset: INTERFACE_ID_LSP7, LSP8IdentifiableDigitalAsset: INTERFACE_ID_LSP8, LSP9Vault: INTERFACE_ID_LSP9, + LSP11SocialRecovery: INTERFACE_ID_LSP11, LSP14Ownable2Step: INTERFACE_ID_LSP14, LSP17Extendable: INTERFACE_ID_LSP17Extendable, LSP17Extension: INTERFACE_ID_LSP17Extension, LSP20CallVerification: INTERFACE_ID_LSP20CallVerification, LSP20CallVerifier: INTERFACE_ID_LSP20CallVerifier, - LSP11BasicSocialRecovery: '0x049a28f1', LSP25ExecuteRelayCall: INTERFACE_ID_LSP25, LSP26FollowerSystem: INTERFACE_ID_LSP26, } as const; diff --git a/packages/lsp-smart-contracts/contracts/LSP11BasicSocialRecovery/ILSP11BasicSocialRecovery.sol b/packages/lsp-smart-contracts/contracts/LSP11BasicSocialRecovery/ILSP11BasicSocialRecovery.sol deleted file mode 100644 index 4259c2b72..000000000 --- a/packages/lsp-smart-contracts/contracts/LSP11BasicSocialRecovery/ILSP11BasicSocialRecovery.sol +++ /dev/null @@ -1,179 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.0; - -/** - * @title Interface of the LSP11 - Basic Social Recovery standard, a contract to recover access control into an account. - * @dev Sets permission for a controller address after a recovery process to interact with an ERC725 - * contract via the LSP6KeyManager - */ -interface ILSP11BasicSocialRecovery { - /** - * @notice Emitted when setting a new guardian for the target - * @param newGuardian The address of the added guardian - */ - event GuardianAdded(address indexed newGuardian); - - /** - * @notice Emitted when removing an existing guardian for the target - * @param removedGuardian The address of the guardian removed - */ - event GuardianRemoved(address indexed removedGuardian); - - /** - * @notice Emitted when changing the guardian threshold - * @param guardianThreshold The minimum number of selection by guardians needed by a controller to start - * a recovery process - */ - event GuardiansThresholdChanged(uint256 indexed guardianThreshold); - - /** - * @notice Emitted when changing the secret hash - * @param secretHash The secret hash used to finish the recovery process - */ - event SecretHashChanged(bytes32 indexed secretHash); - - /** - * @notice Emitted when a guardian select a new potential controller address for the target - * @param recoveryCounter The current recovery process counter - * @param guardian The address of the guardian - * @param addressSelected The address selected by the guardian - */ - event SelectedNewController( - uint256 indexed recoveryCounter, - address indexed guardian, - address indexed addressSelected - ); - - /** - * @notice Emitted when the recovery process is finished by the controller who - * reached the guardian threshold and submitted the string that produce the secretHash - * @param recoveryCounter The current recovery process - * @param newController The address of the new controller controlling the target by the KeyManager - * @param guardians The array of addresses containing the guardians of the target - */ - event RecoveryProcessSuccessful( - uint256 indexed recoveryCounter, - address indexed newController, - bytes32 indexed newSecretHash, - address[] guardians - ); - - /** - * @dev The address of an ERC725 contract where we want to recover - * and set permissions for a controller address - */ - function target() external view returns (address); - - /** - * @dev Returns the current recovery counter - * When a recovery process is successfully finished the recovery counter is incremented - */ - function getRecoveryCounter() external view returns (uint256); - - /** - * @dev Returns the addresses of all guardians - * The guardians will select an address to be added as a controller - * key for the linked `target` if he reaches the guardian threshold and - * provide the correct string that produce the secretHash - */ - function getGuardians() external view returns (address[] memory); - - /** - * @dev Returns TRUE if the address provided is a guardian, FALSE otherwise - * @param _address The address to query - */ - function isGuardian(address _address) external view returns (bool); - - /** - * @dev Returns the recovery secret hash - */ - function getRecoverySecretHash() external view returns (bytes32); - - /** - * @dev Returns the guardian threshold - * The guardian threshold represents the minimum number of selection by guardians required - * for an address to start a recovery process - */ - function getGuardiansThreshold() external view returns (uint256); - - /** - * @dev Returns the address of a controller that a `guardian` selected for in order to recover the target - * @param guardian the address of a guardian to query his selection - * @return the address that `guardian` selected - */ - function getGuardianChoice( - address guardian - ) external view returns (address); - - /** - * @dev Adds a guardian of the target - * @dev Can be called only by the owner - * @param newGuardian The address to add as a guardian - */ - function addGuardian(address newGuardian) external; - - /** - * @dev Removes a guardian of the target - * @dev Can be called only by the owner - * @param currentGuardian The address of the existing guardian to remove - * - * Requirements: - * - * - The guardians count should be higher or equal to the guardian threshold - */ - function removeGuardian(address currentGuardian) external; - - /** - * @dev Sets the hash of the secret string to be provided in `recoverOwnership(..)` function - * @dev Can be called only by the owner - * @param newRecoverSecretHash The hash of the secret string - * - * Requirements: - * - * - `secretHash` cannot be bytes32(0) - */ - function setRecoverySecretHash(bytes32 newRecoverSecretHash) external; - - /** - * @dev Sets the minimum number of selection by the guardians required so that an - * address can recover ownership - * - * @dev Can be called only by the owner - * @param guardiansThreshold The threshold to set - * - * Requirements: - * - `guardiansThreshold` cannot be more than the guardians count. - */ - function setGuardiansThreshold(uint256 guardiansThreshold) external; - - /** - * @dev select an address to be a potential controller address if he reaches - * the guardian threshold and provide the correct secret string - * - * Requirements: - * - only guardians can select an address - * - * @param addressSelected The address selected by the guardian - */ - function selectNewController(address addressSelected) external; - - /** - * @dev Recovers the ownership permissions of an address in the linked target - * and increment the recover counter - * - * Requirements - * - the address of the recoverer must have a selection equal or higher than the threshold - * defined in `getGuardiansThreshold(...)` - * - * - must have provided the right `plainSecret` that produces the secret Hash - * - * @param recoverer The address of the recoverer - * @param plainSecret The secret word that produce the secret Hash - * @param newHash The new secret Hash to be used in the next recovery process - */ - function recoverOwnership( - address recoverer, - string memory plainSecret, - bytes32 newHash - ) external; -} diff --git a/packages/lsp-smart-contracts/contracts/LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.sol b/packages/lsp-smart-contracts/contracts/LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.sol deleted file mode 100644 index fa3df8e6a..000000000 --- a/packages/lsp-smart-contracts/contracts/LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.sol +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.0; - -// modules -import { - OwnableUnset -} from "@erc725/smart-contracts/contracts/custom/OwnableUnset.sol"; -import {LSP11BasicSocialRecoveryCore} from "./LSP11BasicSocialRecoveryCore.sol"; - -/** - * @title Implementation of LSP11 - Basic Social Recovery standard - * @dev Sets permission for a controller address after a recovery process to interact with an ERC725 - * contract via the LSP6KeyManager - */ -contract LSP11BasicSocialRecovery is LSP11BasicSocialRecoveryCore { - /** - * @notice Sets the target and the owner addresses - * @param _owner The owner of the LSP11 contract - * @param target_ The address of the ER725 contract to recover - */ - constructor(address _owner, address target_) { - OwnableUnset._setOwner(_owner); - _target = target_; - } -} diff --git a/packages/lsp-smart-contracts/contracts/LSP11BasicSocialRecovery/LSP11BasicSocialRecoveryCore.sol b/packages/lsp-smart-contracts/contracts/LSP11BasicSocialRecovery/LSP11BasicSocialRecoveryCore.sol deleted file mode 100644 index 0dd64c689..000000000 --- a/packages/lsp-smart-contracts/contracts/LSP11BasicSocialRecovery/LSP11BasicSocialRecoveryCore.sol +++ /dev/null @@ -1,340 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.4; - -// interfaces -import {ILSP11BasicSocialRecovery} from "./ILSP11BasicSocialRecovery.sol"; - -// libraries -import {LSP6Utils} from "@lukso/lsp6-contracts/contracts/LSP6Utils.sol"; - -// modules -import {ERC725} from "@erc725/smart-contracts/contracts/ERC725.sol"; -import { - OwnableUnset -} from "@erc725/smart-contracts/contracts/custom/OwnableUnset.sol"; -import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; -import { - EnumerableSet -} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; - -// constants -import { - ALL_REGULAR_PERMISSIONS -} from "@lukso/lsp6-contracts/contracts/LSP6Constants.sol"; -import {_INTERFACEID_LSP11} from "./LSP11Constants.sol"; -import { - CallerIsNotGuardian, - GuardianAlreadyExist, - GuardianDoNotExist, - GuardiansNumberCannotGoBelowThreshold, - ThresholdCannotBeHigherThanGuardiansNumber, - SecretHashCannotBeZero, - AddressZeroNotAllowed, - ThresholdNotReachedForRecoverer, - WrongPlainSecret -} from "./LSP11Errors.sol"; - -/** - * @title Core Implementation of LSP11-BasicSocialRecovery standard - * @dev Sets permission for a controller address after a recovery process to interact with an ERC725 - * contract via the LSP6KeyManager - */ -abstract contract LSP11BasicSocialRecoveryCore is - OwnableUnset, - ERC165, - ILSP11BasicSocialRecovery -{ - using EnumerableSet for EnumerableSet.AddressSet; - - address internal _target; - - // The guardians threshold - uint256 internal _guardiansThreshold; - - // The number of successful recovery processes - uint256 internal _recoveryCounter; - - // The secret hash to be set by the owner - bytes32 internal _recoverySecretHash; - - // Stores the address selected by a guardian - // in the current `_recoveryCounter` - mapping(uint256 => mapping(address => address)) internal _guardiansChoice; - - // List of guardians addresses - EnumerableSet.AddressSet internal _guardians; - - /** - * @dev Throws if called by any account other than the guardians - */ - modifier onlyGuardians() virtual { - if (!_guardians.contains(msg.sender)) - revert CallerIsNotGuardian(msg.sender); - _; - } - - /** - * @inheritdoc ERC165 - */ - function supportsInterface( - bytes4 _interfaceId - ) public view virtual override returns (bool) { - return - _interfaceId == _INTERFACEID_LSP11 || - super.supportsInterface(_interfaceId); - } - - /** - * @inheritdoc ILSP11BasicSocialRecovery - */ - function target() public view virtual override returns (address) { - return _target; - } - - /** - * @inheritdoc ILSP11BasicSocialRecovery - */ - function getRecoveryCounter() - public - view - virtual - override - returns (uint256) - { - return _recoveryCounter; - } - - /** - * @inheritdoc ILSP11BasicSocialRecovery - */ - function getGuardians() - public - view - virtual - override - returns (address[] memory) - { - return _guardians.values(); - } - - /** - * @inheritdoc ILSP11BasicSocialRecovery - */ - function isGuardian( - address _address - ) public view virtual override returns (bool) { - return _guardians.contains(_address); - } - - /** - * @inheritdoc ILSP11BasicSocialRecovery - */ - function getGuardiansThreshold() - public - view - virtual - override - returns (uint256) - { - return _guardiansThreshold; - } - - /** - * @inheritdoc ILSP11BasicSocialRecovery - */ - function getRecoverySecretHash() - public - view - virtual - override - returns (bytes32) - { - return _recoverySecretHash; - } - - /** - * @inheritdoc ILSP11BasicSocialRecovery - */ - function getGuardianChoice( - address guardian - ) public view virtual override returns (address) { - return _guardiansChoice[_recoveryCounter][guardian]; - } - - /** - * @inheritdoc ILSP11BasicSocialRecovery - */ - function addGuardian( - address newGuardian - ) public virtual override onlyOwner { - if (_guardians.contains(newGuardian)) - revert GuardianAlreadyExist(newGuardian); - - _guardians.add(newGuardian); - emit GuardianAdded(newGuardian); - } - - /** - * @inheritdoc ILSP11BasicSocialRecovery - */ - function removeGuardian( - address existingGuardian - ) public virtual override onlyOwner { - if (!_guardians.contains(existingGuardian)) - revert GuardianDoNotExist(existingGuardian); - if (_guardians.length() == _guardiansThreshold) - revert GuardiansNumberCannotGoBelowThreshold(_guardiansThreshold); - - _guardians.remove(existingGuardian); - emit GuardianRemoved(existingGuardian); - } - - /** - * @inheritdoc ILSP11BasicSocialRecovery - */ - function setGuardiansThreshold( - uint256 newThreshold - ) public virtual override onlyOwner { - if (newThreshold > _guardians.length()) - revert ThresholdCannotBeHigherThanGuardiansNumber( - newThreshold, - _guardians.length() - ); - - _guardiansThreshold = newThreshold; - emit GuardiansThresholdChanged(newThreshold); - } - - /** - * @inheritdoc ILSP11BasicSocialRecovery - * @dev Throws if hash provided is bytes32(0) - */ - function setRecoverySecretHash( - bytes32 newRecoverSecretHash - ) public virtual override onlyOwner { - if (newRecoverSecretHash == bytes32(0)) revert SecretHashCannotBeZero(); - - _recoverySecretHash = newRecoverSecretHash; - emit SecretHashChanged(newRecoverSecretHash); - } - - /** - * @inheritdoc ILSP11BasicSocialRecovery - */ - function selectNewController( - address addressSelected - ) public virtual override onlyGuardians { - uint256 currentRecoveryCounter = _recoveryCounter; - - _guardiansChoice[currentRecoveryCounter][msg.sender] = addressSelected; - emit SelectedNewController( - currentRecoveryCounter, - msg.sender, - addressSelected - ); - } - - /** - * @inheritdoc ILSP11BasicSocialRecovery - */ - function recoverOwnership( - address recoverer, - string memory plainSecret, - bytes32 newSecretHash - ) public virtual override { - // caching storage variables - uint256 currentRecoveryCounter = _recoveryCounter; - address[] memory guardians = _guardians.values(); - address target_ = _target; - - _validateRequirements( - recoverer, - currentRecoveryCounter, - plainSecret, - newSecretHash, - guardians - ); - - _recoveryCounter++; - _recoverySecretHash = newSecretHash; - emit SecretHashChanged(newSecretHash); - - address keyManager = ERC725(target_).owner(); - - // Setting permissions for `recoverer` - (bytes32[] memory keys, bytes[] memory values) = LSP6Utils - .generateNewPermissionsKeys( - ERC725(target_), - recoverer, - ALL_REGULAR_PERMISSIONS - ); - - LSP6Utils.setDataViaKeyManager(keyManager, keys, values); - - emit RecoveryProcessSuccessful( - currentRecoveryCounter, - recoverer, - newSecretHash, - guardians - ); - - _cleanStorage(currentRecoveryCounter, guardians.length, guardians); - } - - /** - * @dev The number of guardians should be reasonable, as the validation method - * is using a loop to check the selection of each guardian - * - * Throws if: - * - The address trying to recover didn't reach the guardiansThreshold - * - The new hash being set is bytes32(0) - * - The secret word provided is incorrect - */ - function _validateRequirements( - address recoverer, - uint256 currentRecoveryCounter, - string memory plainSecret, - bytes32 newHash, - address[] memory guardians - ) internal view virtual { - if (recoverer == address(0)) revert AddressZeroNotAllowed(); - uint256 callerSelections; - - unchecked { - for (uint256 i; i < guardians.length; i++) { - if ( - _guardiansChoice[currentRecoveryCounter][guardians[i]] == - recoverer - ) callerSelections++; - } - } - - uint256 guardiansThreshold = _guardiansThreshold; - - if (callerSelections < guardiansThreshold) - revert ThresholdNotReachedForRecoverer( - recoverer, - callerSelections, - guardiansThreshold - ); - if (newHash == bytes32(0)) revert SecretHashCannotBeZero(); - if (keccak256(abi.encodePacked(plainSecret)) != _recoverySecretHash) - revert WrongPlainSecret(); - } - - /** - * @dev Remove the guardians choice after a successful recovery process - * To avoid keeping unnecessary state - */ - function _cleanStorage( - uint256 recoveryCounter, - uint256 guardiansLength, - address[] memory guardians - ) internal virtual { - unchecked { - for (uint256 i; i < guardiansLength; i++) { - delete _guardiansChoice[recoveryCounter][guardians[i]]; - } - } - } -} diff --git a/packages/lsp-smart-contracts/contracts/LSP11BasicSocialRecovery/LSP11BasicSocialRecoveryInit.sol b/packages/lsp-smart-contracts/contracts/LSP11BasicSocialRecovery/LSP11BasicSocialRecoveryInit.sol deleted file mode 100644 index 873a507fc..000000000 --- a/packages/lsp-smart-contracts/contracts/LSP11BasicSocialRecovery/LSP11BasicSocialRecoveryInit.sol +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.0; - -// modules -import { - LSP11BasicSocialRecoveryInitAbstract -} from "./LSP11BasicSocialRecoveryInitAbstract.sol"; - -/** - * @title Deployable Proxy Implementation of LSP11 - Basic Social Recovery standard - * @dev Sets permission for a controller address after a recovery process to interact with an ERC725 - * contract via the LSP6KeyManager - */ -contract LSP11BasicSocialRecoveryInit is LSP11BasicSocialRecoveryInitAbstract { - constructor() { - _disableInitializers(); - } - - /** - * @notice Sets the target and the owner addresses - * @param _owner The owner of the LSP11 contract - * @param target_ The address of the ER725 contract to recover - */ - function initialize( - address target_, - address _owner - ) public virtual initializer { - LSP11BasicSocialRecoveryInitAbstract._initialize(target_, _owner); - } -} diff --git a/packages/lsp-smart-contracts/contracts/LSP11BasicSocialRecovery/LSP11BasicSocialRecoveryInitAbstract.sol b/packages/lsp-smart-contracts/contracts/LSP11BasicSocialRecovery/LSP11BasicSocialRecoveryInitAbstract.sol deleted file mode 100644 index 9d3d45709..000000000 --- a/packages/lsp-smart-contracts/contracts/LSP11BasicSocialRecovery/LSP11BasicSocialRecoveryInitAbstract.sol +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.0; - -// modules -import { - Initializable -} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; -import { - OwnableUnset -} from "@erc725/smart-contracts/contracts/custom/OwnableUnset.sol"; -import {LSP11BasicSocialRecoveryCore} from "./LSP11BasicSocialRecoveryCore.sol"; - -/** - * @title Inheritable Proxy Implementation of LSP11 - Basic Social Recovery standard - * @dev Sets permission for a controller address after a recovery process to interact with an ERC725 - * contract via the LSP6KeyManager - */ -contract LSP11BasicSocialRecoveryInitAbstract is - Initializable, - LSP11BasicSocialRecoveryCore -{ - function _initialize( - address _owner, - address target_ - ) internal virtual onlyInitializing { - OwnableUnset._setOwner(_owner); - _target = target_; - } -} diff --git a/packages/lsp-smart-contracts/contracts/LSP11BasicSocialRecovery/LSP11Constants.sol b/packages/lsp-smart-contracts/contracts/LSP11BasicSocialRecovery/LSP11Constants.sol deleted file mode 100644 index 66ceb1657..000000000 --- a/packages/lsp-smart-contracts/contracts/LSP11BasicSocialRecovery/LSP11Constants.sol +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.0; - -// --- ERC165 interface ids - -bytes4 constant _INTERFACEID_LSP11 = 0x049a28f1; diff --git a/packages/lsp-smart-contracts/contracts/LSP11BasicSocialRecovery/LSP11Errors.sol b/packages/lsp-smart-contracts/contracts/LSP11BasicSocialRecovery/LSP11Errors.sol deleted file mode 100644 index 6c6951c2b..000000000 --- a/packages/lsp-smart-contracts/contracts/LSP11BasicSocialRecovery/LSP11Errors.sol +++ /dev/null @@ -1,63 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.0; - -// --- Errors - -/** - * @dev reverts when the caller is not a guardian - */ -error CallerIsNotGuardian(address caller); - -/** - * @dev reverts when adding an already existing guardian - */ -error GuardianAlreadyExist(address addressToAdd); - -/** - * @dev reverts when removing a non-existing guardian - */ -error GuardianDoNotExist(address addressToRemove); - -/** - * @dev reverts when removing a guardian and the threshold - * is equal to the number of guardians - */ -error GuardiansNumberCannotGoBelowThreshold(uint256 guardianThreshold); - -/** - * @dev reverts when setting the guardians threshold to a number - * higher than the guardians number - */ -error ThresholdCannotBeHigherThanGuardiansNumber( - uint256 thresholdGiven, - uint256 guardianNumber -); - -/** - * @dev reverts when the secret hash provided is equal to bytes32(0) - */ -error SecretHashCannotBeZero(); - -/** - * @dev reverts when `recoverOwnership(..)` is called with a recoverer that didn't reach - * the guardians threshold - * @param recoverer The address of the recoverer - * @param selections The number of selections that the recoverer have - * @param guardiansThreshold The minimum number of selection needed - */ -error ThresholdNotReachedForRecoverer( - address recoverer, - uint256 selections, - uint256 guardiansThreshold -); - -/** - * @dev reverts when the plain secret produce a different hash than the - * secret hash originally set - */ -error WrongPlainSecret(); - -/** - * @dev reverts when the address zero calls `recoverOwnership(..)` function - */ -error AddressZeroNotAllowed(); diff --git a/packages/lsp-smart-contracts/contracts/LSP11SocialRecovery/ILSP11SocialRecovery.sol b/packages/lsp-smart-contracts/contracts/LSP11SocialRecovery/ILSP11SocialRecovery.sol new file mode 100644 index 000000000..b3f64090e --- /dev/null +++ b/packages/lsp-smart-contracts/contracts/LSP11SocialRecovery/ILSP11SocialRecovery.sol @@ -0,0 +1,4 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.9; + +import "@lukso/lsp11-contracts/contracts/ILSP11SocialRecovery.sol"; diff --git a/packages/lsp-smart-contracts/contracts/LSP11SocialRecovery/LSP11Constants.sol b/packages/lsp-smart-contracts/contracts/LSP11SocialRecovery/LSP11Constants.sol new file mode 100644 index 000000000..37b8ab43f --- /dev/null +++ b/packages/lsp-smart-contracts/contracts/LSP11SocialRecovery/LSP11Constants.sol @@ -0,0 +1,4 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.9; + +import "@lukso/lsp11-contracts/contracts/LSP11Constants.sol"; diff --git a/packages/lsp-smart-contracts/contracts/LSP11SocialRecovery/LSP11Errors.sol b/packages/lsp-smart-contracts/contracts/LSP11SocialRecovery/LSP11Errors.sol new file mode 100644 index 000000000..220656d94 --- /dev/null +++ b/packages/lsp-smart-contracts/contracts/LSP11SocialRecovery/LSP11Errors.sol @@ -0,0 +1,4 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.9; + +import "@lukso/lsp11-contracts/contracts/LSP11Errors.sol"; diff --git a/packages/lsp-smart-contracts/contracts/LSP11SocialRecovery/LSP11SocialRecovery.sol b/packages/lsp-smart-contracts/contracts/LSP11SocialRecovery/LSP11SocialRecovery.sol new file mode 100644 index 000000000..1e89b30a9 --- /dev/null +++ b/packages/lsp-smart-contracts/contracts/LSP11SocialRecovery/LSP11SocialRecovery.sol @@ -0,0 +1,4 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.9; + +import "@lukso/lsp11-contracts/contracts/LSP11SocialRecovery.sol"; diff --git a/packages/lsp-smart-contracts/contracts/LSP4DigitalAssetMetadata/LSP4Utils.sol b/packages/lsp-smart-contracts/contracts/LSP4DigitalAssetMetadata/LSP4Utils.sol index dad7017b9..72fabe536 100644 --- a/packages/lsp-smart-contracts/contracts/LSP4DigitalAssetMetadata/LSP4Utils.sol +++ b/packages/lsp-smart-contracts/contracts/LSP4DigitalAssetMetadata/LSP4Utils.sol @@ -1,4 +1,4 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.24; +pragma solidity ^0.8.4; import "@lukso/lsp4-contracts/contracts/LSP4Utils.sol"; diff --git a/packages/lsp-smart-contracts/contracts/Mocks/ERC165Interfaces.sol b/packages/lsp-smart-contracts/contracts/Mocks/ERC165Interfaces.sol index 89e9f3aa1..eef928ec3 100644 --- a/packages/lsp-smart-contracts/contracts/Mocks/ERC165Interfaces.sol +++ b/packages/lsp-smart-contracts/contracts/Mocks/ERC165Interfaces.sol @@ -53,8 +53,8 @@ import { ILSP9Vault as ILSP9 } from "@lukso/lsp9-contracts/contracts/ILSP9Vault.sol"; import { - ILSP11BasicSocialRecovery as ILSP11 -} from "../LSP11BasicSocialRecovery/ILSP11BasicSocialRecovery.sol"; + ILSP11SocialRecovery as ILSP11 +} from "../LSP11SocialRecovery/ILSP11SocialRecovery.sol"; import { ILSP14Ownable2Step as ILSP14 } from "@lukso/lsp14-contracts/contracts/ILSP14Ownable2Step.sol"; @@ -88,9 +88,7 @@ import { import { _INTERFACEID_LSP9 } from "@lukso/lsp9-contracts/contracts/LSP9Constants.sol"; -import { - _INTERFACEID_LSP11 -} from "../LSP11BasicSocialRecovery/LSP11Constants.sol"; +import {_INTERFACEID_LSP11} from "../LSP11SocialRecovery/LSP11Constants.sol"; import { _INTERFACEID_LSP14 } from "@lukso/lsp14-contracts/contracts/LSP14Constants.sol"; @@ -161,7 +159,9 @@ contract CalculateLSPInterfaces { } function calculateInterfaceLSP6KeyManager() public pure returns (bytes4) { - bytes4 interfaceId = type(ILSP6).interfaceId ^ + // prettier-ignore + bytes4 interfaceId = + type(ILSP6).interfaceId ^ type(IERC1271).interfaceId ^ calculateInterfaceLSP20CallVerifier() ^ calculateInterfaceLSP25ExecuteRelayCall(); @@ -175,7 +175,9 @@ contract CalculateLSPInterfaces { } function calculateInterfaceLSP7() public pure returns (bytes4) { - bytes4 interfaceId = type(ILSP7).interfaceId ^ + // prettier-ignore + bytes4 interfaceId = + type(ILSP7).interfaceId ^ type(IERC725Y).interfaceId ^ calculateInterfaceLSP17Extendable(); @@ -188,7 +190,9 @@ contract CalculateLSPInterfaces { } function calculateInterfaceLSP8() public pure returns (bytes4) { - bytes4 interfaceId = type(ILSP8).interfaceId ^ + // prettier-ignore + bytes4 interfaceId = + type(ILSP8).interfaceId ^ type(IERC725Y).interfaceId ^ calculateInterfaceLSP17Extendable(); @@ -219,11 +223,14 @@ contract CalculateLSPInterfaces { } function calculateInterfaceLSP11() public pure returns (bytes4) { - bytes4 interfaceId = type(ILSP11).interfaceId; + // prettier-ignore + bytes4 interfaceId = + type(ILSP11).interfaceId ^ + type(ILSP25).interfaceId; require( interfaceId == _INTERFACEID_LSP11, - "_LSP11_INTERFACE_ID does not match XOR of the functions" + "hardcoded _LSP11_INTERFACE_ID does not match XOR of the functions" ); return interfaceId; diff --git a/packages/lsp-smart-contracts/tests/LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.behaviour.ts b/packages/lsp-smart-contracts/tests/LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.behaviour.ts deleted file mode 100644 index a5c3b3edb..000000000 --- a/packages/lsp-smart-contracts/tests/LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.behaviour.ts +++ /dev/null @@ -1,1135 +0,0 @@ -import { ethers } from 'hardhat'; -import { expect } from 'chai'; -import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; - -import { LSP11BasicSocialRecovery, LSP6KeyManager, UniversalProfile } from '../../types'; - -import { ERC725YDataKeys, INTERFACE_IDS } from '../../constants'; -import { ALL_PERMISSIONS } from '@lukso/lsp6-contracts'; - -import { callPayload } from '../utils/fixtures'; -import { ContractTransactionResponse } from 'ethers'; - -export type LSP11TestAccounts = { - owner: SignerWithAddress; - addressASelected: SignerWithAddress; - addressBSelected: SignerWithAddress; - any: SignerWithAddress; - random: SignerWithAddress; - - guardian1: SignerWithAddress; - guardian2: SignerWithAddress; - guardian3: SignerWithAddress; - guardian4: SignerWithAddress; -}; - -export const getNamedAccounts = async (): Promise => { - const [ - owner, - addressASelected, - addressBSelected, - any, - random, - guardian1, - guardian2, - guardian3, - guardian4, - ] = await ethers.getSigners(); - - return { - owner, - addressASelected, - addressBSelected, - any, - random, - guardian1, - guardian2, - guardian3, - guardian4, - }; -}; - -export type LSP11DeployParams = { - owner: UniversalProfile; - target: UniversalProfile; -}; - -export type LSP11TestContext = { - accounts: LSP11TestAccounts; - lsp11BasicSocialRecovery: LSP11BasicSocialRecovery; - deployParams: LSP11DeployParams; - universalProfile: UniversalProfile; - lsp6KeyManager: LSP6KeyManager; -}; - -export const shouldBehaveLikeLSP11 = (buildContext: () => Promise) => { - let context: LSP11TestContext; - - describe('When using the contract as password recovery', () => { - before(async () => { - context = await buildContext(); - }); - - describe('when testing owner functionalities', () => { - it('Should revert when non-owner calls `setRecoverySecretHash(..)`', async () => { - const txParams = { - hash: ethers.solidityPackedKeccak256(['string'], ['LUKSO']), - }; - - await expect( - context.lsp11BasicSocialRecovery - .connect(context.accounts.any) - .setRecoverySecretHash(txParams.hash), - ).to.be.revertedWithCustomError( - context.lsp11BasicSocialRecovery, - 'OwnableCallerNotTheOwner', - ); - }); - - it('Should revert when owner calls `setRecoverySecretHash(..)` with bytes32(0) as secret', async () => { - const txParams = { - hash: '0x0000000000000000000000000000000000000000000000000000000000000000', - }; - - const payload = context.lsp11BasicSocialRecovery.interface.encodeFunctionData( - 'setRecoverySecretHash', - [txParams.hash], - ); - - await expect( - context.lsp6KeyManager - .connect(context.accounts.owner) - .execute( - callPayload( - context.universalProfile, - await context.lsp11BasicSocialRecovery.getAddress(), - payload, - ), - ), - ).to.be.revertedWithCustomError(context.lsp11BasicSocialRecovery, 'SecretHashCannotBeZero'); - }); - - it('Should pass when owner calls `setRecoverySecretHash(..)`', async () => { - const txParams = { - hash: ethers.solidityPackedKeccak256(['string'], ['LUKSO']), - }; - - const payload = context.lsp11BasicSocialRecovery.interface.encodeFunctionData( - 'setRecoverySecretHash', - [txParams.hash], - ); - - await expect( - context.lsp6KeyManager - .connect(context.accounts.owner) - .execute( - callPayload( - context.universalProfile, - await context.lsp11BasicSocialRecovery.getAddress(), - payload, - ), - ), - ) - .to.emit(context.lsp11BasicSocialRecovery, 'SecretHashChanged') - .withArgs(txParams.hash); - }); - }); - - describe('when testing recovery', () => { - describe('when providing the wrong plainSecret', () => { - it('should revert', async () => { - const txParams = { - secret: 'NotLUKSO', - newHash: ethers.solidityPackedKeccak256(['string'], ['UniversalProfiles']), - }; - - await expect( - context.lsp11BasicSocialRecovery - .connect(context.accounts.addressASelected) - .recoverOwnership( - context.accounts.addressASelected.address, - txParams.secret, - txParams.newHash, - ), - ).to.be.revertedWithCustomError(context.lsp11BasicSocialRecovery, 'WrongPlainSecret'); - }); - }); - - describe('when providing bytes32(0) as newSecretHash', () => { - it('should revert', async () => { - const txParams = { - secret: 'LUKSO', - newHash: '0x0000000000000000000000000000000000000000000000000000000000000000', - }; - - await expect( - context.lsp11BasicSocialRecovery - .connect(context.accounts.addressASelected) - .recoverOwnership( - context.accounts.addressASelected.address, - txParams.secret, - txParams.newHash, - ), - ).to.be.revertedWithCustomError( - context.lsp11BasicSocialRecovery, - 'SecretHashCannotBeZero', - ); - }); - }); - - describe('when providing the correct plainSecret and a valid newHash', () => { - let recoveryTx; - let txParams; - let recoveryCounterBeforeRecovery; - - before(async () => { - txParams = { - secret: 'LUKSO', - newHash: ethers.solidityPackedKeccak256(['string'], ['UniversalProfiles']), - }; - - recoveryCounterBeforeRecovery = - await context.lsp11BasicSocialRecovery.getRecoveryCounter(); - - recoveryTx = await context.lsp11BasicSocialRecovery - .connect(context.accounts.addressASelected) - .recoverOwnership( - context.accounts.addressASelected.address, - txParams.secret, - txParams.newHash, - ); - }); - - it('should increment the recovery counter', async () => { - const recoveryCounterAfterRecovery = - await context.lsp11BasicSocialRecovery.getRecoveryCounter(); - - expect(recoveryCounterAfterRecovery).to.equal( - ethers.toNumber(recoveryCounterBeforeRecovery) + 1, - ); - }); - - it('should emit RecoveryProcessSuccessful event', async () => { - const guardians = await context.lsp11BasicSocialRecovery.getGuardians(); - - expect(recoveryTx) - .to.emit(context.lsp11BasicSocialRecovery, 'RecoveryProcessSuccessful') - .withArgs( - recoveryCounterBeforeRecovery, - context.accounts.addressASelected.address, - txParams.secret, - guardians, - ); - }); - - it('should have set the correct AddressPermissions Keys on target', async () => { - const txParams = { - permissionArrayKey: ERC725YDataKeys.LSP6['AddressPermissions[]'].length, - permissionInArrayKey: - ERC725YDataKeys.LSP6['AddressPermissions[]'].index + - '00000000000000000000000000000003', - permissionMap: - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + - context.accounts.addressASelected.address.substr(2), - }; - const [permissionArrayLength, controllerAddress, controllerPermissions] = - await context.universalProfile.getDataBatch([ - txParams.permissionArrayKey, - txParams.permissionInArrayKey, - txParams.permissionMap, - ]); - - expect(permissionArrayLength).to.equal(ethers.zeroPadValue(ethers.toBeHex(4), 16)); - expect(ethers.getAddress(controllerAddress)).to.equal( - context.accounts.addressASelected.address, - ); - expect(controllerPermissions).to.equal(ALL_PERMISSIONS); - }); - }); - }); - - describe('when testing execution on target after recovery', () => { - describe('when setting data on the target', () => { - it('should pass', async () => { - const txParams = { - key: ethers.solidityPackedKeccak256(['string'], ['MyKey']), - value: ethers.hexlify(ethers.toUtf8Bytes('I have access')), - }; - - const payload = context.universalProfile.interface.encodeFunctionData('setData', [ - txParams.key, - txParams.value, - ]); - - await context.lsp6KeyManager.connect(context.accounts.addressASelected).execute(payload); - - const value = await context.universalProfile.getData(txParams.key); - - expect(value).to.equal(txParams.value); - }); - }); - }); - }); - - describe('When using the contract as social recovery', () => { - before(async () => { - context = await buildContext(); - }); - - describe('when testing owner functionalities', () => { - it('Should revert when non-owner calls addGuardian function', async () => { - const txParams = { - guardianAddress: context.accounts.guardian1.address, - }; - await expect( - context.lsp11BasicSocialRecovery - .connect(context.accounts.any) - .addGuardian(txParams.guardianAddress), - ).to.be.revertedWithCustomError( - context.lsp11BasicSocialRecovery, - 'OwnableCallerNotTheOwner', - ); - }); - - it('Should pass and emit GuardianAdded event when owner calls addGuardian function', async () => { - const txParams = { - guardianAddress: context.accounts.guardian1.address, - }; - - const payload = context.lsp11BasicSocialRecovery.interface.encodeFunctionData( - 'addGuardian', - [txParams.guardianAddress], - ); - - await expect( - context.lsp6KeyManager - .connect(context.accounts.owner) - .execute( - callPayload( - context.universalProfile, - await context.lsp11BasicSocialRecovery.getAddress(), - payload, - ), - ), - ) - .to.emit(context.lsp11BasicSocialRecovery, 'GuardianAdded') - .withArgs(txParams.guardianAddress); - - const isGuardian = await context.lsp11BasicSocialRecovery.isGuardian( - txParams.guardianAddress, - ); - - expect(isGuardian).to.be.true; - }); - - it('Should revert when non-owner calls removeGuardian function', async () => { - const txParams = { - guardianAddress: context.accounts.guardian1.address, - }; - await expect( - context.lsp11BasicSocialRecovery - .connect(context.accounts.any) - .removeGuardian(txParams.guardianAddress), - ).to.be.revertedWithCustomError( - context.lsp11BasicSocialRecovery, - 'OwnableCallerNotTheOwner', - ); - }); - - it('Should pass and emit GuardianRemoved event when owner calls removeGuardian function', async () => { - const txParams = { - guardianAddress: context.accounts.guardian1.address, - }; - - const payload = context.lsp11BasicSocialRecovery.interface.encodeFunctionData( - 'removeGuardian', - [txParams.guardianAddress], - ); - - await expect( - context.lsp6KeyManager - .connect(context.accounts.owner) - .execute( - callPayload( - context.universalProfile, - await context.lsp11BasicSocialRecovery.getAddress(), - payload, - ), - ), - ) - .to.emit(context.lsp11BasicSocialRecovery, 'GuardianRemoved') - .withArgs(txParams.guardianAddress); - - const isGuardian = await context.lsp11BasicSocialRecovery.isGuardian( - txParams.guardianAddress, - ); - - expect(isGuardian).to.be.false; - }); - - it('Should revert when non-owner calls `setGuardiansThreshold(..)`', async () => { - const txParams = { - newThreshold: 1, - }; - - await expect( - context.lsp11BasicSocialRecovery - .connect(context.accounts.any) - .setGuardiansThreshold(txParams.newThreshold), - ).to.be.revertedWithCustomError( - context.lsp11BasicSocialRecovery, - 'OwnableCallerNotTheOwner', - ); - }); - - it('Should pass and emit GuardiansThresholdChanged event when owner `setGuardiansThreshold(..)`', async () => { - const txParams = { - newThreshold: 0, - }; - - const payload = context.lsp11BasicSocialRecovery.interface.encodeFunctionData( - 'setGuardiansThreshold', - [txParams.newThreshold], - ); - - await expect( - context.lsp6KeyManager - .connect(context.accounts.owner) - .execute( - callPayload( - context.universalProfile, - await context.lsp11BasicSocialRecovery.getAddress(), - payload, - ), - ), - ) - .to.emit(context.lsp11BasicSocialRecovery, 'GuardiansThresholdChanged') - .withArgs(txParams.newThreshold); - - const guardiansThreshold = ethers.toNumber( - await context.lsp11BasicSocialRecovery.getGuardiansThreshold(), - ); - expect(guardiansThreshold).to.equal(txParams.newThreshold); - }); - - it('Should revert when non-owner calls `setRecoverySecretHash(..)`', async () => { - const txParams = { - hash: ethers.solidityPackedKeccak256(['string'], ['LUKSO']), - }; - - await expect( - context.lsp11BasicSocialRecovery - .connect(context.accounts.any) - .setRecoverySecretHash(txParams.hash), - ).to.be.revertedWithCustomError( - context.lsp11BasicSocialRecovery, - 'OwnableCallerNotTheOwner', - ); - }); - - it('Should pass and emit SecretHashChanged event when owner calls `setRecoverySecretHash(..)`', async () => { - const txParams = { - hash: ethers.solidityPackedKeccak256(['string'], ['LUKSO']), - }; - - const payload = context.lsp11BasicSocialRecovery.interface.encodeFunctionData( - 'setRecoverySecretHash', - [txParams.hash], - ); - - await expect( - context.lsp6KeyManager - .connect(context.accounts.owner) - .execute( - callPayload( - context.universalProfile, - await context.lsp11BasicSocialRecovery.getAddress(), - payload, - ), - ), - ) - .to.emit(context.lsp11BasicSocialRecovery, 'SecretHashChanged') - .withArgs(txParams.hash); - }); - }); - - describe('when testing function logic', () => { - describe('when owner calls addGuardian(..) with an existing Guardian address', () => { - let txParams; - let payload; - before('Adding the guardian first', async () => { - // Add the guardian - txParams = { - guardianAddress: context.accounts.guardian1.address, - }; - - payload = context.lsp11BasicSocialRecovery.interface.encodeFunctionData('addGuardian', [ - txParams.guardianAddress, - ]); - - await expect( - context.lsp6KeyManager - .connect(context.accounts.owner) - .execute( - callPayload( - context.universalProfile, - await context.lsp11BasicSocialRecovery.getAddress(), - payload, - ), - ), - ) - .to.emit(context.lsp11BasicSocialRecovery, 'GuardianAdded') - .withArgs(txParams.guardianAddress); - }); - - it('Should revert with GuardianAlreadyExist error ', async () => { - await expect( - context.lsp6KeyManager - .connect(context.accounts.owner) - .execute( - callPayload( - context.universalProfile, - await context.lsp11BasicSocialRecovery.getAddress(), - payload, - ), - ), - ) - .to.be.revertedWithCustomError(context.lsp11BasicSocialRecovery, 'GuardianAlreadyExist') - .withArgs(txParams.guardianAddress); - - const isGuardian = await context.lsp11BasicSocialRecovery.isGuardian( - txParams.guardianAddress, - ); - expect(isGuardian).to.be.true; - }); - }); - - describe('when owner calls removeGuardian(..) with a non-existing Guardian address', () => { - it('Should revert with GuardianDoNotExist error', async () => { - const txParams = { - guardianAddress: context.accounts.random.address, - }; - - const payload = context.lsp11BasicSocialRecovery.interface.encodeFunctionData( - 'removeGuardian', - [txParams.guardianAddress], - ); - - await expect( - context.lsp6KeyManager - .connect(context.accounts.owner) - .execute( - callPayload( - context.universalProfile, - await context.lsp11BasicSocialRecovery.getAddress(), - payload, - ), - ), - ) - .to.be.revertedWithCustomError(context.lsp11BasicSocialRecovery, 'GuardianDoNotExist') - .withArgs(txParams.guardianAddress); - }); - }); - - describe('when owner calls setGuardiansThreshold(..) with a threshold higher than the guardians count', () => { - it('should revert with ThresholdCannotBeHigherThanGuardiansNumber error', async () => { - const guardians = await context.lsp11BasicSocialRecovery.getGuardians(); - - expect(guardians.length).to.equal(1); - - const txParams = { - newThreshold: 2, - }; - - const payload = context.lsp11BasicSocialRecovery.interface.encodeFunctionData( - 'setGuardiansThreshold', - [txParams.newThreshold], - ); - - await expect( - context.lsp6KeyManager - .connect(context.accounts.owner) - .execute( - callPayload( - context.universalProfile, - await context.lsp11BasicSocialRecovery.getAddress(), - payload, - ), - ), - ) - .to.be.revertedWithCustomError( - context.lsp11BasicSocialRecovery, - 'ThresholdCannotBeHigherThanGuardiansNumber', - ) - .withArgs(txParams.newThreshold, guardians.length); - }); - }); - - describe('when owner calls setGuardiansThreshold(..) with a threshold lower than the guardians count', () => { - it('should pass', async () => { - const guardians = await context.lsp11BasicSocialRecovery.getGuardians(); - - expect(guardians.length).to.equal(1); - - const txParams = { - newThreshold: 0, - }; - - const payload = context.lsp11BasicSocialRecovery.interface.encodeFunctionData( - 'setGuardiansThreshold', - [txParams.newThreshold], - ); - - await expect( - context.lsp6KeyManager - .connect(context.accounts.owner) - .execute( - callPayload( - context.universalProfile, - await context.lsp11BasicSocialRecovery.getAddress(), - payload, - ), - ), - ) - .to.emit(context.lsp11BasicSocialRecovery, 'GuardiansThresholdChanged') - .withArgs(txParams.newThreshold); - - const guardiansThreshold = await context.lsp11BasicSocialRecovery.getGuardiansThreshold(); - expect(guardiansThreshold).to.equal(txParams.newThreshold); - }); - }); - - describe('when owner calls setGuardiansThreshold(..) with a threshold equal to the guardians count', () => { - it('should pass', async () => { - const guardians = await context.lsp11BasicSocialRecovery.getGuardians(); - - expect(guardians.length).to.equal(1); - - const txParams = { - newThreshold: 1, - }; - - const payload = context.lsp11BasicSocialRecovery.interface.encodeFunctionData( - 'setGuardiansThreshold', - [txParams.newThreshold], - ); - - await expect( - context.lsp6KeyManager - .connect(context.accounts.owner) - .execute( - callPayload( - context.universalProfile, - await context.lsp11BasicSocialRecovery.getAddress(), - payload, - ), - ), - ) - .to.emit(context.lsp11BasicSocialRecovery, 'GuardiansThresholdChanged') - .withArgs(txParams.newThreshold); - - const guardiansThreshold = await context.lsp11BasicSocialRecovery.getGuardiansThreshold(); - expect(guardiansThreshold).to.equal(txParams.newThreshold); - }); - }); - - describe('when owner calls removeGuardian(..) when the threshold is equal to the guardians count', () => { - let guardians; - let guardiansThreshold; - before('Check that the guardians number is equal to the guardians threshold', async () => { - guardians = await context.lsp11BasicSocialRecovery.getGuardians(); - guardiansThreshold = await context.lsp11BasicSocialRecovery.getGuardiansThreshold(); - - expect(guardians.length).to.equal(guardiansThreshold); - }); - - it('Should revert with GuardiansNumberCannotGoBelowThreshold error', async () => { - const txParams = { - guardianAddress: context.accounts.guardian1.address, - }; - - const payload = context.lsp11BasicSocialRecovery.interface.encodeFunctionData( - 'removeGuardian', - [txParams.guardianAddress], - ); - - await expect( - context.lsp6KeyManager - .connect(context.accounts.owner) - .execute( - callPayload( - context.universalProfile, - await context.lsp11BasicSocialRecovery.getAddress(), - payload, - ), - ), - ) - .to.be.revertedWithCustomError( - context.lsp11BasicSocialRecovery, - 'GuardiansNumberCannotGoBelowThreshold', - ) - .withArgs(guardiansThreshold); - }); - }); - - describe('when owner calls setRecoverySecretHash(..) with bytes32(0) as secret', () => { - it('should revert with SecretHashCannotBeZero error', async () => { - const txParams = { - hash: '0x0000000000000000000000000000000000000000000000000000000000000000', - }; - - const payload = context.lsp11BasicSocialRecovery.interface.encodeFunctionData( - 'setRecoverySecretHash', - [txParams.hash], - ); - - await expect( - context.lsp6KeyManager - .connect(context.accounts.owner) - .execute( - callPayload( - context.universalProfile, - await context.lsp11BasicSocialRecovery.getAddress(), - payload, - ), - ), - ).to.be.revertedWithCustomError( - context.lsp11BasicSocialRecovery, - 'SecretHashCannotBeZero', - ); - }); - }); - }); - - describe('when testing guardians functionalities', () => { - before('Checking guardians and add few more', async () => { - // Checking that guardian1 address is set - const isAddress1Guardian = await context.lsp11BasicSocialRecovery.isGuardian( - context.accounts.guardian1.address, - ); - - expect(isAddress1Guardian).to.be.true; - - // Adding more guardians - - const payload1 = context.lsp11BasicSocialRecovery.interface.encodeFunctionData( - 'addGuardian', - [context.accounts.guardian2.address], - ); - - const payload2 = context.lsp11BasicSocialRecovery.interface.encodeFunctionData( - 'addGuardian', - [context.accounts.guardian3.address], - ); - - const payload3 = context.lsp11BasicSocialRecovery.interface.encodeFunctionData( - 'addGuardian', - [context.accounts.guardian4.address], - ); - - await context.lsp6KeyManager - .connect(context.accounts.owner) - .executeBatch( - [0, 0, 0], - [ - callPayload( - context.universalProfile, - await context.lsp11BasicSocialRecovery.getAddress(), - payload1, - ), - callPayload( - context.universalProfile, - await context.lsp11BasicSocialRecovery.getAddress(), - payload2, - ), - callPayload( - context.universalProfile, - await context.lsp11BasicSocialRecovery.getAddress(), - payload3, - ), - ], - ); - - const isAddress2Guardian = await context.lsp11BasicSocialRecovery.isGuardian( - context.accounts.guardian2.address, - ); - - const isAddress3Guardian = await context.lsp11BasicSocialRecovery.isGuardian( - context.accounts.guardian3.address, - ); - - const isAddress4Guardian = await context.lsp11BasicSocialRecovery.isGuardian( - context.accounts.guardian4.address, - ); - - expect(isAddress2Guardian).to.be.true; - expect(isAddress3Guardian).to.be.true; - expect(isAddress4Guardian).to.be.true; - }); - - describe('when non-guardian calls selectNewController(..) function', () => { - it('should revert with CallerIsNotGuardian error', async () => { - const txParams = { - addressToSelect: context.accounts.addressASelected.address, - }; - - const caller = context.accounts.random; - - const isGuardian = await context.lsp11BasicSocialRecovery.isGuardian(caller.address); - - expect(isGuardian).to.be.false; - - await expect( - context.lsp11BasicSocialRecovery - .connect(caller) - .selectNewController(txParams.addressToSelect), - ) - .to.be.revertedWithCustomError(context.lsp11BasicSocialRecovery, 'CallerIsNotGuardian') - .withArgs(caller.address); - }); - }); - - describe('when a guardian calls selectNewController(..) function', () => { - it('should pass and emit SelectedNewController event', async () => { - const txParams = { - addressToSelect: context.accounts.addressASelected.address, - }; - - const caller = context.accounts.guardian1; - - const isGuardian = await context.lsp11BasicSocialRecovery.isGuardian(caller.address); - - expect(isGuardian).to.be.true; - - const currentRecoveryCounter = - await context.lsp11BasicSocialRecovery.getRecoveryCounter(); - - await expect( - context.lsp11BasicSocialRecovery - .connect(caller) - .selectNewController(txParams.addressToSelect), - ) - .to.emit(context.lsp11BasicSocialRecovery, 'SelectedNewController') - .withArgs(currentRecoveryCounter, caller.address, txParams.addressToSelect); - }); - }); - }); - - describe('when finalizing recovery', () => { - let plainSecret; - let recoverySecretHash; - let beforeRecoveryCounter; - let guardiansThreshold; - let addressBselection; - - before('Distribution selection of the guardians and setting recovery params', async () => { - // Checks that recoveryCounter equal 0 before recovery - beforeRecoveryCounter = await context.lsp11BasicSocialRecovery.getRecoveryCounter(); - - expect(beforeRecoveryCounter).to.equal(0); - - // Changing the threshold to 3 out of 4 guardians - const payload1 = context.lsp11BasicSocialRecovery.interface.encodeFunctionData( - 'setGuardiansThreshold', - [3], - ); - - await context.lsp6KeyManager - .connect(context.accounts.owner) - .execute( - callPayload( - context.universalProfile, - await context.lsp11BasicSocialRecovery.getAddress(), - payload1, - ), - ); - - guardiansThreshold = await context.lsp11BasicSocialRecovery.getGuardiansThreshold(); - expect(guardiansThreshold).to.equal(3); - - // Changing the secretHash to "LUKSO" - plainSecret = 'LUKSO'; - recoverySecretHash = ethers.solidityPackedKeccak256(['string'], [plainSecret]); - - const payload2 = context.lsp11BasicSocialRecovery.interface.encodeFunctionData( - 'setRecoverySecretHash', - [recoverySecretHash], - ); - - await context.lsp6KeyManager - .connect(context.accounts.owner) - .execute( - callPayload( - context.universalProfile, - await context.lsp11BasicSocialRecovery.getAddress(), - payload2, - ), - ); - - // Guardian 1 selects address A - await context.lsp11BasicSocialRecovery - .connect(context.accounts.guardian1) - .selectNewController(context.accounts.addressASelected.address); - - const guardian1Choice = await context.lsp11BasicSocialRecovery.getGuardianChoice( - context.accounts.guardian1.address, - ); - - expect(guardian1Choice).to.equal(context.accounts.addressASelected.address); - - // Guardian 2 selects address A - await context.lsp11BasicSocialRecovery - .connect(context.accounts.guardian2) - .selectNewController(context.accounts.addressASelected.address); - - const guardian2Choice = await context.lsp11BasicSocialRecovery.getGuardianChoice( - context.accounts.guardian2.address, - ); - - expect(guardian2Choice).to.equal(context.accounts.addressASelected.address); - - // Guardian 3 selects address A - await context.lsp11BasicSocialRecovery - .connect(context.accounts.guardian3) - .selectNewController(context.accounts.addressASelected.address); - - const guardian3Choice = await context.lsp11BasicSocialRecovery.getGuardianChoice( - context.accounts.guardian3.address, - ); - - expect(guardian3Choice).to.equal(context.accounts.addressASelected.address); - - // Guardian 4 selects address B - await context.lsp11BasicSocialRecovery - .connect(context.accounts.guardian4) - .selectNewController(context.accounts.addressBSelected.address); - - const guardian4Choice = await context.lsp11BasicSocialRecovery.getGuardianChoice( - context.accounts.guardian4.address, - ); - - addressBselection = 1; - - expect(guardian4Choice).to.equal(context.accounts.addressBSelected.address); - }); - - describe("When address B calls recoverOwnership(..) when it didn't reached the guardians threshold", () => { - it('should revert with ThresholdNotReachedForRecoverer error', async () => { - const txParams = { - secret: plainSecret, - newHash: ethers.solidityPackedKeccak256(['string'], ['NotLUKSO']), - }; - - await expect( - context.lsp11BasicSocialRecovery - .connect(context.accounts.addressBSelected) - .recoverOwnership( - context.accounts.addressBSelected.address, - txParams.secret, - txParams.newHash, - ), - ) - .to.be.revertedWithCustomError( - context.lsp11BasicSocialRecovery, - 'ThresholdNotReachedForRecoverer', - ) - .withArgs( - context.accounts.addressBSelected.address, - addressBselection, - guardiansThreshold, - ); - }); - }); - - describe('When address A calls recoverOwnership(..) with bytes32(0) as new secretHash', () => { - it('should revert with SecretHashCannotBeZero error', async () => { - const txParams = { - secret: plainSecret, - newHash: '0x0000000000000000000000000000000000000000000000000000000000000000', - }; - - await expect( - context.lsp11BasicSocialRecovery - .connect(context.accounts.addressASelected) - .recoverOwnership( - context.accounts.addressASelected.address, - txParams.secret, - txParams.newHash, - ), - ).to.be.revertedWithCustomError( - context.lsp11BasicSocialRecovery, - 'SecretHashCannotBeZero', - ); - }); - }); - - describe('When address A calls recoverOwnership(..) with the incorrect plainSecret', () => { - it('should revert with WrongPlainSecret error', async () => { - const txParams = { - secret: 'NotTheValidPlainSecret', - newHash: ethers.solidityPackedKeccak256(['string'], ['NotLUKSO']), - }; - - await expect( - context.lsp11BasicSocialRecovery - .connect(context.accounts.addressASelected) - .recoverOwnership( - context.accounts.addressASelected.address, - txParams.secret, - txParams.newHash, - ), - ).to.be.revertedWithCustomError(context.lsp11BasicSocialRecovery, 'WrongPlainSecret'); - }); - }); - - describe('When address A calls recoverOwnership(..) with the correct plainSecret', () => { - let ownershipRecoveryTx; - let newPlainSecret; - let newSecretHash; - before('Creating the tx of recovering', async () => { - newPlainSecret = 'UniversalProfiles'; - newSecretHash = ethers.solidityPackedKeccak256(['string'], [newPlainSecret]); - - const txParams = { - secret: plainSecret, - newHash: newSecretHash, - }; - - ownershipRecoveryTx = await context.lsp11BasicSocialRecovery - .connect(context.accounts.addressASelected) - .recoverOwnership( - context.accounts.addressASelected.address, - txParams.secret, - txParams.newHash, - ); - }); - - it('should pass and emit RecoveryProcessSuccessful event', async () => { - expect(ownershipRecoveryTx) - .to.emit(context.lsp11BasicSocialRecovery, 'RecoveryProcessSuccessful') - .withArgs( - beforeRecoveryCounter, - context.accounts.addressASelected, - newSecretHash, - await context.lsp11BasicSocialRecovery.getGuardians(), - ); - }); - - it('should increment the recovery counter', async () => { - const afterRecoveryCounter = await context.lsp11BasicSocialRecovery.getRecoveryCounter(); - - expect(afterRecoveryCounter).to.equal(ethers.toNumber(beforeRecoveryCounter) + 1); - }); - - it('should update the recoverySecretHash ', async () => { - expect(ownershipRecoveryTx) - .to.emit(context.lsp11BasicSocialRecovery, 'SecretHashChanged') - .withArgs(newSecretHash); - }); - - it('should add the AddressPermissions Key for address A in the target ', async () => { - const txParams = { - permissionArrayKey: ERC725YDataKeys.LSP6['AddressPermissions[]'].length, - permissionInArrayKey: - ERC725YDataKeys.LSP6['AddressPermissions[]'].index + - '00000000000000000000000000000003', - permissionMap: - ERC725YDataKeys.LSP6['AddressPermissions:Permissions'] + - context.accounts.addressASelected.address.substr(2), - }; - const [permissionArrayLength, controllerAddress, controllerPermissions] = - await context.universalProfile.getDataBatch([ - txParams.permissionArrayKey, - txParams.permissionInArrayKey, - txParams.permissionMap, - ]); - - expect(permissionArrayLength).to.equal(ethers.zeroPadValue(ethers.toBeHex(4), 16)); - expect(ethers.getAddress(controllerAddress)).to.equal( - context.accounts.addressASelected.address, - ); - expect(controllerPermissions).to.equal(ALL_PERMISSIONS); - }); - }); - }); - - describe('when testing execution on target after recovery', () => { - describe('when setting data on the target', () => { - it('should pass', async () => { - const txParams = { - key: ethers.solidityPackedKeccak256(['string'], ['MyKey']), - value: ethers.hexlify(ethers.toUtf8Bytes('I have access')), - }; - - const payload = context.universalProfile.interface.encodeFunctionData('setData', [ - txParams.key, - txParams.value, - ]); - - await context.lsp6KeyManager.connect(context.accounts.addressASelected).execute(payload); - - const value = await context.universalProfile.getData(txParams.key); - - expect(value).to.equal(txParams.value); - }); - }); - }); - - describe('when checking guardians choice', () => { - it('should be reset', async () => { - const guardian1Choice = await context.lsp11BasicSocialRecovery.getGuardianChoice( - context.accounts.guardian1.address, - ); - - expect(guardian1Choice).to.equal(ethers.ZeroAddress); - - const guardian2Choice = await context.lsp11BasicSocialRecovery.getGuardianChoice( - context.accounts.guardian2.address, - ); - - expect(guardian2Choice).to.equal(ethers.ZeroAddress); - }); - }); - }); -}; - -export type LSP11InitializeTestContext = { - lsp11BasicSocialRecovery: LSP11BasicSocialRecovery; - deployParams: LSP11DeployParams; - initializeTransaction: ContractTransactionResponse; -}; - -export const shouldInitializeLikeLSP11 = ( - buildContext: () => Promise, -) => { - let context: LSP11InitializeTestContext; - - before(async () => { - context = await buildContext(); - }); - - describe('when the contract was initialized', () => { - it('Should have registered the ERC165 interface', async () => { - expect(await context.lsp11BasicSocialRecovery.supportsInterface(INTERFACE_IDS.ERC165)).to.be - .true; - }); - - it('Should have registered the LSP11 interface', async () => { - expect( - await context.lsp11BasicSocialRecovery.supportsInterface( - INTERFACE_IDS.LSP11BasicSocialRecovery, - ), - ).to.be.true; - }); - - it('Should have set the owner', async () => { - const owner = await context.lsp11BasicSocialRecovery.owner(); - expect(owner).to.equal(await context.deployParams.owner.getAddress()); - }); - - it('Should have set the linked target', async () => { - const target = await context.lsp11BasicSocialRecovery['target()'](); - expect(target).to.equal(await context.deployParams.target.getAddress()); - }); - }); -}; diff --git a/packages/lsp-smart-contracts/tests/LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.test.ts b/packages/lsp-smart-contracts/tests/LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.test.ts deleted file mode 100644 index 728d6ede4..000000000 --- a/packages/lsp-smart-contracts/tests/LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.test.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { LSP11BasicSocialRecovery__factory, LSP6KeyManager, UniversalProfile } from '../../types'; - -import { - getNamedAccounts, - shouldInitializeLikeLSP11, - LSP11TestContext, - shouldBehaveLikeLSP11, -} from './LSP11BasicSocialRecovery.behaviour'; - -import { - setupProfileWithKeyManagerWithURD, - grantLSP11PermissionViaKeyManager, -} from '../utils/fixtures'; - -describe('LSP11BasicSocialRecovery with constructor', () => { - let context: LSP11TestContext; - - const buildTestContext = async (): Promise => { - const accounts = await getNamedAccounts(); - - const [UP, KM] = await setupProfileWithKeyManagerWithURD(accounts.owner); - - const universalProfile = UP as UniversalProfile; - const lsp6KeyManager = KM as LSP6KeyManager; - - const deployParams = { - owner: universalProfile, - target: universalProfile, - }; - - const lsp11BasicSocialRecovery = await new LSP11BasicSocialRecovery__factory( - accounts.any, - ).deploy(await deployParams.owner.getAddress(), await deployParams.target.getAddress()); - - await grantLSP11PermissionViaKeyManager( - accounts.owner, - universalProfile, - lsp6KeyManager, - await lsp11BasicSocialRecovery.getAddress(), - ); - - return { - accounts, - lsp11BasicSocialRecovery, - deployParams, - universalProfile, - lsp6KeyManager, - }; - }; - - before(async () => { - context = await buildTestContext(); - }); - - describe('When deploying the contract', () => { - describe('When initializing the contract', () => { - shouldInitializeLikeLSP11(async () => { - const { lsp11BasicSocialRecovery, deployParams } = context; - return { - lsp11BasicSocialRecovery, - deployParams, - initializeTransaction: context.lsp11BasicSocialRecovery.deploymentTransaction(), - }; - }); - }); - }); - - describe('When testing deployed contract', () => { - shouldBehaveLikeLSP11(buildTestContext); - }); -}); diff --git a/packages/lsp-smart-contracts/tests/LSP11BasicSocialRecovery/LSP11BasicSocialRecoveryInit.test.ts b/packages/lsp-smart-contracts/tests/LSP11BasicSocialRecovery/LSP11BasicSocialRecoveryInit.test.ts deleted file mode 100644 index 686f84632..000000000 --- a/packages/lsp-smart-contracts/tests/LSP11BasicSocialRecovery/LSP11BasicSocialRecoveryInit.test.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { expect } from 'chai'; - -import { - LSP6KeyManager, - UniversalProfile, - LSP11BasicSocialRecoveryInit__factory, - LSP11BasicSocialRecovery, -} from '../../types'; - -import { - getNamedAccounts, - shouldInitializeLikeLSP11, - LSP11TestContext, - shouldBehaveLikeLSP11, -} from './LSP11BasicSocialRecovery.behaviour'; - -import { - setupProfileWithKeyManagerWithURD, - deployProxy, - grantLSP11PermissionViaKeyManager, -} from '../utils/fixtures'; - -describe('LSP11BasicSocialRecoveryInit with proxy', () => { - const buildTestContext = async (): Promise => { - const accounts = await getNamedAccounts(); - - const [UP, KM] = await setupProfileWithKeyManagerWithURD(accounts.owner); - - const universalProfile = UP as UniversalProfile; - const lsp6KeyManager = KM as LSP6KeyManager; - - const deployParams = { - owner: universalProfile, - target: universalProfile, - }; - - const lsp11BasicSocialRecoveryInit = await new LSP11BasicSocialRecoveryInit__factory( - accounts.owner, - ).deploy(); - - const lsp11BasicSocialRecoveryProxy = await deployProxy( - await lsp11BasicSocialRecoveryInit.getAddress(), - accounts.owner, - ); - - const lsp11BasicSocialRecovery = lsp11BasicSocialRecoveryInit.attach( - lsp11BasicSocialRecoveryProxy, - ) as unknown as LSP11BasicSocialRecovery; - - await grantLSP11PermissionViaKeyManager( - accounts.owner, - universalProfile, - lsp6KeyManager, - await lsp11BasicSocialRecovery.getAddress(), - ); - - return { - accounts, - lsp11BasicSocialRecovery, - deployParams, - universalProfile, - lsp6KeyManager, - }; - }; - - const initializeProxy = async (context: LSP11TestContext) => { - return context.lsp11BasicSocialRecovery['initialize(address,address)']( - await context.deployParams.owner.getAddress(), - await context.deployParams.target.getAddress(), - ); - }; - - describe('When deploying the contract as proxy', () => { - let context: LSP11TestContext; - - before(async () => { - context = await buildTestContext(); - }); - - describe('When initializing the proxy contract', () => { - shouldInitializeLikeLSP11(async () => { - const { lsp11BasicSocialRecovery, deployParams } = context; - const initializeTransaction = await initializeProxy(context); - - return { - lsp11BasicSocialRecovery, - deployParams, - initializeTransaction, - }; - }); - }); - - describe('When calling initialize more than once', () => { - it('should revert', async () => { - await expect(initializeProxy(context)).to.be.revertedWith( - 'Initializable: contract is already initialized', - ); - }); - }); - }); - - describe('When testing deployed contract', () => { - shouldBehaveLikeLSP11(() => - buildTestContext().then(async (context) => { - await initializeProxy(context); - - return context; - }), - ); - }); -}); diff --git a/packages/lsp-smart-contracts/tests/Mocks/ERC165Interfaces.test.ts b/packages/lsp-smart-contracts/tests/Mocks/ERC165Interfaces.test.ts index 4f0d05c02..0442780ec 100644 --- a/packages/lsp-smart-contracts/tests/Mocks/ERC165Interfaces.test.ts +++ b/packages/lsp-smart-contracts/tests/Mocks/ERC165Interfaces.test.ts @@ -66,7 +66,7 @@ describe('Calculate LSP interfaces', () => { it('LSP11', async () => { const result = await contract.calculateInterfaceLSP11(); - expect(result).to.equal(INTERFACE_IDS.LSP11BasicSocialRecovery); + expect(result).to.equal(INTERFACE_IDS.LSP11SocialRecovery); }); it('LSP14', async () => { diff --git a/packages/lsp-smart-contracts/tests/foundry/LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.t.sol b/packages/lsp-smart-contracts/tests/foundry/LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.t.sol deleted file mode 100644 index 1e37dea63..000000000 --- a/packages/lsp-smart-contracts/tests/foundry/LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.t.sol +++ /dev/null @@ -1,75 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.13; - -import "forge-std/Test.sol"; - -import "./LSP11Mock.sol"; -import "../../../contracts/LSP11BasicSocialRecovery/LSP11Errors.sol"; - -contract LSP11BasicSocialRecoveryTests is Test { - LSP11Mock public lsp11; - address internal _lsp11OwnerAddress = vm.addr(1); - address internal _targetAddress = vm.addr(2); - - function setUp() public { - lsp11 = new LSP11Mock(_lsp11OwnerAddress, _targetAddress); - } - - // when secret is not set, should revert with any plainSecret value - function testValidateRequirementsShouldRevertWithRandomSecret( - string memory plainSecret - ) public { - address recoverer = vm.addr(3); - uint256 currentRecoveryCounter = 1; - bytes32 newHash = keccak256(abi.encodePacked("newHash")); - address[] memory guardians = new address[](0); - vm.expectRevert(WrongPlainSecret.selector); - lsp11.validateRequirements( - recoverer, - currentRecoveryCounter, - plainSecret, - newHash, - guardians - ); - } - - function testShouldNotRevertWithCorrectSecret( - string memory plainSecret - ) public { - address recoverer = vm.addr(3); - uint256 currentRecoveryCounter = 1; - bytes32 newHash = keccak256(abi.encodePacked("newHash")); - address[] memory guardians = new address[](0); - vm.prank(_lsp11OwnerAddress); - lsp11.setRecoverySecretHash(keccak256(abi.encodePacked(plainSecret))); - lsp11.validateRequirements( - recoverer, - currentRecoveryCounter, - plainSecret, - newHash, - guardians - ); - } - - // mocking setGuardiansThreshold(...) to be able to test the revert (ThresholdCannotBeHigherThanGuardiansNumber) - function testSetCannotGuardiansThresholdSuperiorToGuardiansLength( - uint64 guardianLength, - uint64 offset - ) public { - if (offset == 0) return; - vm.startPrank(_lsp11OwnerAddress); - uint256 guardianLength256 = guardianLength; - uint256 offset256 = offset; - uint256 newThreshold = guardianLength256 + offset256; - - vm.expectRevert( - abi.encodeWithSelector( - ThresholdCannotBeHigherThanGuardiansNumber.selector, - newThreshold, - guardianLength - ) - ); - lsp11.setGuardiansThresholdMock(newThreshold, guardianLength); - vm.stopPrank(); - } -} diff --git a/packages/lsp-smart-contracts/tests/foundry/LSP11BasicSocialRecovery/LSP11Mock.sol b/packages/lsp-smart-contracts/tests/foundry/LSP11BasicSocialRecovery/LSP11Mock.sol deleted file mode 100644 index 02414f79f..000000000 --- a/packages/lsp-smart-contracts/tests/foundry/LSP11BasicSocialRecovery/LSP11Mock.sol +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.13; - -import "../../../contracts/LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.sol"; -import "../../../contracts/LSP11BasicSocialRecovery/LSP11Errors.sol"; - -contract LSP11Mock is LSP11BasicSocialRecovery { - constructor( - address _owner, - address target_ - ) LSP11BasicSocialRecovery(_owner, target_) {} - - function validateRequirements( - address recoverer, - uint256 currentRecoveryCounter, - string memory plainSecret, - bytes32 newHash, - address[] memory guardians - ) public view { - _validateRequirements( - recoverer, - currentRecoveryCounter, - plainSecret, - newHash, - guardians - ); - } - - function setGuardiansThresholdMock( - uint256 newThreshold, - uint256 guardianLength - ) public onlyOwner { - if (newThreshold > guardianLength) - revert ThresholdCannotBeHigherThanGuardiansNumber( - newThreshold, - guardianLength - ); - - _guardiansThreshold = newThreshold; - } -} diff --git a/packages/lsp11-contracts/contracts/LSP11SocialRecovery.sol b/packages/lsp11-contracts/contracts/LSP11SocialRecovery.sol index a1381a256..f79c63f8c 100644 --- a/packages/lsp11-contracts/contracts/LSP11SocialRecovery.sol +++ b/packages/lsp11-contracts/contracts/LSP11SocialRecovery.sol @@ -901,14 +901,20 @@ contract LSP11SocialRecovery is // if there is no guardians, disallow recovering if (guardiansThresholdOfAccount == 0) revert AccountNotSetupYet(); - // retrieve number of votes caller have - uint256 votesOfGuardianVotedAddress_ = _votesOfguardianVotedAddress[ - account - ][recoveryCounter][votedAddress]; - - // if the threshold is 0, and the caller does not have votes will rely on the hash - if (votesOfGuardianVotedAddress_ < guardiansThresholdOfAccount) - revert CallerVotesHaveNotReachedThreshold(account, votedAddress); + // use block scope to discard local variable after check and prevent stack too deep + { + // retrieve number of votes caller have + uint256 votesOfGuardianVotedAddress_ = _votesOfguardianVotedAddress[ + account + ][recoveryCounter][votedAddress]; + + // if the threshold is 0, and the caller does not have votes will rely on the hash + if (votesOfGuardianVotedAddress_ < guardiansThresholdOfAccount) + revert CallerVotesHaveNotReachedThreshold( + account, + votedAddress + ); + } // if there is a secret require a commitment first if (currentSecretHash != bytes32(0)) { diff --git a/packages/lsp11-contracts/foundry/LSP11UniversalRecovery.t.sol b/packages/lsp11-contracts/foundry/LSP11AccountFunctionalities.t.sol similarity index 100% rename from packages/lsp11-contracts/foundry/LSP11UniversalRecovery.t.sol rename to packages/lsp11-contracts/foundry/LSP11AccountFunctionalities.t.sol diff --git a/packages/lsp11-contracts/package.json b/packages/lsp11-contracts/package.json index 43a86827a..8c75dde72 100644 --- a/packages/lsp11-contracts/package.json +++ b/packages/lsp11-contracts/package.json @@ -47,7 +47,6 @@ "package": "hardhat prepare-package" }, "dependencies": { - "@erc725/smart-contracts": "^7.0.0", "@lukso/lsp25-contracts": "~0.15.0", "@openzeppelin/contracts": "^4.9.6" } diff --git a/packages/lsp4-contracts/contracts/LSP4Utils.sol b/packages/lsp4-contracts/contracts/LSP4Utils.sol index 3541abb6b..76b59251f 100644 --- a/packages/lsp4-contracts/contracts/LSP4Utils.sol +++ b/packages/lsp4-contracts/contracts/LSP4Utils.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.24; +pragma solidity ^0.8.4; import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; import { diff --git a/publish.mjs b/publish.mjs index c61d78b0c..0479210e7 100644 --- a/publish.mjs +++ b/publish.mjs @@ -1,8 +1,8 @@ #!/usr/bin/env node -import { readFile } from "fs/promises"; -import { $ } from "zx"; +import { readFile } from 'fs/promises'; +import { $ } from 'zx'; -const outputs = JSON.parse(await readFile(process.argv[2], "utf-8")); +const outputs = JSON.parse(await readFile(process.argv[2], 'utf-8')); for (const key in outputs) { const value = outputs[key]; const match = key.match(/^(.*\/.*)--release_created$/); @@ -10,13 +10,13 @@ for (const key in outputs) { // Skip if no release was created for this LSP package if (!match || !value) continue; - let tag = "latest"; + let tag = 'latest'; const version = outputs[`${match[1]}--version`]; // Do not publish as latest on npm if we are doing a release candidate - if (version != null && version.includes("-rc")) { - tag = "rc"; + if (version != null && version.includes('-rc')) { + tag = 'rc'; } const workspace = match[1];