diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b1182ee..272fe03e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,19 +23,11 @@ All notable changes to this project will be documented in this file. - **ERC-165 Interface Implementation**: - Implemented ERC-165 support across all major contracts in the suite, allowing them to explicitly declare the interfaces they support. This enhancement improves interoperability and makes it easier for external contracts and tools to interact with T-REX contracts. - - ERC-165 support was added to the following contracts: - - `Token` - - `IdentityRegistry` - - `IdentityRegistryStorage` - - `TrustedIssuersRegistry` - - `ClaimTopicsRegistry` - - `TREXGateway` - - `DVATransferManager` - - `ModularCompliance` - - Compliance Modules (e.g., `CountryAllowModule`, `TransferRestrictModule`) - - `TREXImplementationAuthority` - - `IAFactory` - Each contract now implements the `supportsInterface` function to identify the supported interfaces, ensuring compliance with ERC-165 standards. + - In addition to implementing ERC-165, the ERC-3643 interfaces were organized into a new directory, with each interface inheriting from the original ERC-3643 standard interface. This setup allows for future expansion and maintains uniformity across the suite: + - `IERC3643`, `IERC3643IdentityRegistry`, `IERC3643Compliance`, `IERC3643ClaimTopicsRegistry`, `IERC3643TrustedIssuersRegistry`, `IERC3643IdentityRegistryStorage` + - For contracts that extend the ERC-3643 standard with new functions, `supportsInterface` now checks for both the new interface ID and the original ERC-3643 interface ID. + - For interfaces that did not change, `supportsInterface` checks for the ERC-3643 interface ID directly, omitting the empty version-specific interface to avoid redundancy. - **Add and Set Module in a Single Transaction**: - Introduced the `addAndSetModule` function in the `ModularCompliance` contract, allowing the contract owner to add a new compliance module and interact with it in a single transaction. diff --git a/contracts/DVD/DVDTransferManager.sol b/contracts/DVD/DVDTransferManager.sol index 58255c42..a0ce737e 100644 --- a/contracts/DVD/DVDTransferManager.sol +++ b/contracts/DVD/DVDTransferManager.sol @@ -72,6 +72,8 @@ import "../roles/AgentRole.sol"; import "../token/IToken.sol"; import "../errors/CommonErrors.sol"; import "../errors/InvalidArgumentErrors.sol"; +import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; + /// events @@ -388,20 +390,14 @@ contract DVDTransferManager is Ownable { } /** - * @dev check if `_token` corresponds to a functional TREX token (with identity registry initiated) + * @dev check if `_token` corresponds to a TREX token * @param _token the address token to check - * the function will try to call `identityRegistry()` on - * the address, which is a getter specific to TREX tokens - * if the call pass and returns an address it means that - * the token is a TREX, otherwise it's not a TREX + * the function will check if the address implements IERC3643 * return `true` if the token is a TREX, `false` otherwise */ function isTREX(address _token) public view returns (bool) { - try IToken(_token).identityRegistry() returns (IIdentityRegistry _ir) { - if (address(_ir) != address(0)) { - return true; - } - return false; + try IERC165(_token).supportsInterface(type(IERC3643).interfaceId) returns (bool _trex) { + return _trex; } catch { return false; diff --git a/contracts/ERC-3643/IERC3643.sol b/contracts/ERC-3643/IERC3643.sol new file mode 100644 index 00000000..8af2604e --- /dev/null +++ b/contracts/ERC-3643/IERC3643.sol @@ -0,0 +1,470 @@ +// SPDX-License-Identifier: CC0-1.0 +// +// :+#####%%%%%%%%%%%%%%+ +// .-*@@@%+.:+%@@@@@%%#***%@@%= +// :=*%@@@#=. :#@@% *@@@%= +// .-+*%@%*-.:+%@@@@@@+. -*+: .=#. :%@@@%- +// :=*@@@@%%@@@@@@@@@%@@@- .=#@@@%@%= =@@@@#. +// -=+#%@@%#*=:. :%@@@@%. -*@@#*@@@@@@@#=:- *@@@@+ +// =@@%=:. :=: *@@@@@%#- =%*%@@@@#+-. =+ :%@@@%- +// -@@%. .+@@@ =+=-. @@#- +@@@%- =@@@@%: +// :@@@. .+@@#%: : .=*=-::.-%@@@+*@@= +@@@@#. +// %@@: +@%%* =%@@@@@@@@@@@#. .*@%- +@@@@*. +// #@@= .+@@@@%:=*@@@@@- :%@%: .*@@@@+ +// *@@* +@@@#-@@%-:%@@* +@@#. :%@@@@- +// -@@% .:-=++*##%%%@@@@@@@@@@@@*. :@+.@@@%: .#@@+ =@@@@#: +// .@@@*-+*#%%%@@@@@@@@@@@@@@@@%%#**@@%@@@. *@=*@@# :#@%= .#@@@@#- +// -%@@@@@@@@@@@@@@@*+==-:-@@@= *@# .#@*-=*@@@@%= -%@@@* =@@@@@%- +// -+%@@@#. %@%%= -@@:+@: -@@* *@@*-:: -%@@%=. .*@@@@@# +// *@@@* +@* *@@##@@- #@*@@+ -@@= . :+@@@#: .-+@@@%+- +// +@@@%*@@:..=@@@@* .@@@* .#@#. .=+- .=%@@@*. :+#@@@@*=: +// =@@@@%@@@@@@@@@@@@@@@@@@@@@@%- :+#*. :*@@@%=. .=#@@@@%+: +// .%@@= ..... .=#@@+. .#@@@*: -*%@@@@%+. +// +@@#+===---:::... .=%@@*- +@@@+. -*@@@@@%+. +// -@@@@@@@@@@@@@@@@@@@@@@%@@@@= -@@@+ -#@@@@@#=. +// ..:::---===+++***###%%%@@@#- .#@@+ -*@@@@@#=. +// @@@@@@+. +@@*. .+@@@@@%=. +// -@@@@@= =@@%: -#@@@@%+. +// +@@@@@. =@@@= .+@@@@@*: +// #@@@@#:%@@#. :*@@@@#- +// @@@@@%@@@= :#@@@@+. +// :@@@@@@@#.:#@@@%- +// +@@@@@@-.*@@@*: +// #@@@@#.=@@@+. +// @@@@+-%@%= +// :@@@#%@%= +// +@@@@%- +// :#%%= +// + +pragma solidity 0.8.26; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import "./IERC3643IdentityRegistry.sol"; +import "./IERC3643Compliance.sol"; + +/// Events + +/// @dev This event is emitted when the token information is updated. +/// @param _newName is the name of the token. +/// @param _newSymbol is the symbol of the token. +/// @param _newDecimals is the decimals of the token. +/// @param _newVersion is the version of the token. +/// @param _newOnchainID is the address of the onchainID of the token. +event UpdatedTokenInformation(string indexed _newName, string indexed _newSymbol, uint8 _newDecimals, + string _newVersion, address indexed _newOnchainID); + +/// @dev This event is emitted when the IdentityRegistry has been set for the token. +/// @param _identityRegistry is the address of the Identity Registry of the token. +event IdentityRegistryAdded(address indexed _identityRegistry); + +/// @dev This event is emitted when the Compliance has been set for the token. +/// @param _compliance is the address of the Compliance contract of the token. +event ComplianceAdded(address indexed _compliance); + +/// @dev This event is emitted when an investor successfully recovers his tokens. +/// @param _lostWallet is the address of the wallet that the investor lost access to. +/// @param _newWallet is the address of the wallet that the investor provided for the recovery. +/// @param _investorOnchainID is the address of the onchainID of the investor who asked for a recovery. +event RecoverySuccess(address indexed _lostWallet, address indexed _newWallet, address indexed _investorOnchainID); + +/// @dev This event is emitted when the wallet of an investor is frozen or unfrozen. +/// @param _userAddress is the wallet of the investor that is concerned by the freezing status. +/// @param _isFrozen is the freezing status of the wallet. +/// @param _isFrozen equals `true` the wallet is frozen after emission of the event. +/// @param _isFrozen equals `false` the wallet is unfrozen after emission of the event. +/// @param _owner is the address of the agent who called the function to freeze the wallet. +event AddressFrozen(address indexed _userAddress, bool indexed _isFrozen, address indexed _owner); + +/// @dev This event is emitted when a certain amount of tokens is frozen on a wallet. +/// @param _userAddress is the wallet of the investor that is concerned by the freezing status. +/// @param _amount is the amount of tokens that are frozen. +event TokensFrozen(address indexed _userAddress, uint256 _amount); + +/// @dev This event is emitted when a certain amount of tokens is unfrozen on a wallet. +/// @param _userAddress is the wallet of the investor that is concerned by the freezing status. +/// @param _amount is the amount of tokens that are unfrozen. +event TokensUnfrozen(address indexed _userAddress, uint256 _amount); + +/// @dev This event is emitted when the token is paused. +/// @param _userAddress is the address of the wallet that called the pause function +event Paused(address _userAddress); + +/// @dev This event is emitted when the token is unpaused. +/// @param _userAddress is the address of the wallet that called the unpause function. +event Unpaused(address _userAddress); + + +interface IERC3643 is IERC20, IERC20Metadata { + + /// Functions + + /// Setters + + /** + * @dev sets the token name + * @param _name the name of token to set + * Only the owner of the token smart contract can call this function + * emits a `UpdatedTokenInformation` event + */ + function setName(string calldata _name) external; + + /** + * @dev sets the token symbol + * @param _symbol the token symbol to set + * Only the owner of the token smart contract can call this function + * emits a `UpdatedTokenInformation` event + */ + function setSymbol(string calldata _symbol) external; + + /** + * @dev sets the onchain ID of the token + * @param _onchainID the address of the onchain ID to set + * Only the owner of the token smart contract can call this function + * emits a `UpdatedTokenInformation` event + */ + function setOnchainID(address _onchainID) external; + + /** + * @dev Pauses the token contract. When the contract is paused, investors cannot transfer tokens anymore. + * This function can only be called by an agent of the token, provided the agent is not restricted from pausing the token. + * emits a `Paused` event upon successful execution. + * To pause token transfers, the calling agent must have pausing capabilities enabled. + * If the agent is disabled from pausing, the function call will fail. + * The function can be called only when the contract is not already paused. + * error AgentNotAuthorized - Thrown if the agent is disabled from pausing the token, + * indicating they do not have the necessary permissions to execute this function. + */ + function pause() external; + + /** + * @dev Unpauses the token contract, allowing investors to resume token transfers under normal conditions + * This function can only be called by an agent of the token, provided the agent is not restricted from pausing the token. + * emits an `Unpaused` event upon successful execution. + * To unpause token transfers, the calling agent must have pausing capabilities enabled. + * If the agent is disabled from pausing, the function call will fail. + * The function can be called only when the contract is currently paused. + * error AgentNotAuthorized - Thrown if the agent is disabled from pausing the token, + * indicating they do not have the necessary permissions to execute this function. + */ + function unpause() external; + + /** + * @dev Sets an address's frozen status for this token, + * either freezing or unfreezing the address based on the provided boolean value. + * This function can be called by an agent of the token, assuming the agent is not restricted from freezing addresses. + * emits an `AddressFrozen` event upon successful execution. + * @param _userAddress The address for which to update the frozen status. + * @param _freeze The frozen status to be applied: `true` to freeze, `false` to unfreeze. + * @notice To change an address's frozen status, the calling agent must have the capability to freeze addresses enabled. + * If the agent is disabled from freezing addresses, the function call will fail. + * error AgentNotAuthorized - Thrown if the agent is disabled from freezing addresses, + * indicating they do not have the necessary permissions to execute this function. + */ + function setAddressFrozen(address _userAddress, bool _freeze) external; + + /** + * @dev Freezes a specified token amount for a given address, preventing those tokens from being transferred. + * This function can be called by an agent of the token, provided the agent is not restricted from freezing tokens. + * emits a `TokensFrozen` event upon successful execution. + * @param _userAddress The address for which to freeze tokens. + * @param _amount The amount of tokens to be frozen. + * @notice To freeze tokens for an address, the calling agent must have the capability to freeze tokens enabled. + * If the agent is disabled from freezing tokens, the function call will fail. + * error AgentNotAuthorized - Thrown if the agent is disabled from freezing tokens, + * indicating they do not have the necessary permissions to execute this function. + */ + function freezePartialTokens(address _userAddress, uint256 _amount) external; + + /** + * @dev Unfreezes a specified token amount for a given address, allowing those tokens to be transferred again. + * This function can be called by an agent of the token, assuming the agent is not restricted from unfreezing tokens. + * emits a `TokensUnfrozen` event upon successful execution. + * @param _userAddress The address for which to unfreeze tokens. + * @param _amount The amount of tokens to be unfrozen. + * @notice To unfreeze tokens for an address, the calling agent must have the capability to unfreeze tokens enabled. + * If the agent is disabled from unfreezing tokens, the function call will fail. + * error AgentNotAuthorized - Thrown if the agent is disabled from unfreezing tokens, + * indicating they do not have the necessary permissions to execute this function. + */ + function unfreezePartialTokens(address _userAddress, uint256 _amount) external; + + /** + * @dev sets the Identity Registry for the token + * @param _identityRegistry the address of the Identity Registry to set + * Only the owner of the token smart contract can call this function + * emits an `IdentityRegistryAdded` event + */ + function setIdentityRegistry(address _identityRegistry) external; + + /** + * @dev sets the compliance contract of the token + * @param _compliance the address of the compliance contract to set + * Only the owner of the token smart contract can call this function + * calls bindToken on the compliance contract + * emits a `ComplianceAdded` event + */ + function setCompliance(address _compliance) external; + + /// Transfer Actions + + /** + * @dev Initiates a forced transfer of tokens between two whitelisted wallets. + * If the `from` address does not have sufficient free tokens (unfrozen tokens) + * but possesses a total balance equal to or greater than the specified `amount`, + * the frozen token amount is reduced to ensure enough free tokens for the transfer. + * In such cases, the remaining balance in the `from` account consists entirely of frozen tokens post-transfer. + * It is imperative that the `to` address is a verified and whitelisted address. + * @param _from The address of the sender. + * @param _to The address of the receiver. + * @param _amount The number of tokens to be transferred. + * This function can only be invoked by a wallet designated as an agent of the token, + * provided the agent is not restricted from initiating forced transfers of the token. + * Emits a `TokensUnfrozen` event if `_amount` is higher than the free balance of `_from`. + * Also emits a `Transfer` event. + * To execute this function, the calling agent must not be restricted from initiating forced transfers of the token. + * If the agent is restricted from this capability, the function call will fail. + * The function can only be called when the contract is not already paused. + * error `AgentNotAuthorized` - Thrown if the agent is restricted from initiating forced transfers of the token, + * indicating they do not have the necessary permissions to execute this function. + */ + function forcedTransfer( + address _from, + address _to, + uint256 _amount + ) external returns (bool); + + /** + * @dev Mints tokens to a specified address. + * This enhanced version of the default mint method allows tokens to be minted + * to an address only if it is a verified and whitelisted address according to the security token. + * @param _to Address to mint the tokens to. + * @param _amount Amount of tokens to mint. + * This function can only be called by a wallet designated as an agent of the token, + * provided the agent is not restricted from minting tokens. + * Emits a `Transfer` event upon successful minting. + * To execute this function, the calling agent must not be restricted from minting tokens. + * If the agent is restricted from this capability, the function call will fail. + */ + function mint(address _to, uint256 _amount) external; + + /** + * @dev Burns tokens from a specified address. + * If the account address does not have sufficient free tokens (unfrozen tokens) + * but possesses a total balance equal to or greater than the specified value, + * the frozen token amount is reduced to ensure enough free tokens for the burn. + * In such cases, the remaining balance in the account consists entirely of frozen tokens post-transaction. + * @param _userAddress Address to burn the tokens from. + * @param _amount Amount of tokens to burn. + * This function can only be called by a wallet designated as an agent of the token, + * provided the agent is not restricted from burning tokens. + * Emits a `TokensUnfrozen` event if `_amount` exceeds the free balance of `_userAddress`. + * Also emits a `Transfer` event. + * To execute this function, the calling agent must not be restricted from burning tokens. + * If the agent is restricted from this capability, the function call will fail. + */ + function burn(address _userAddress, uint256 _amount) external; + + /** + * @dev Initiates a recovery process to transfer tokens and associated states + * from a lost wallet to a new wallet for an investor. + * + * This function allows an authorized agent to recover tokens from a lost wallet, + * transferring them to a new wallet while preserving the investor's + * identity and status within the token ecosystem. The function ensures that all relevant data, + * including frozen tokens and address freezing status, is accurately transferred to the new wallet. + * + * @param _lostWallet The wallet that the investor lost, containing the tokens to be recovered. + * @param _newWallet The newly provided wallet to which tokens and associated statuses must be transferred. + * @param _investorOnchainID The ONCHAINID of the investor whose tokens are being recovered. + * + * Requirements: + * - The caller must be an agent authorized to perform recovery operations, with no restrictions on this capability. + * - The `_lostWallet` must have a non-zero token balance; otherwise, the recovery is unnecessary and will revert. + * - Either the `_lostWallet` or the `_newWallet` must be present in the identity registry; + * if neither is present, the function will revert. + * + * Operations: + * - Transfers the entire token balance from `_lostWallet` to `_newWallet`. + * - Transfers any frozen tokens from `_lostWallet` to `_newWallet`, updating the frozen token count accordingly. + * - Transfers the address freeze status from `_lostWallet` to `_newWallet`, + * ensuring the new wallet retains any restrictions if applicable. + * - Updates the identity registry: + * - If `_lostWallet` is listed in the identity registry, it will be removed, + * and `_newWallet` will be registered unless already present. + * + * Emits the following events: + * - `TokensUnfrozen` if there are frozen tokens on `_lostWallet` that are transferred. + * - `TokensFrozen` if frozen tokens are added to `_newWallet`. + * - `AddressFrozen` if the freeze status of either wallet changes. + * - `Transfer` to reflect the movement of tokens from `_lostWallet` to `_newWallet`. + * - `RecoverySuccess` upon successful completion of the recovery process. + * + * Reverts if: + * - The agent calling the function does not have the necessary permissions to perform recovery (`AgentNotAuthorized`). + * - The `_lostWallet` has no tokens to recover (`NoTokenToRecover`). + * - Neither `_lostWallet` nor `_newWallet` is present in the identity registry (`RecoveryNotPossible`). + * + * @return A boolean value indicating whether the recovery process was successful. + */ + function recoveryAddress( + address _lostWallet, + address _newWallet, + address _investorOnchainID + ) external returns (bool); + + /// Batch Actions + + /** + * @dev function allowing to issue transfers in batch + * Require that the msg.sender and `to` addresses are not frozen. + * Require that the total value should not exceed available balance. + * Require that the `to` addresses are all verified addresses, + * IMPORTANT : THIS TRANSACTION COULD EXCEED GAS LIMIT IF `_toList.length` IS TOO HIGH, + * USE WITH CARE OR YOU COULD LOSE TX FEES WITH AN "OUT OF GAS" TRANSACTION + * @param _toList The addresses of the receivers + * @param _amounts The number of tokens to transfer to the corresponding receiver + * emits _toList.length `Transfer` events + */ + function batchTransfer(address[] calldata _toList, uint256[] calldata _amounts) external; + + /** + * @dev Initiates forced transfers in batch. + * Requires that each _amounts[i] does not exceed the available balance of _fromList[i]. + * Requires that the _toList addresses are all verified and whitelisted addresses. + * IMPORTANT: THIS TRANSACTION COULD EXCEED GAS LIMIT IF _fromList.length IS TOO HIGH. + * USE WITH CARE TO AVOID "OUT OF GAS" TRANSACTIONS AND POTENTIAL LOSS OF TX FEES. + * @param _fromList The addresses of the senders. + * @param _toList The addresses of the receivers. + * @param _amounts The number of tokens to transfer to the corresponding receiver. + * This function can only be called by a wallet designated as an agent of the token, + * provided the agent is not restricted from initiating forced transfers in batch. + * Emits `TokensUnfrozen` events for each `_amounts[i]` that exceeds the free balance of `_fromList[i]`. + * Also emits _fromList.length `Transfer` events upon successful batch transfer. + * To execute this function, the calling agent must not be restricted from initiating forced transfer. + * If the agent is restricted from this capability, the function call will fail. + */ + function batchForcedTransfer( + address[] calldata _fromList, + address[] calldata _toList, + uint256[] calldata _amounts + ) external; + + /** + * @dev Initiates minting of tokens in batch. + * Requires that the `_toList` addresses are all verified and whitelisted addresses. + * IMPORTANT: THIS TRANSACTION COULD EXCEED GAS LIMIT IF `_toList.length` IS TOO HIGH. + * USE WITH CARE TO AVOID "OUT OF GAS" TRANSACTIONS AND POTENTIAL LOSS OF TX FEES. + * @param _toList The addresses of the receivers. + * @param _amounts The number of tokens to mint to the corresponding receiver. + * This function can only be called by a wallet designated as an agent of the token, + * provided the agent is not restricted from minting tokens. + * Emits _toList.length `Transfer` events upon successful batch minting. + * To execute this function, the calling agent must not be restricted from minting tokens. + * If the agent is restricted from this capability, the function call will fail. + */ + function batchMint(address[] calldata _toList, uint256[] calldata _amounts) external; + + /** + * @dev Initiates burning of tokens in batch. + * Requires that the `_userAddresses` addresses are all verified and whitelisted addresses. + * IMPORTANT: THIS TRANSACTION COULD EXCEED GAS LIMIT IF `_userAddresses.length` IS TOO HIGH. + * USE WITH CARE TO AVOID "OUT OF GAS" TRANSACTIONS AND POTENTIAL LOSS OF TX FEES. + * @param _userAddresses The addresses of the wallets concerned by the burn. + * @param _amounts The number of tokens to burn from the corresponding wallets. + * This function can only be called by a wallet designated as an agent of the token, + * provided the agent is not restricted from burning tokens. + * Emits _userAddresses.length `Transfer` events upon successful batch burn. + * To execute this function, the calling agent must not be restricted from burning tokens. + * If the agent is restricted from this capability, the function call will fail. + */ + function batchBurn(address[] calldata _userAddresses, uint256[] calldata _amounts) external; + + /** + * @dev Initiates setting of frozen status for addresses in batch. + * IMPORTANT: THIS TRANSACTION COULD EXCEED GAS LIMIT IF `_userAddresses.length` IS TOO HIGH. + * USE WITH CARE TO AVOID "OUT OF GAS" TRANSACTIONS AND POTENTIAL LOSS OF TX FEES. + * @param _userAddresses The addresses for which to update frozen status. + * @param _freeze Frozen status of the corresponding address. + * This function can only be called by a wallet designated as an agent of the token, + * provided the agent is not restricted from setting frozen addresses. + * Emits _userAddresses.length `AddressFrozen` events upon successful batch update of frozen status. + * To execute this function, the calling agent must not be restricted from setting frozen addresses. + * If the agent is restricted from this capability, the function call will fail. + */ + function batchSetAddressFrozen(address[] calldata _userAddresses, bool[] calldata _freeze) external; + + /** + * @dev Initiates partial freezing of tokens in batch. + * IMPORTANT: THIS TRANSACTION COULD EXCEED GAS LIMIT IF `_userAddresses.length` IS TOO HIGH. + * USE WITH CARE TO AVOID "OUT OF GAS" TRANSACTIONS AND POTENTIAL LOSS OF TX FEES. + * @param _userAddresses The addresses on which tokens need to be partially frozen. + * @param _amounts The amount of tokens to freeze on the corresponding address. + * This function can only be called by a wallet designated as an agent of the token, + * provided the agent is not restricted from partially freezing tokens. + * Emits _userAddresses.length `TokensFrozen` events upon successful batch partial freezing. + * To execute this function, the calling agent must not be restricted from partially freezing tokens. + * If the agent is restricted from this capability, the function call will fail. + */ + function batchFreezePartialTokens(address[] calldata _userAddresses, uint256[] calldata _amounts) external; + + /** + * @dev Initiates partial unfreezing of tokens in batch. + * IMPORTANT: THIS TRANSACTION COULD EXCEED GAS LIMIT IF `_userAddresses.length` IS TOO HIGH. + * USE WITH CARE TO AVOID "OUT OF GAS" TRANSACTIONS AND POTENTIAL LOSS OF TX FEES. + * @param _userAddresses The addresses on which tokens need to be partially unfrozen. + * @param _amounts The amount of tokens to unfreeze on the corresponding address. + * This function can only be called by a wallet designated as an agent of the token, + * provided the agent is not restricted from partially freezing tokens. + * Emits _userAddresses.length `TokensUnfrozen` events upon successful batch partial unfreezing. + * To execute this function, the calling agent must not be restricted from partially freezing tokens. + * If the agent is restricted from this capability, the function call will fail. + */ + function batchUnfreezePartialTokens(address[] calldata _userAddresses, uint256[] calldata _amounts) external; + + /// Getters + + /** + * @dev Returns the address of the onchainID of the token. + * the onchainID of the token gives all the information available + * about the token and is managed by the token issuer or his agent. + */ + function onchainID() external view returns (address); + /** + * @dev Returns the TREX version of the token. + */ + function version() external view returns (string memory); + + /** + * @dev Returns the Identity Registry linked to the token + */ + function identityRegistry() external view returns (IERC3643IdentityRegistry); + + /** + * @dev Returns the Compliance contract linked to the token + */ + function compliance() external view returns (IERC3643Compliance); + + /** + * @dev Returns true if the contract is paused, and false otherwise. + */ + function paused() external view returns (bool); + + /** + * @dev Returns the freezing status of a wallet + * if isFrozen returns `true` the wallet is frozen + * if isFrozen returns `false` the wallet is not frozen + * isFrozen returning `true` doesn't mean that the balance is free, tokens could be blocked by + * a partial freeze or the whole token could be blocked by pause + * @param _userAddress the address of the wallet on which isFrozen is called + */ + function isFrozen(address _userAddress) external view returns (bool); + + /** + * @dev Returns the amount of tokens that are partially frozen on a wallet + * the amount of frozen tokens is always <= to the total balance of the wallet + * @param _userAddress the address of the wallet on which getFrozenTokens is called + */ + function getFrozenTokens(address _userAddress) external view returns (uint256); +} diff --git a/contracts/ERC-3643/IERC3643ClaimTopicsRegistry.sol b/contracts/ERC-3643/IERC3643ClaimTopicsRegistry.sol new file mode 100644 index 00000000..256230ca --- /dev/null +++ b/contracts/ERC-3643/IERC3643ClaimTopicsRegistry.sol @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: CC0-1.0 +// +// :+#####%%%%%%%%%%%%%%+ +// .-*@@@%+.:+%@@@@@%%#***%@@%= +// :=*%@@@#=. :#@@% *@@@%= +// .-+*%@%*-.:+%@@@@@@+. -*+: .=#. :%@@@%- +// :=*@@@@%%@@@@@@@@@%@@@- .=#@@@%@%= =@@@@#. +// -=+#%@@%#*=:. :%@@@@%. -*@@#*@@@@@@@#=:- *@@@@+ +// =@@%=:. :=: *@@@@@%#- =%*%@@@@#+-. =+ :%@@@%- +// -@@%. .+@@@ =+=-. @@#- +@@@%- =@@@@%: +// :@@@. .+@@#%: : .=*=-::.-%@@@+*@@= +@@@@#. +// %@@: +@%%* =%@@@@@@@@@@@#. .*@%- +@@@@*. +// #@@= .+@@@@%:=*@@@@@- :%@%: .*@@@@+ +// *@@* +@@@#-@@%-:%@@* +@@#. :%@@@@- +// -@@% .:-=++*##%%%@@@@@@@@@@@@*. :@+.@@@%: .#@@+ =@@@@#: +// .@@@*-+*#%%%@@@@@@@@@@@@@@@@%%#**@@%@@@. *@=*@@# :#@%= .#@@@@#- +// -%@@@@@@@@@@@@@@@*+==-:-@@@= *@# .#@*-=*@@@@%= -%@@@* =@@@@@%- +// -+%@@@#. %@%%= -@@:+@: -@@* *@@*-:: -%@@%=. .*@@@@@# +// *@@@* +@* *@@##@@- #@*@@+ -@@= . :+@@@#: .-+@@@%+- +// +@@@%*@@:..=@@@@* .@@@* .#@#. .=+- .=%@@@*. :+#@@@@*=: +// =@@@@%@@@@@@@@@@@@@@@@@@@@@@%- :+#*. :*@@@%=. .=#@@@@%+: +// .%@@= ..... .=#@@+. .#@@@*: -*%@@@@%+. +// +@@#+===---:::... .=%@@*- +@@@+. -*@@@@@%+. +// -@@@@@@@@@@@@@@@@@@@@@@%@@@@= -@@@+ -#@@@@@#=. +// ..:::---===+++***###%%%@@@#- .#@@+ -*@@@@@#=. +// @@@@@@+. +@@*. .+@@@@@%=. +// -@@@@@= =@@%: -#@@@@%+. +// +@@@@@. =@@@= .+@@@@@*: +// #@@@@#:%@@#. :*@@@@#- +// @@@@@%@@@= :#@@@@+. +// :@@@@@@@#.:#@@@%- +// +@@@@@@-.*@@@*: +// #@@@@#.=@@@+. +// @@@@+-%@%= +// :@@@#%@%= +// +@@@@%- +// :#%%= +// +pragma solidity 0.8.26; + +/// Events + +/// @dev This event is emitted when a claim topic has been added to the ClaimTopicsRegistry. +/// @param _claimTopic is the required claim added to the Claim Topics Registry. +event ClaimTopicAdded(uint256 indexed _claimTopic); + +/// @dev This event is emitted when a claim topic has been removed from the ClaimTopicsRegistry. +/// @param _claimTopic is the required claim removed from the Claim Topics Registry. +event ClaimTopicRemoved(uint256 indexed _claimTopic); + +interface IERC3643ClaimTopicsRegistry { + /** + * @dev Add a trusted claim topic (For example: KYC=1, AML=2). + * Only owner can call. + * emits `ClaimTopicAdded` event + * cannot add more than 15 topics for 1 token as adding more could create gas issues + * @param _claimTopic The claim topic index + */ + function addClaimTopic(uint256 _claimTopic) external; + + /** + * @dev Remove a trusted claim topic (For example: KYC=1, AML=2). + * Only owner can call. + * emits `ClaimTopicRemoved` event + * @param _claimTopic The claim topic index + */ + function removeClaimTopic(uint256 _claimTopic) external; + + /** + * @dev Get the trusted claim topics for the security token + * @return Array of trusted claim topics + */ + function getClaimTopics() external view returns (uint256[] memory); +} diff --git a/contracts/ERC-3643/IERC3643Compliance.sol b/contracts/ERC-3643/IERC3643Compliance.sol new file mode 100644 index 00000000..6f7a3e61 --- /dev/null +++ b/contracts/ERC-3643/IERC3643Compliance.sol @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: CC0-1.0 +// +// :+#####%%%%%%%%%%%%%%+ +// .-*@@@%+.:+%@@@@@%%#***%@@%= +// :=*%@@@#=. :#@@% *@@@%= +// .-+*%@%*-.:+%@@@@@@+. -*+: .=#. :%@@@%- +// :=*@@@@%%@@@@@@@@@%@@@- .=#@@@%@%= =@@@@#. +// -=+#%@@%#*=:. :%@@@@%. -*@@#*@@@@@@@#=:- *@@@@+ +// =@@%=:. :=: *@@@@@%#- =%*%@@@@#+-. =+ :%@@@%- +// -@@%. .+@@@ =+=-. @@#- +@@@%- =@@@@%: +// :@@@. .+@@#%: : .=*=-::.-%@@@+*@@= +@@@@#. +// %@@: +@%%* =%@@@@@@@@@@@#. .*@%- +@@@@*. +// #@@= .+@@@@%:=*@@@@@- :%@%: .*@@@@+ +// *@@* +@@@#-@@%-:%@@* +@@#. :%@@@@- +// -@@% .:-=++*##%%%@@@@@@@@@@@@*. :@+.@@@%: .#@@+ =@@@@#: +// .@@@*-+*#%%%@@@@@@@@@@@@@@@@%%#**@@%@@@. *@=*@@# :#@%= .#@@@@#- +// -%@@@@@@@@@@@@@@@*+==-:-@@@= *@# .#@*-=*@@@@%= -%@@@* =@@@@@%- +// -+%@@@#. %@%%= -@@:+@: -@@* *@@*-:: -%@@%=. .*@@@@@# +// *@@@* +@* *@@##@@- #@*@@+ -@@= . :+@@@#: .-+@@@%+- +// +@@@%*@@:..=@@@@* .@@@* .#@#. .=+- .=%@@@*. :+#@@@@*=: +// =@@@@%@@@@@@@@@@@@@@@@@@@@@@%- :+#*. :*@@@%=. .=#@@@@%+: +// .%@@= ..... .=#@@+. .#@@@*: -*%@@@@%+. +// +@@#+===---:::... .=%@@*- +@@@+. -*@@@@@%+. +// -@@@@@@@@@@@@@@@@@@@@@@%@@@@= -@@@+ -#@@@@@#=. +// ..:::---===+++***###%%%@@@#- .#@@+ -*@@@@@#=. +// @@@@@@+. +@@*. .+@@@@@%=. +// -@@@@@= =@@%: -#@@@@%+. +// +@@@@@. =@@@= .+@@@@@*: +// #@@@@#:%@@#. :*@@@@#- +// @@@@@%@@@= :#@@@@+. +// :@@@@@@@#.:#@@@%- +// +@@@@@@-.*@@@*: +// #@@@@#.=@@@+. +// @@@@+-%@%= +// :@@@#%@%= +// +@@@@%- +// :#%%= +// +pragma solidity 0.8.26; + +/// Events + +/// @dev This event is emitted when a token has been bound to the compliance contract. +/// @param _token is the address of the token to bind. +event TokenBound(address _token); + +/// @dev This event is emitted when a token has been unbound from the compliance contract. +/// @param _token is the address of the token to unbind. +event TokenUnbound(address _token); + +interface IERC3643Compliance { + + + /// Functions + + /// initialization of the compliance contract + + /** + * @dev binds a token to the compliance contract + * @param _token address of the token to bind + * This function can be called ONLY by the owner of the compliance contract + * Emits a TokenBound event + */ + function bindToken(address _token) external; + + /** + * @dev unbinds a token from the compliance contract + * @param _token address of the token to unbind + * This function can be called ONLY by the owner of the compliance contract + * Emits a TokenUnbound event + */ + function unbindToken(address _token) external; + + + + // compliance check and state update + /** + * @dev function called whenever tokens are transferred + * from one wallet to another + * this function can update state variables in the modules bound to the compliance + * these state variables being used by the module checks to decide if a transfer + * is compliant or not depending on the values stored in these state variables and on + * the parameters of the modules + * This function can be called ONLY by the token contract bound to the compliance + * @param _from The address of the sender + * @param _to The address of the receiver + * @param _amount The amount of tokens involved in the transfer + * This function calls moduleTransferAction() on each module bound to the compliance contract + */ + function transferred( + address _from, + address _to, + uint256 _amount + ) external; + + /** + * @dev function called whenever tokens are created on a wallet + * this function can update state variables in the modules bound to the compliance + * these state variables being used by the module checks to decide if a transfer + * is compliant or not depending on the values stored in these state variables and on + * the parameters of the modules + * This function can be called ONLY by the token contract bound to the compliance + * @param _to The address of the receiver + * @param _amount The amount of tokens involved in the minting + * This function calls moduleMintAction() on each module bound to the compliance contract + */ + function created(address _to, uint256 _amount) external; + + /** + * @dev function called whenever tokens are destroyed from a wallet + * this function can update state variables in the modules bound to the compliance + * these state variables being used by the module checks to decide if a transfer + * is compliant or not depending on the values stored in these state variables and on + * the parameters of the modules + * This function can be called ONLY by the token contract bound to the compliance + * @param _from The address on which tokens are burnt + * @param _amount The amount of tokens involved in the burn + * This function calls moduleBurnAction() on each module bound to the compliance contract + */ + function destroyed(address _from, uint256 _amount) external; + + /** + * @dev checks that the transfer is compliant. + * default compliance always returns true + * READ ONLY FUNCTION, this function cannot be used to increment + * counters, emit events, ... + * @param _from The address of the sender + * @param _to The address of the receiver + * @param _amount The amount of tokens involved in the transfer + * This function will call moduleCheck() on every module bound to the compliance + * If each of the module checks return TRUE, this function will return TRUE as well + * returns FALSE otherwise + */ + function canTransfer( + address _from, + address _to, + uint256 _amount + ) external view returns (bool); + + /// check the parameters of the compliance contract + + function isTokenBound(address _token) external view returns (bool); + + /** + * @dev getter for the address of the token bound + * returns the address of the token + */ + function getTokenBound() external view returns (address); + +} diff --git a/contracts/ERC-3643/IERC3643IdentityRegistry.sol b/contracts/ERC-3643/IERC3643IdentityRegistry.sol new file mode 100644 index 00000000..d64d8a59 --- /dev/null +++ b/contracts/ERC-3643/IERC3643IdentityRegistry.sol @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: CC0-1.0 +// +// :+#####%%%%%%%%%%%%%%+ +// .-*@@@%+.:+%@@@@@%%#***%@@%= +// :=*%@@@#=. :#@@% *@@@%= +// .-+*%@%*-.:+%@@@@@@+. -*+: .=#. :%@@@%- +// :=*@@@@%%@@@@@@@@@%@@@- .=#@@@%@%= =@@@@#. +// -=+#%@@%#*=:. :%@@@@%. -*@@#*@@@@@@@#=:- *@@@@+ +// =@@%=:. :=: *@@@@@%#- =%*%@@@@#+-. =+ :%@@@%- +// -@@%. .+@@@ =+=-. @@#- +@@@%- =@@@@%: +// :@@@. .+@@#%: : .=*=-::.-%@@@+*@@= +@@@@#. +// %@@: +@%%* =%@@@@@@@@@@@#. .*@%- +@@@@*. +// #@@= .+@@@@%:=*@@@@@- :%@%: .*@@@@+ +// *@@* +@@@#-@@%-:%@@* +@@#. :%@@@@- +// -@@% .:-=++*##%%%@@@@@@@@@@@@*. :@+.@@@%: .#@@+ =@@@@#: +// .@@@*-+*#%%%@@@@@@@@@@@@@@@@%%#**@@%@@@. *@=*@@# :#@%= .#@@@@#- +// -%@@@@@@@@@@@@@@@*+==-:-@@@= *@# .#@*-=*@@@@%= -%@@@* =@@@@@%- +// -+%@@@#. %@%%= -@@:+@: -@@* *@@*-:: -%@@%=. .*@@@@@# +// *@@@* +@* *@@##@@- #@*@@+ -@@= . :+@@@#: .-+@@@%+- +// +@@@%*@@:..=@@@@* .@@@* .#@#. .=+- .=%@@@*. :+#@@@@*=: +// =@@@@%@@@@@@@@@@@@@@@@@@@@@@%- :+#*. :*@@@%=. .=#@@@@%+: +// .%@@= ..... .=#@@+. .#@@@*: -*%@@@@%+. +// +@@#+===---:::... .=%@@*- +@@@+. -*@@@@@%+. +// -@@@@@@@@@@@@@@@@@@@@@@%@@@@= -@@@+ -#@@@@@#=. +// ..:::---===+++***###%%%@@@#- .#@@+ -*@@@@@#=. +// @@@@@@+. +@@*. .+@@@@@%=. +// -@@@@@= =@@%: -#@@@@%+. +// +@@@@@. =@@@= .+@@@@@*: +// #@@@@#:%@@#. :*@@@@#- +// @@@@@%@@@= :#@@@@+. +// :@@@@@@@#.:#@@@%- +// +@@@@@@-.*@@@*: +// #@@@@#.=@@@+. +// @@@@+-%@%= +// :@@@#%@%= +// +@@@@%- +// :#%%= +// +pragma solidity 0.8.26; + +import "@onchain-id/solidity/contracts/interface/IIdentity.sol"; +import "./IERC3643IdentityRegistryStorage.sol"; +import "./IERC3643TrustedIssuersRegistry.sol"; +import "./IERC3643ClaimTopicsRegistry.sol"; + +/// Events + +/// @dev This event is emitted when the ClaimTopicsRegistry has been set for the IdentityRegistry. +/// @param _claimTopicsRegistry is the address of the Claim Topics Registry contract. +event ClaimTopicsRegistrySet(address indexed _claimTopicsRegistry); + +/// @dev This event is emitted when the IdentityRegistryStorage has been set for the IdentityRegistry. +/// @param _identityStorage is the address of the Identity Registry Storage contract. +event IdentityStorageSet(address indexed _identityStorage); + +/// @dev This event is emitted when the TrustedIssuersRegistry has been set for the IdentityRegistry. +/// @param _trustedIssuersRegistry is the address of the Trusted Issuers Registry contract. +event TrustedIssuersRegistrySet(address indexed _trustedIssuersRegistry); + +/// @dev This event is emitted when an Identity is registered into the Identity Registry. +/// @param _investorAddress is the address of the investor's wallet. +/// @param _identity is the address of the Identity smart contract (onchainID). +event IdentityRegistered(address indexed _investorAddress, IIdentity indexed _identity); + +/// @dev This event is emitted when an Identity is removed from the Identity Registry. +/// @param _investorAddress is the address of the investor's wallet. +/// @param _identity is the address of the Identity smart contract (onchainID). +event IdentityRemoved(address indexed _investorAddress, IIdentity indexed _identity); + +/// @dev This event is emitted when an Identity has been updated. +/// @param _oldIdentity is the old Identity contract's address to update. +/// @param _newIdentity is the new Identity contract's. +event IdentityUpdated(IIdentity indexed _oldIdentity, IIdentity indexed _newIdentity); + +/// @dev This event is emitted when an Identity's country has been updated. +/// @param _investorAddress is the address on which the country has been updated +/// @param _country is the numeric code (ISO 3166-1) of the new country +event CountryUpdated(address indexed _investorAddress, uint16 indexed _country); + +interface IERC3643IdentityRegistry { + + /// Functions + + /// Identity Registry Setters + + /** + * @dev Replace the actual identityRegistryStorage contract with a new one. + * This function can only be called by the wallet set as owner of the smart contract + * @param _identityRegistryStorage The address of the new Identity Registry Storage + * emits `IdentityStorageSet` event + */ + function setIdentityRegistryStorage(address _identityRegistryStorage) external; + + /** + * @dev Replace the actual claimTopicsRegistry contract with a new one. + * This function can only be called by the wallet set as owner of the smart contract + * @param _claimTopicsRegistry The address of the new claim Topics Registry + * emits `ClaimTopicsRegistrySet` event + */ + function setClaimTopicsRegistry(address _claimTopicsRegistry) external; + + /** + * @dev Replace the actual trustedIssuersRegistry contract with a new one. + * This function can only be called by the wallet set as owner of the smart contract + * @param _trustedIssuersRegistry The address of the new Trusted Issuers Registry + * emits `TrustedIssuersRegistrySet` event + */ + function setTrustedIssuersRegistry(address _trustedIssuersRegistry) external; + + /// Registry Actions + /** + * @dev Register an identity contract corresponding to a user address. + * Requires that the user doesn't have an identity contract already registered. + * This function can only be called by a wallet set as agent of the smart contract + * @param _userAddress The address of the user + * @param _identity The address of the user's identity contract + * @param _country The country of the investor + * emits `IdentityRegistered` event + */ + function registerIdentity( + address _userAddress, + IIdentity _identity, + uint16 _country + ) external; + + /** + * @dev Removes an user from the identity registry. + * Requires that the user have an identity contract already deployed that will be deleted. + * This function can only be called by a wallet set as agent of the smart contract + * @param _userAddress The address of the user to be removed + * emits `IdentityRemoved` event + */ + function deleteIdentity(address _userAddress) external; + + /** + * @dev Updates the country corresponding to a user address. + * Requires that the user should have an identity contract already deployed that will be replaced. + * This function can only be called by a wallet set as agent of the smart contract + * @param _userAddress The address of the user + * @param _country The new country of the user + * emits `CountryUpdated` event + */ + function updateCountry(address _userAddress, uint16 _country) external; + + /** + * @dev Updates an identity contract corresponding to a user address. + * Requires that the user address should be the owner of the identity contract. + * Requires that the user should have an identity contract already deployed that will be replaced. + * This function can only be called by a wallet set as agent of the smart contract + * @param _userAddress The address of the user + * @param _identity The address of the user's new identity contract + * emits `IdentityUpdated` event + */ + function updateIdentity(address _userAddress, IIdentity _identity) external; + + /** + * @dev function allowing to register identities in batch + * This function can only be called by a wallet set as agent of the smart contract + * Requires that none of the users has an identity contract already registered. + * IMPORTANT : THIS TRANSACTION COULD EXCEED GAS LIMIT IF `_userAddresses.length` IS TOO HIGH, + * USE WITH CARE OR YOU COULD LOSE TX FEES WITH AN "OUT OF GAS" TRANSACTION + * @param _userAddresses The addresses of the users + * @param _identities The addresses of the corresponding identity contracts + * @param _countries The countries of the corresponding investors + * emits _userAddresses.length `IdentityRegistered` events + */ + function batchRegisterIdentity( + address[] calldata _userAddresses, + IIdentity[] calldata _identities, + uint16[] calldata _countries + ) external; + + /// Registry Consultation + + /** + * @dev This functions checks whether a wallet has its Identity registered or not + * in the Identity Registry. + * @param _userAddress The address of the user to be checked. + * @return 'True' if the address is contained in the Identity Registry, 'false' if not. + */ + function contains(address _userAddress) external view returns (bool); + + /** + * @dev This functions checks whether an identity contract + * corresponding to the provided user address has the required claims or not based + * on the data fetched from trusted issuers registry and from the claim topics registry + * @param _userAddress The address of the user to be verified. + * @return 'True' if the address is verified, 'false' if not. + */ + function isVerified(address _userAddress) external view returns (bool); + + /** + * @dev Returns the onchainID of an investor. + * @param _userAddress The wallet of the investor + */ + function identity(address _userAddress) external view returns (IIdentity); + + /** + * @dev Returns the country code of an investor. + * @param _userAddress The wallet of the investor + */ + function investorCountry(address _userAddress) external view returns (uint16); + + // identity registry getters + /** + * @dev Returns the IdentityRegistryStorage linked to the current IdentityRegistry. + */ + function identityStorage() external view returns (IERC3643IdentityRegistryStorage); + + /** + * @dev Returns the TrustedIssuersRegistry linked to the current IdentityRegistry. + */ + function issuersRegistry() external view returns (IERC3643TrustedIssuersRegistry); + + /** + * @dev Returns the ClaimTopicsRegistry linked to the current IdentityRegistry. + */ + function topicsRegistry() external view returns (IERC3643ClaimTopicsRegistry); + +} diff --git a/contracts/ERC-3643/IERC3643IdentityRegistryStorage.sol b/contracts/ERC-3643/IERC3643IdentityRegistryStorage.sol new file mode 100644 index 00000000..db68bb8e --- /dev/null +++ b/contracts/ERC-3643/IERC3643IdentityRegistryStorage.sol @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: CC0-1.0 +// +// :+#####%%%%%%%%%%%%%%+ +// .-*@@@%+.:+%@@@@@%%#***%@@%= +// :=*%@@@#=. :#@@% *@@@%= +// .-+*%@%*-.:+%@@@@@@+. -*+: .=#. :%@@@%- +// :=*@@@@%%@@@@@@@@@%@@@- .=#@@@%@%= =@@@@#. +// -=+#%@@%#*=:. :%@@@@%. -*@@#*@@@@@@@#=:- *@@@@+ +// =@@%=:. :=: *@@@@@%#- =%*%@@@@#+-. =+ :%@@@%- +// -@@%. .+@@@ =+=-. @@#- +@@@%- =@@@@%: +// :@@@. .+@@#%: : .=*=-::.-%@@@+*@@= +@@@@#. +// %@@: +@%%* =%@@@@@@@@@@@#. .*@%- +@@@@*. +// #@@= .+@@@@%:=*@@@@@- :%@%: .*@@@@+ +// *@@* +@@@#-@@%-:%@@* +@@#. :%@@@@- +// -@@% .:-=++*##%%%@@@@@@@@@@@@*. :@+.@@@%: .#@@+ =@@@@#: +// .@@@*-+*#%%%@@@@@@@@@@@@@@@@%%#**@@%@@@. *@=*@@# :#@%= .#@@@@#- +// -%@@@@@@@@@@@@@@@*+==-:-@@@= *@# .#@*-=*@@@@%= -%@@@* =@@@@@%- +// -+%@@@#. %@%%= -@@:+@: -@@* *@@*-:: -%@@%=. .*@@@@@# +// *@@@* +@* *@@##@@- #@*@@+ -@@= . :+@@@#: .-+@@@%+- +// +@@@%*@@:..=@@@@* .@@@* .#@#. .=+- .=%@@@*. :+#@@@@*=: +// =@@@@%@@@@@@@@@@@@@@@@@@@@@@%- :+#*. :*@@@%=. .=#@@@@%+: +// .%@@= ..... .=#@@+. .#@@@*: -*%@@@@%+. +// +@@#+===---:::... .=%@@*- +@@@+. -*@@@@@%+. +// -@@@@@@@@@@@@@@@@@@@@@@%@@@@= -@@@+ -#@@@@@#=. +// ..:::---===+++***###%%%@@@#- .#@@+ -*@@@@@#=. +// @@@@@@+. +@@*. .+@@@@@%=. +// -@@@@@= =@@%: -#@@@@%+. +// +@@@@@. =@@@= .+@@@@@*: +// #@@@@#:%@@#. :*@@@@#- +// @@@@@%@@@= :#@@@@+. +// :@@@@@@@#.:#@@@%- +// +@@@@@@-.*@@@*: +// #@@@@#.=@@@+. +// @@@@+-%@%= +// :@@@#%@%= +// +@@@@%- +// :#%%= +// +pragma solidity 0.8.26; +import "@onchain-id/solidity/contracts/interface/IIdentity.sol"; + +/// events + +/// @dev This event is emitted when an Identity is registered into the storage contract. +/// @param _investorAddress` is the address of the investor's wallet. +/// @param _identity` is the address of the Identity smart contract (onchainID). +event IdentityStored(address indexed _investorAddress, IIdentity indexed _identity); + +/// @dev This event is emitted when an Identity is removed from the storage contract. +/// @param _investorAddress is the address of the investor's wallet. +/// @param _identity is the address of the Identity smart contract (onchainID). +event IdentityUnstored(address indexed _investorAddress, IIdentity indexed _identity); + +/// @dev This event is emitted when an Identity has been updated. +/// @param _oldIdentity is the old Identity contract's address to update. +/// @param _newIdentity is the new Identity contract's. +event IdentityModified(IIdentity indexed _oldIdentity, IIdentity indexed _newIdentity); + +/// @dev This event is emitted when an Identity's country has been updated. +/// @param _investorAddress is the address on which the country has been updated. +/// @param _country is the numeric code (ISO 3166-1) of the new country. +event CountryModified(address indexed _investorAddress, uint16 indexed _country); + +/// @dev This event is emitted when an Identity Registry is bound to the storage contract. +/// @param _identityRegistry is the address of the identity registry added. +event IdentityRegistryBound(address indexed _identityRegistry); + +/// @dev This event is emitted when an Identity Registry is unbound from the storage contract. +/// @param _identityRegistry is the address of the identity registry removed. +event IdentityRegistryUnbound(address indexed _identityRegistry); + +interface IERC3643IdentityRegistryStorage { + + /// functions + + /** + * @dev adds an identity contract corresponding to a user address in the storage. + * Requires that the user doesn't have an identity contract already registered. + * This function can only be called by an address set as agent of the smart contract + * @param _userAddress The address of the user + * @param _identity The address of the user's identity contract + * @param _country The country of the investor + * emits `IdentityStored` event + */ + function addIdentityToStorage( + address _userAddress, + IIdentity _identity, + uint16 _country + ) external; + + /** + * @dev Removes an user from the storage. + * Requires that the user have an identity contract already deployed that will be deleted. + * This function can only be called by an address set as agent of the smart contract + * @param _userAddress The address of the user to be removed + * emits `IdentityUnstored` event + */ + function removeIdentityFromStorage(address _userAddress) external; + + /** + * @dev Updates the country corresponding to a user address. + * Requires that the user should have an identity contract already deployed that will be replaced. + * This function can only be called by an address set as agent of the smart contract + * @param _userAddress The address of the user + * @param _country The new country of the user + * emits `CountryModified` event + */ + function modifyStoredInvestorCountry(address _userAddress, uint16 _country) external; + + /** + * @dev Updates an identity contract corresponding to a user address. + * Requires that the user address should be the owner of the identity contract. + * Requires that the user should have an identity contract already deployed that will be replaced. + * This function can only be called by an address set as agent of the smart contract + * @param _userAddress The address of the user + * @param _identity The address of the user's new identity contract + * emits `IdentityModified` event + */ + function modifyStoredIdentity(address _userAddress, IIdentity _identity) external; + + /** + * @notice Adds an identity registry as agent of the Identity Registry Storage Contract. + * This function can only be called by the wallet set as owner of the smart contract + * This function adds the identity registry to the list of identityRegistries linked to the storage contract + * cannot bind more than 300 IR to 1 IRS + * @param _identityRegistry The identity registry address to add. + */ + function bindIdentityRegistry(address _identityRegistry) external; + + /** + * @notice Removes an identity registry from being agent of the Identity Registry Storage Contract. + * This function can only be called by the wallet set as owner of the smart contract + * This function removes the identity registry from the list of identityRegistries linked to the storage contract + * @param _identityRegistry The identity registry address to remove. + */ + function unbindIdentityRegistry(address _identityRegistry) external; + + /** + * @dev Returns the identity registries linked to the storage contract + */ + function linkedIdentityRegistries() external view returns (address[] memory); + + /** + * @dev Returns the onchainID of an investor. + * @param _userAddress The wallet of the investor + */ + function storedIdentity(address _userAddress) external view returns (IIdentity); + + /** + * @dev Returns the country code of an investor. + * @param _userAddress The wallet of the investor + */ + function storedInvestorCountry(address _userAddress) external view returns (uint16); +} diff --git a/contracts/ERC-3643/IERC3643TrustedIssuersRegistry.sol b/contracts/ERC-3643/IERC3643TrustedIssuersRegistry.sol new file mode 100644 index 00000000..06ed14f0 --- /dev/null +++ b/contracts/ERC-3643/IERC3643TrustedIssuersRegistry.sol @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: CC0-1.0 +// +// :+#####%%%%%%%%%%%%%%+ +// .-*@@@%+.:+%@@@@@%%#***%@@%= +// :=*%@@@#=. :#@@% *@@@%= +// .-+*%@%*-.:+%@@@@@@+. -*+: .=#. :%@@@%- +// :=*@@@@%%@@@@@@@@@%@@@- .=#@@@%@%= =@@@@#. +// -=+#%@@%#*=:. :%@@@@%. -*@@#*@@@@@@@#=:- *@@@@+ +// =@@%=:. :=: *@@@@@%#- =%*%@@@@#+-. =+ :%@@@%- +// -@@%. .+@@@ =+=-. @@#- +@@@%- =@@@@%: +// :@@@. .+@@#%: : .=*=-::.-%@@@+*@@= +@@@@#. +// %@@: +@%%* =%@@@@@@@@@@@#. .*@%- +@@@@*. +// #@@= .+@@@@%:=*@@@@@- :%@%: .*@@@@+ +// *@@* +@@@#-@@%-:%@@* +@@#. :%@@@@- +// -@@% .:-=++*##%%%@@@@@@@@@@@@*. :@+.@@@%: .#@@+ =@@@@#: +// .@@@*-+*#%%%@@@@@@@@@@@@@@@@%%#**@@%@@@. *@=*@@# :#@%= .#@@@@#- +// -%@@@@@@@@@@@@@@@*+==-:-@@@= *@# .#@*-=*@@@@%= -%@@@* =@@@@@%- +// -+%@@@#. %@%%= -@@:+@: -@@* *@@*-:: -%@@%=. .*@@@@@# +// *@@@* +@* *@@##@@- #@*@@+ -@@= . :+@@@#: .-+@@@%+- +// +@@@%*@@:..=@@@@* .@@@* .#@#. .=+- .=%@@@*. :+#@@@@*=: +// =@@@@%@@@@@@@@@@@@@@@@@@@@@@%- :+#*. :*@@@%=. .=#@@@@%+: +// .%@@= ..... .=#@@+. .#@@@*: -*%@@@@%+. +// +@@#+===---:::... .=%@@*- +@@@+. -*@@@@@%+. +// -@@@@@@@@@@@@@@@@@@@@@@%@@@@= -@@@+ -#@@@@@#=. +// ..:::---===+++***###%%%@@@#- .#@@+ -*@@@@@#=. +// @@@@@@+. +@@*. .+@@@@@%=. +// -@@@@@= =@@%: -#@@@@%+. +// +@@@@@. =@@@= .+@@@@@*: +// #@@@@#:%@@#. :*@@@@#- +// @@@@@%@@@= :#@@@@+. +// :@@@@@@@#.:#@@@%- +// +@@@@@@-.*@@@*: +// #@@@@#.=@@@+. +// @@@@+-%@%= +// :@@@#%@%= +// +@@@@%- +// :#%%= +// +pragma solidity 0.8.26; +import "@onchain-id/solidity/contracts/interface/IClaimIssuer.sol"; + +/// Events + +/// @dev This event is emitted when a trusted issuer is added in the registry. +/// @param _trustedIssuer is the address of the trusted issuer's ClaimIssuer contract. +/// @param _claimTopics is the set of claims that the trusted issuer is allowed to emit. +event TrustedIssuerAdded(IClaimIssuer indexed _trustedIssuer, uint256[] _claimTopics); + +/// @dev This event is emitted when a trusted issuer is removed from the registry. +/// @param _trustedIssuer is the address of the trusted issuer's ClaimIssuer contract. +event TrustedIssuerRemoved(IClaimIssuer indexed _trustedIssuer); + +/// &dev This event is emitted when the set of claim topics is changed for a given trusted issuer. +/// @param _trustedIssuer is the address of the trusted issuer's ClaimIssuer contract +/// @param _claimTopics is the set of claims that the trusted issuer is allowed to emit. +event ClaimTopicsUpdated(IClaimIssuer indexed _trustedIssuer, uint256[] _claimTopics); + + +interface IERC3643TrustedIssuersRegistry { + + // Functions + + // Setters + /** + * @dev registers a ClaimIssuer contract as trusted claim issuer. + * Requires that a ClaimIssuer contract doesn't already exist + * Requires that the claimTopics set is not empty + * Requires that there is no more than 15 claimTopics + * Requires that there is no more than 50 Trusted issuers + * @param _trustedIssuer The ClaimIssuer contract address of the trusted claim issuer. + * @param _claimTopics the set of claim topics that the trusted issuer is allowed to emit + * This function can only be called by the owner of the Trusted Issuers Registry contract + * emits a `TrustedIssuerAdded` event + */ + function addTrustedIssuer(IClaimIssuer _trustedIssuer, uint256[] calldata _claimTopics) external; + + /** + * @dev Removes the ClaimIssuer contract of a trusted claim issuer. + * Requires that the claim issuer contract to be registered first + * @param _trustedIssuer the claim issuer to remove. + * This function can only be called by the owner of the Trusted Issuers Registry contract + * emits a `TrustedIssuerRemoved` event + */ + function removeTrustedIssuer(IClaimIssuer _trustedIssuer) external; + + /** + * @dev Updates the set of claim topics that a trusted issuer is allowed to emit. + * Requires that this ClaimIssuer contract already exists in the registry + * Requires that the provided claimTopics set is not empty + * Requires that there is no more than 15 claimTopics + * @param _trustedIssuer the claim issuer to update. + * @param _claimTopics the set of claim topics that the trusted issuer is allowed to emit + * This function can only be called by the owner of the Trusted Issuers Registry contract + * emits a `ClaimTopicsUpdated` event + */ + function updateIssuerClaimTopics(IClaimIssuer _trustedIssuer, uint256[] calldata _claimTopics) external; + + /// Getters + + /** + * @dev Function for getting all the trusted claim issuers stored. + * @return array of all claim issuers registered. + */ + function getTrustedIssuers() external view returns (IClaimIssuer[] memory); + + /** + * @dev Function for getting all the trusted issuer allowed for a given claim topic. + * @param claimTopic the claim topic to get the trusted issuers for. + * @return array of all claim issuer addresses that are allowed for the given claim topic. + */ + function getTrustedIssuersForClaimTopic(uint256 claimTopic) external view returns (IClaimIssuer[] memory); + + /** + * @dev Checks if the ClaimIssuer contract is trusted + * @param _issuer the address of the ClaimIssuer contract + * @return true if the issuer is trusted, false otherwise. + */ + function isTrustedIssuer(address _issuer) external view returns (bool); + + /** + * @dev Function for getting all the claim topic of trusted claim issuer + * Requires the provided ClaimIssuer contract to be registered in the trusted issuers registry. + * @param _trustedIssuer the trusted issuer concerned. + * @return The set of claim topics that the trusted issuer is allowed to emit + */ + function getTrustedIssuerClaimTopics(IClaimIssuer _trustedIssuer) external view returns (uint256[] memory); + + /** + * @dev Function for checking if the trusted claim issuer is allowed + * to emit a certain claim topic + * @param _issuer the address of the trusted issuer's ClaimIssuer contract + * @param _claimTopic the Claim Topic that has to be checked to know if the `issuer` is allowed to emit it + * @return true if the issuer is trusted for this claim topic. + */ + function hasClaimTopic(address _issuer, uint256 _claimTopic) external view returns (bool); +} diff --git a/contracts/compliance/modular/IModularCompliance.sol b/contracts/compliance/modular/IModularCompliance.sol index 53b79e28..40a1ed99 100644 --- a/contracts/compliance/modular/IModularCompliance.sol +++ b/contracts/compliance/modular/IModularCompliance.sol @@ -62,6 +62,8 @@ pragma solidity 0.8.26; +import "../../ERC-3643/IERC3643Compliance.sol"; + /// events /// @dev Event emitted for each executed interaction with a module contract. @@ -72,15 +74,6 @@ pragma solidity 0.8.26; event ModuleInteraction(address indexed _target, bytes4 _selector); -/// @dev This event is emitted when a token has been bound to the compliance contract. -/// @param _token is the address of the token to bind. -event TokenBound(address _token); - -/// @dev This event is emitted when a token has been unbound from the compliance contract. -/// @param _token is the address of the token to unbind. -event TokenUnbound(address _token); - - /// @dev This event is emitted when a module has been added to the list of modules bound to the compliance contract. /// @param _module The address of the compliance module. event ModuleAdded(address indexed _module); @@ -91,26 +84,10 @@ event ModuleAdded(address indexed _module); event ModuleRemoved(address indexed _module); -interface IModularCompliance { +interface IModularCompliance is IERC3643Compliance { /// functions - /** - * @dev binds a token to the compliance contract - * @param _token address of the token to bind - * This function can be called ONLY by the owner of the compliance contract - * Emits a TokenBound event - */ - function bindToken(address _token) external; - - /** - * @dev unbinds a token from the compliance contract - * @param _token address of the token to unbind - * This function can be called ONLY by the owner of the compliance contract - * Emits a TokenUnbound event - */ - function unbindToken(address _token) external; - /** * @dev adds a module to the list of compliance modules * @param _module address of the module to add @@ -172,81 +149,12 @@ interface IModularCompliance { */ function addAndSetModule(address _module, bytes[] calldata _interactions) external; - /** - * @dev function called whenever tokens are transferred - * from one wallet to another - * this function can update state variables in the modules bound to the compliance - * these state variables being used by the module checks to decide if a transfer - * is compliant or not depending on the values stored in these state variables and on - * the parameters of the modules - * This function can be called ONLY by the token contract bound to the compliance - * @param _from The address of the sender - * @param _to The address of the receiver - * @param _amount The amount of tokens involved in the transfer - * This function calls moduleTransferAction() on each module bound to the compliance contract - */ - function transferred( - address _from, - address _to, - uint256 _amount - ) external; - - /** - * @dev function called whenever tokens are created on a wallet - * this function can update state variables in the modules bound to the compliance - * these state variables being used by the module checks to decide if a transfer - * is compliant or not depending on the values stored in these state variables and on - * the parameters of the modules - * This function can be called ONLY by the token contract bound to the compliance - * @param _to The address of the receiver - * @param _amount The amount of tokens involved in the minting - * This function calls moduleMintAction() on each module bound to the compliance contract - */ - function created(address _to, uint256 _amount) external; - - /** - * @dev function called whenever tokens are destroyed from a wallet - * this function can update state variables in the modules bound to the compliance - * these state variables being used by the module checks to decide if a transfer - * is compliant or not depending on the values stored in these state variables and on - * the parameters of the modules - * This function can be called ONLY by the token contract bound to the compliance - * @param _from The address on which tokens are burnt - * @param _amount The amount of tokens involved in the burn - * This function calls moduleBurnAction() on each module bound to the compliance contract - */ - function destroyed(address _from, uint256 _amount) external; - - /** - * @dev checks that the transfer is compliant. - * default compliance always returns true - * READ ONLY FUNCTION, this function cannot be used to increment - * counters, emit events, ... - * @param _from The address of the sender - * @param _to The address of the receiver - * @param _amount The amount of tokens involved in the transfer - * This function will call moduleCheck() on every module bound to the compliance - * If each of the module checks return TRUE, this function will return TRUE as well - * returns FALSE otherwise - */ - function canTransfer( - address _from, - address _to, - uint256 _amount - ) external view returns (bool); - /** * @dev getter for the modules bound to the compliance contract * returns address array of module contracts bound to the compliance */ function getModules() external view returns (address[] memory); - /** - * @dev getter for the address of the token bound - * returns the address of the token - */ - function getTokenBound() external view returns (address); - /** * @dev checks if a module is bound to the compliance contract * returns true if module is bound, false otherwise diff --git a/contracts/compliance/modular/ModularCompliance.sol b/contracts/compliance/modular/ModularCompliance.sol index 67310fc8..d2ecf752 100644 --- a/contracts/compliance/modular/ModularCompliance.sol +++ b/contracts/compliance/modular/ModularCompliance.sol @@ -109,7 +109,7 @@ contract ModularCompliance is IModularCompliance, OwnableUpgradeable, MCStorage, } /** - * @dev See {IModularCompliance-bindToken}. + * @dev See {IERC3643Compliance-bindToken}. */ function bindToken(address _token) external override { require(owner() == msg.sender || (_tokenBound == address(0) && msg.sender == _token), OnlyOwnerOrTokenCanCall()); @@ -119,7 +119,7 @@ contract ModularCompliance is IModularCompliance, OwnableUpgradeable, MCStorage, } /** - * @dev See {IModularCompliance-unbindToken}. + * @dev See {IERC3643Compliance-unbindToken}. */ function unbindToken(address _token) external override { require(owner() == msg.sender || msg.sender == _token , OnlyOwnerOrTokenCanCall()); @@ -149,7 +149,7 @@ contract ModularCompliance is IModularCompliance, OwnableUpgradeable, MCStorage, } /** - * @dev See {IModularCompliance-transferred}. + * @dev See {IERC3643Compliance-transferred}. */ function transferred(address _from, address _to, uint256 _value) external onlyToken override { require( @@ -164,7 +164,7 @@ contract ModularCompliance is IModularCompliance, OwnableUpgradeable, MCStorage, } /** - * @dev See {IModularCompliance-created}. + * @dev See {IERC3643Compliance-created}. */ function created(address _to, uint256 _value) external onlyToken override { require(_to != address(0), ZeroAddress()); @@ -176,7 +176,7 @@ contract ModularCompliance is IModularCompliance, OwnableUpgradeable, MCStorage, } /** - * @dev See {IModularCompliance-destroyed}. + * @dev See {IERC3643Compliance-destroyed}. */ function destroyed(address _from, uint256 _value) external onlyToken override { require(_from != address(0), ZeroAddress()); @@ -213,14 +213,24 @@ contract ModularCompliance is IModularCompliance, OwnableUpgradeable, MCStorage, } /** - * @dev See {IModularCompliance-getTokenBound}. + * @dev See {IERC3643Compliance-getTokenBound}. */ function getTokenBound() external view override returns (address) { return _tokenBound; } /** - * @dev See {IModularCompliance-canTransfer}. + * @dev See {IERC3643Compliance-getTokenBound}. + */ + function isTokenBound(address _token) external view override returns (bool) { + if(_token == _tokenBound) { + return true; + } + return false; + } + + /** + * @dev See {IERC3643Compliance-canTransfer}. */ function canTransfer(address _from, address _to, uint256 _value) external view override returns (bool) { uint256 length = _modules.length; @@ -292,6 +302,7 @@ contract ModularCompliance is IModularCompliance, OwnableUpgradeable, MCStorage, function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) { return interfaceId == type(IModularCompliance).interfaceId || + interfaceId == type(IERC3643Compliance).interfaceId || interfaceId == type(IERC173).interfaceId || interfaceId == type(IERC165).interfaceId; } diff --git a/contracts/compliance/modular/modules/TransferFeesModule.sol b/contracts/compliance/modular/modules/TransferFeesModule.sol index 672ce857..b57cbc83 100644 --- a/contracts/compliance/modular/modules/TransferFeesModule.sol +++ b/contracts/compliance/modular/modules/TransferFeesModule.sol @@ -127,7 +127,7 @@ contract TransferFeesModule is AbstractModuleUpgradeable { address tokenAddress = IModularCompliance(msg.sender).getTokenBound(); require(_rate <= 10000, FeeRateIsOutOfRange(msg.sender, _rate)); - IIdentityRegistry identityRegistry = IToken(tokenAddress).identityRegistry(); + IERC3643IdentityRegistry identityRegistry = IToken(tokenAddress).identityRegistry(); require(identityRegistry.isVerified(_collector), CollectorAddressIsNotVerified(msg.sender, _collector)); _fees[msg.sender].rate = _rate; diff --git a/contracts/proxy/authority/TREXImplementationAuthority.sol b/contracts/proxy/authority/TREXImplementationAuthority.sol index 761affe3..95a8009a 100644 --- a/contracts/proxy/authority/TREXImplementationAuthority.sol +++ b/contracts/proxy/authority/TREXImplementationAuthority.sol @@ -197,9 +197,9 @@ contract TREXImplementationAuthority is ITREXImplementationAuthority, Ownable, I address _ir = address(IToken(_token).identityRegistry()); address _mc = address(IToken(_token).compliance()); - address _irs = address(IIdentityRegistry(_ir).identityStorage()); - address _ctr = address(IIdentityRegistry(_ir).topicsRegistry()); - address _tir = address(IIdentityRegistry(_ir).issuersRegistry()); + address _irs = address(IERC3643IdentityRegistry(_ir).identityStorage()); + address _ctr = address(IERC3643IdentityRegistry(_ir).topicsRegistry()); + address _tir = address(IERC3643IdentityRegistry(_ir).issuersRegistry()); // calling this function requires ownership of ALL contracts of the T-REX suite require( diff --git a/contracts/registry/implementation/ClaimTopicsRegistry.sol b/contracts/registry/implementation/ClaimTopicsRegistry.sol index 638d5c4d..a9129cda 100644 --- a/contracts/registry/implementation/ClaimTopicsRegistry.sol +++ b/contracts/registry/implementation/ClaimTopicsRegistry.sol @@ -124,7 +124,7 @@ contract ClaimTopicsRegistry is IClaimTopicsRegistry, OwnableUpgradeable, CTRSto */ function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) { return - interfaceId == type(IClaimTopicsRegistry).interfaceId || + interfaceId == type(IERC3643ClaimTopicsRegistry).interfaceId || interfaceId == type(IERC173).interfaceId || interfaceId == type(IERC165).interfaceId; } diff --git a/contracts/registry/implementation/IdentityRegistry.sol b/contracts/registry/implementation/IdentityRegistry.sol index 052e3a78..9193ee13 100644 --- a/contracts/registry/implementation/IdentityRegistry.sol +++ b/contracts/registry/implementation/IdentityRegistry.sol @@ -261,21 +261,21 @@ contract IdentityRegistry is IIdentityRegistry, AgentRoleUpgradeable, IRStorage, /** * @dev See {IIdentityRegistry-issuersRegistry}. */ - function issuersRegistry() external view override returns (ITrustedIssuersRegistry) { + function issuersRegistry() external view override returns (IERC3643TrustedIssuersRegistry) { return _tokenIssuersRegistry; } /** * @dev See {IIdentityRegistry-topicsRegistry}. */ - function topicsRegistry() external view override returns (IClaimTopicsRegistry) { + function topicsRegistry() external view override returns (IERC3643ClaimTopicsRegistry) { return _tokenTopicsRegistry; } /** * @dev See {IIdentityRegistry-identityStorage}. */ - function identityStorage() external view override returns (IIdentityRegistryStorage) { + function identityStorage() external view override returns (IERC3643IdentityRegistryStorage) { return _tokenIdentityStorage; } @@ -314,6 +314,7 @@ contract IdentityRegistry is IIdentityRegistry, AgentRoleUpgradeable, IRStorage, function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) { return interfaceId == type(IIdentityRegistry).interfaceId || + interfaceId == type(IERC3643IdentityRegistry).interfaceId || interfaceId == type(IERC173).interfaceId || interfaceId == type(IERC165).interfaceId; } diff --git a/contracts/registry/implementation/IdentityRegistryStorage.sol b/contracts/registry/implementation/IdentityRegistryStorage.sol index b2cb19ab..2291a1e4 100644 --- a/contracts/registry/implementation/IdentityRegistryStorage.sol +++ b/contracts/registry/implementation/IdentityRegistryStorage.sol @@ -201,7 +201,7 @@ contract IdentityRegistryStorage is IIdentityRegistryStorage, AgentRoleUpgradeab */ function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) { return - interfaceId == type(IIdentityRegistryStorage).interfaceId || + interfaceId == type(IERC3643IdentityRegistryStorage).interfaceId || interfaceId == type(IERC173).interfaceId || interfaceId == type(IERC165).interfaceId; } diff --git a/contracts/registry/implementation/TrustedIssuersRegistry.sol b/contracts/registry/implementation/TrustedIssuersRegistry.sol index 559f0a54..acc6d50c 100644 --- a/contracts/registry/implementation/TrustedIssuersRegistry.sol +++ b/contracts/registry/implementation/TrustedIssuersRegistry.sol @@ -234,7 +234,7 @@ contract TrustedIssuersRegistry is ITrustedIssuersRegistry, OwnableUpgradeable, */ function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) { return - interfaceId == type(ITrustedIssuersRegistry).interfaceId || + interfaceId == type(IERC3643TrustedIssuersRegistry).interfaceId || interfaceId == type(IERC173).interfaceId || interfaceId == type(IERC165).interfaceId; } diff --git a/contracts/registry/interface/IClaimTopicsRegistry.sol b/contracts/registry/interface/IClaimTopicsRegistry.sol index d117e451..b83c29bf 100644 --- a/contracts/registry/interface/IClaimTopicsRegistry.sol +++ b/contracts/registry/interface/IClaimTopicsRegistry.sol @@ -62,39 +62,11 @@ pragma solidity 0.8.26; -/// Events +import "../../ERC-3643/IERC3643ClaimTopicsRegistry.sol"; -/// @dev This event is emitted when a claim topic has been added to the ClaimTopicsRegistry. -/// @param _claimTopic is the required claim added to the Claim Topics Registry. -event ClaimTopicAdded(uint256 indexed _claimTopic); +// solhint-disable-next-line no-empty-blocks +interface IClaimTopicsRegistry is IERC3643ClaimTopicsRegistry { -/// @dev This event is emitted when a claim topic has been removed from the ClaimTopicsRegistry. -/// @param _claimTopic is the required claim removed from the Claim Topics Registry. -event ClaimTopicRemoved(uint256 indexed _claimTopic); +// functions that are not part of the original standard can be added here in future versions - -interface IClaimTopicsRegistry { - - /** - * @dev Add a trusted claim topic (For example: KYC=1, AML=2). - * Only owner can call. - * emits `ClaimTopicAdded` event - * cannot add more than 15 topics for 1 token as adding more could create gas issues - * @param _claimTopic The claim topic index - */ - function addClaimTopic(uint256 _claimTopic) external; - - /** - * @dev Remove a trusted claim topic (For example: KYC=1, AML=2). - * Only owner can call. - * emits `ClaimTopicRemoved` event - * @param _claimTopic The claim topic index - */ - function removeClaimTopic(uint256 _claimTopic) external; - - /** - * @dev Get the trusted claim topics for the security token - * @return Array of trusted claim topics - */ - function getClaimTopics() external view returns (uint256[] memory); } diff --git a/contracts/registry/interface/IIdentityRegistry.sol b/contracts/registry/interface/IIdentityRegistry.sol index 7639687f..26469b19 100644 --- a/contracts/registry/interface/IIdentityRegistry.sol +++ b/contracts/registry/interface/IIdentityRegistry.sol @@ -62,47 +62,10 @@ pragma solidity 0.8.26; -import "./ITrustedIssuersRegistry.sol"; -import "./IClaimTopicsRegistry.sol"; -import "./IIdentityRegistryStorage.sol"; - -import "@onchain-id/solidity/contracts/interface/IClaimIssuer.sol"; -import "@onchain-id/solidity/contracts/interface/IIdentity.sol"; +import "../../ERC-3643/IERC3643IdentityRegistry.sol"; /// Events -/// @dev This event is emitted when the ClaimTopicsRegistry has been set for the IdentityRegistry. -/// @param _claimTopicsRegistry is the address of the Claim Topics Registry contract. -event ClaimTopicsRegistrySet(address indexed _claimTopicsRegistry); - -/// @dev This event is emitted when the IdentityRegistryStorage has been set for the IdentityRegistry. -/// @param _identityStorage is the address of the Identity Registry Storage contract. -event IdentityStorageSet(address indexed _identityStorage); - -/// @dev This event is emitted when the TrustedIssuersRegistry has been set for the IdentityRegistry. -/// @param _trustedIssuersRegistry is the address of the Trusted Issuers Registry contract. -event TrustedIssuersRegistrySet(address indexed _trustedIssuersRegistry); - -/// @dev This event is emitted when an Identity is registered into the Identity Registry. -/// @param _investorAddress is the address of the investor's wallet. -/// @param _identity is the address of the Identity smart contract (onchainID). -event IdentityRegistered(address indexed _investorAddress, IIdentity indexed _identity); - -/// @dev This event is emitted when an Identity is removed from the Identity Registry. -/// @param _investorAddress is the address of the investor's wallet. -/// @param _identity is the address of the Identity smart contract (onchainID). -event IdentityRemoved(address indexed _investorAddress, IIdentity indexed _identity); - -/// @dev This event is emitted when an Identity has been updated. -/// @param _oldIdentity is the old Identity contract's address to update. -/// @param _newIdentity is the new Identity contract's. -event IdentityUpdated(IIdentity indexed _oldIdentity, IIdentity indexed _newIdentity); - -/// @dev This event is emitted when an Identity's country has been updated. -/// @param _investorAddress is the address on which the country has been updated -/// @param _country is the numeric code (ISO 3166-1) of the new country -event CountryUpdated(address indexed _investorAddress, uint16 indexed _country); - /// @dev This event is emitted when Eligibility checks are disabled. event EligibilityChecksDisabled(); @@ -110,93 +73,7 @@ event EligibilityChecksDisabled(); event EligibilityChecksEnabled(); -interface IIdentityRegistry { - - /** - * @dev Register an identity contract corresponding to a user address. - * Requires that the user doesn't have an identity contract already registered. - * This function can only be called by a wallet set as agent of the smart contract - * @param _userAddress The address of the user - * @param _identity The address of the user's identity contract - * @param _country The country of the investor - * emits `IdentityRegistered` event - */ - function registerIdentity( - address _userAddress, - IIdentity _identity, - uint16 _country - ) external; - - /** - * @dev Removes an user from the identity registry. - * Requires that the user have an identity contract already deployed that will be deleted. - * This function can only be called by a wallet set as agent of the smart contract - * @param _userAddress The address of the user to be removed - * emits `IdentityRemoved` event - */ - function deleteIdentity(address _userAddress) external; - - /** - * @dev Replace the actual identityRegistryStorage contract with a new one. - * This function can only be called by the wallet set as owner of the smart contract - * @param _identityRegistryStorage The address of the new Identity Registry Storage - * emits `IdentityStorageSet` event - */ - function setIdentityRegistryStorage(address _identityRegistryStorage) external; - - /** - * @dev Replace the actual claimTopicsRegistry contract with a new one. - * This function can only be called by the wallet set as owner of the smart contract - * @param _claimTopicsRegistry The address of the new claim Topics Registry - * emits `ClaimTopicsRegistrySet` event - */ - function setClaimTopicsRegistry(address _claimTopicsRegistry) external; - - /** - * @dev Replace the actual trustedIssuersRegistry contract with a new one. - * This function can only be called by the wallet set as owner of the smart contract - * @param _trustedIssuersRegistry The address of the new Trusted Issuers Registry - * emits `TrustedIssuersRegistrySet` event - */ - function setTrustedIssuersRegistry(address _trustedIssuersRegistry) external; - - /** - * @dev Updates the country corresponding to a user address. - * Requires that the user should have an identity contract already deployed that will be replaced. - * This function can only be called by a wallet set as agent of the smart contract - * @param _userAddress The address of the user - * @param _country The new country of the user - * emits `CountryUpdated` event - */ - function updateCountry(address _userAddress, uint16 _country) external; - - /** - * @dev Updates an identity contract corresponding to a user address. - * Requires that the user address should be the owner of the identity contract. - * Requires that the user should have an identity contract already deployed that will be replaced. - * This function can only be called by a wallet set as agent of the smart contract - * @param _userAddress The address of the user - * @param _identity The address of the user's new identity contract - * emits `IdentityUpdated` event - */ - function updateIdentity(address _userAddress, IIdentity _identity) external; - - /** - * @dev function allowing to register identities in batch - * This function can only be called by a wallet set as agent of the smart contract - * Requires that none of the users has an identity contract already registered. - * IMPORTANT : THIS TRANSACTION COULD EXCEED GAS LIMIT IF `_userAddresses.length` IS TOO HIGH, - * USE WITH CARE OR YOU COULD LOSE TX FEES WITH AN "OUT OF GAS" TRANSACTION - * @param _userAddresses The addresses of the users - * @param _identities The addresses of the corresponding identity contracts - * @param _countries The countries of the corresponding investors - * emits _userAddresses.length `IdentityRegistered` events - */ - function batchRegisterIdentity( - address[] calldata _userAddresses, - IIdentity[] calldata _identities, - uint16[] calldata _countries - ) external; +interface IIdentityRegistry is IERC3643IdentityRegistry { /** * @dev Disables the eligibility checks for token transfers and other operations. @@ -230,48 +107,4 @@ interface IIdentityRegistry { * Emits an `EligibilityChecksEnabled` event upon successful execution. */ function enableEligibilityChecks() external; - - /** - * @dev This functions checks whether a wallet has its Identity registered or not - * in the Identity Registry. - * @param _userAddress The address of the user to be checked. - * @return 'True' if the address is contained in the Identity Registry, 'false' if not. - */ - function contains(address _userAddress) external view returns (bool); - - /** - * @dev This functions checks whether an identity contract - * corresponding to the provided user address has the required claims or not based - * on the data fetched from trusted issuers registry and from the claim topics registry - * @param _userAddress The address of the user to be verified. - * @return 'True' if the address is verified, 'false' if not. - */ - function isVerified(address _userAddress) external view returns (bool); - - /** - * @dev Returns the onchainID of an investor. - * @param _userAddress The wallet of the investor - */ - function identity(address _userAddress) external view returns (IIdentity); - - /** - * @dev Returns the country code of an investor. - * @param _userAddress The wallet of the investor - */ - function investorCountry(address _userAddress) external view returns (uint16); - - /** - * @dev Returns the IdentityRegistryStorage linked to the current IdentityRegistry. - */ - function identityStorage() external view returns (IIdentityRegistryStorage); - - /** - * @dev Returns the TrustedIssuersRegistry linked to the current IdentityRegistry. - */ - function issuersRegistry() external view returns (ITrustedIssuersRegistry); - - /** - * @dev Returns the ClaimTopicsRegistry linked to the current IdentityRegistry. - */ - function topicsRegistry() external view returns (IClaimTopicsRegistry); } diff --git a/contracts/registry/interface/IIdentityRegistryStorage.sol b/contracts/registry/interface/IIdentityRegistryStorage.sol index e394a040..318fdf10 100644 --- a/contracts/registry/interface/IIdentityRegistryStorage.sol +++ b/contracts/registry/interface/IIdentityRegistryStorage.sol @@ -62,120 +62,11 @@ pragma solidity 0.8.26; -import "@onchain-id/solidity/contracts/interface/IIdentity.sol"; +import "../../ERC-3643/IERC3643IdentityRegistryStorage.sol"; +// solhint-disable-next-line no-empty-blocks +interface IIdentityRegistryStorage is IERC3643IdentityRegistryStorage { -/// events +// functions that are not part of the original standard can be added here in future versions -/// @dev This event is emitted when an Identity is registered into the storage contract. -/// @param _investorAddress` is the address of the investor's wallet. -/// @param _identity` is the address of the Identity smart contract (onchainID). -event IdentityStored(address indexed _investorAddress, IIdentity indexed _identity); - -/// @dev This event is emitted when an Identity is removed from the storage contract. -/// @param _investorAddress is the address of the investor's wallet. -/// @param _identity is the address of the Identity smart contract (onchainID). -event IdentityUnstored(address indexed _investorAddress, IIdentity indexed _identity); - -/// @dev This event is emitted when an Identity has been updated. -/// @param _oldIdentity is the old Identity contract's address to update. -/// @param _newIdentity is the new Identity contract's. -event IdentityModified(IIdentity indexed _oldIdentity, IIdentity indexed _newIdentity); - -/// @dev This event is emitted when an Identity's country has been updated. -/// @param _investorAddress is the address on which the country has been updated. -/// @param _country is the numeric code (ISO 3166-1) of the new country. -event CountryModified(address indexed _investorAddress, uint16 indexed _country); - -/// @dev This event is emitted when an Identity Registry is bound to the storage contract. -/// @param _identityRegistry is the address of the identity registry added. -event IdentityRegistryBound(address indexed _identityRegistry); - -/// @dev This event is emitted when an Identity Registry is unbound from the storage contract. -/// @param _identityRegistry is the address of the identity registry removed. -event IdentityRegistryUnbound(address indexed _identityRegistry); - - -interface IIdentityRegistryStorage { - - /// functions - - /** - * @dev adds an identity contract corresponding to a user address in the storage. - * Requires that the user doesn't have an identity contract already registered. - * This function can only be called by an address set as agent of the smart contract - * @param _userAddress The address of the user - * @param _identity The address of the user's identity contract - * @param _country The country of the investor - * emits `IdentityStored` event - */ - function addIdentityToStorage( - address _userAddress, - IIdentity _identity, - uint16 _country - ) external; - - /** - * @dev Removes an user from the storage. - * Requires that the user have an identity contract already deployed that will be deleted. - * This function can only be called by an address set as agent of the smart contract - * @param _userAddress The address of the user to be removed - * emits `IdentityUnstored` event - */ - function removeIdentityFromStorage(address _userAddress) external; - - /** - * @dev Updates the country corresponding to a user address. - * Requires that the user should have an identity contract already deployed that will be replaced. - * This function can only be called by an address set as agent of the smart contract - * @param _userAddress The address of the user - * @param _country The new country of the user - * emits `CountryModified` event - */ - function modifyStoredInvestorCountry(address _userAddress, uint16 _country) external; - - /** - * @dev Updates an identity contract corresponding to a user address. - * Requires that the user address should be the owner of the identity contract. - * Requires that the user should have an identity contract already deployed that will be replaced. - * This function can only be called by an address set as agent of the smart contract - * @param _userAddress The address of the user - * @param _identity The address of the user's new identity contract - * emits `IdentityModified` event - */ - function modifyStoredIdentity(address _userAddress, IIdentity _identity) external; - - /** - * @notice Adds an identity registry as agent of the Identity Registry Storage Contract. - * This function can only be called by the wallet set as owner of the smart contract - * This function adds the identity registry to the list of identityRegistries linked to the storage contract - * cannot bind more than 300 IR to 1 IRS - * @param _identityRegistry The identity registry address to add. - */ - function bindIdentityRegistry(address _identityRegistry) external; - - /** - * @notice Removes an identity registry from being agent of the Identity Registry Storage Contract. - * This function can only be called by the wallet set as owner of the smart contract - * This function removes the identity registry from the list of identityRegistries linked to the storage contract - * @param _identityRegistry The identity registry address to remove. - */ - function unbindIdentityRegistry(address _identityRegistry) external; - - /** - * @dev Returns the identity registries linked to the storage contract - */ - function linkedIdentityRegistries() external view returns (address[] memory); - - /** - * @dev Returns the onchainID of an investor. - * @param _userAddress The wallet of the investor - */ - function storedIdentity(address _userAddress) external view returns (IIdentity); - - /** - * @dev Returns the country code of an investor. - * @param _userAddress The wallet of the investor - */ - function storedInvestorCountry(address _userAddress) external view returns (uint16); } diff --git a/contracts/registry/interface/ITrustedIssuersRegistry.sol b/contracts/registry/interface/ITrustedIssuersRegistry.sol index 91fdabaa..b5cc75a7 100644 --- a/contracts/registry/interface/ITrustedIssuersRegistry.sol +++ b/contracts/registry/interface/ITrustedIssuersRegistry.sol @@ -62,96 +62,11 @@ */ pragma solidity 0.8.26; +import "../../ERC-3643/IERC3643TrustedIssuersRegistry.sol"; -import "@onchain-id/solidity/contracts/interface/IClaimIssuer.sol"; +// solhint-disable-next-line no-empty-blocks +interface ITrustedIssuersRegistry is IERC3643TrustedIssuersRegistry { -/// Events +// functions that are not part of the original standard can be added here in future versions -/// @dev This event is emitted when a trusted issuer is added in the registry. -/// @param _trustedIssuer is the address of the trusted issuer's ClaimIssuer contract. -/// @param _claimTopics is the set of claims that the trusted issuer is allowed to emit. -event TrustedIssuerAdded(IClaimIssuer indexed _trustedIssuer, uint256[] _claimTopics); - -/// @dev This event is emitted when a trusted issuer is removed from the registry. -/// @param _trustedIssuer is the address of the trusted issuer's ClaimIssuer contract. -event TrustedIssuerRemoved(IClaimIssuer indexed _trustedIssuer); - -/// &dev This event is emitted when the set of claim topics is changed for a given trusted issuer. -/// @param _trustedIssuer is the address of the trusted issuer's ClaimIssuer contract -/// @param _claimTopics is the set of claims that the trusted issuer is allowed to emit. -event ClaimTopicsUpdated(IClaimIssuer indexed _trustedIssuer, uint256[] _claimTopics); - - -interface ITrustedIssuersRegistry { - - /** - * @dev registers a ClaimIssuer contract as trusted claim issuer. - * Requires that a ClaimIssuer contract doesn't already exist - * Requires that the claimTopics set is not empty - * Requires that there is no more than 15 claimTopics - * Requires that there is no more than 50 Trusted issuers - * @param _trustedIssuer The ClaimIssuer contract address of the trusted claim issuer. - * @param _claimTopics the set of claim topics that the trusted issuer is allowed to emit - * This function can only be called by the owner of the Trusted Issuers Registry contract - * emits a `TrustedIssuerAdded` event - */ - function addTrustedIssuer(IClaimIssuer _trustedIssuer, uint256[] calldata _claimTopics) external; - - /** - * @dev Removes the ClaimIssuer contract of a trusted claim issuer. - * Requires that the claim issuer contract to be registered first - * @param _trustedIssuer the claim issuer to remove. - * This function can only be called by the owner of the Trusted Issuers Registry contract - * emits a `TrustedIssuerRemoved` event - */ - function removeTrustedIssuer(IClaimIssuer _trustedIssuer) external; - - /** - * @dev Updates the set of claim topics that a trusted issuer is allowed to emit. - * Requires that this ClaimIssuer contract already exists in the registry - * Requires that the provided claimTopics set is not empty - * Requires that there is no more than 15 claimTopics - * @param _trustedIssuer the claim issuer to update. - * @param _claimTopics the set of claim topics that the trusted issuer is allowed to emit - * This function can only be called by the owner of the Trusted Issuers Registry contract - * emits a `ClaimTopicsUpdated` event - */ - function updateIssuerClaimTopics(IClaimIssuer _trustedIssuer, uint256[] calldata _claimTopics) external; - - /** - * @dev Function for getting all the trusted claim issuers stored. - * @return array of all claim issuers registered. - */ - function getTrustedIssuers() external view returns (IClaimIssuer[] memory); - - /** - * @dev Function for getting all the trusted issuer allowed for a given claim topic. - * @param claimTopic the claim topic to get the trusted issuers for. - * @return array of all claim issuer addresses that are allowed for the given claim topic. - */ - function getTrustedIssuersForClaimTopic(uint256 claimTopic) external view returns (IClaimIssuer[] memory); - - /** - * @dev Checks if the ClaimIssuer contract is trusted - * @param _issuer the address of the ClaimIssuer contract - * @return true if the issuer is trusted, false otherwise. - */ - function isTrustedIssuer(address _issuer) external view returns (bool); - - /** - * @dev Function for getting all the claim topic of trusted claim issuer - * Requires the provided ClaimIssuer contract to be registered in the trusted issuers registry. - * @param _trustedIssuer the trusted issuer concerned. - * @return The set of claim topics that the trusted issuer is allowed to emit - */ - function getTrustedIssuerClaimTopics(IClaimIssuer _trustedIssuer) external view returns (uint256[] memory); - - /** - * @dev Function for checking if the trusted claim issuer is allowed - * to emit a certain claim topic - * @param _issuer the address of the trusted issuer's ClaimIssuer contract - * @param _claimTopic the Claim Topic that has to be checked to know if the `issuer` is allowed to emit it - * @return true if the issuer is trusted for this claim topic. - */ - function hasClaimTopic(address _issuer, uint256 _claimTopic) external view returns (bool); } diff --git a/contracts/token/IToken.sol b/contracts/token/IToken.sol index fe34e2d0..487f9c07 100644 --- a/contracts/token/IToken.sol +++ b/contracts/token/IToken.sol @@ -63,61 +63,8 @@ pragma solidity 0.8.26; -import "../registry/interface/IIdentityRegistry.sol"; -import "../compliance/modular/IModularCompliance.sol"; -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./TokenStructs.sol"; - -/// events - -/// @dev This event is emitted when the token information is updated. -/// @param _newName is the name of the token. -/// @param _newSymbol is the symbol of the token. -/// @param _newDecimals is the decimals of the token. -/// @param _newVersion is the version of the token. -/// @param _newOnchainID is the address of the onchainID of the token. -event UpdatedTokenInformation(string indexed _newName, string indexed _newSymbol, uint8 _newDecimals, - string _newVersion, address indexed _newOnchainID); - -/// @dev This event is emitted when the IdentityRegistry has been set for the token. -/// @param _identityRegistry is the address of the Identity Registry of the token. -event IdentityRegistryAdded(address indexed _identityRegistry); - -/// @dev This event is emitted when the Compliance has been set for the token. -/// @param _compliance is the address of the Compliance contract of the token. -event ComplianceAdded(address indexed _compliance); - -/// @dev This event is emitted when an investor successfully recovers his tokens. -/// @param _lostWallet is the address of the wallet that the investor lost access to. -/// @param _newWallet is the address of the wallet that the investor provided for the recovery. -/// @param _investorOnchainID is the address of the onchainID of the investor who asked for a recovery. -event RecoverySuccess(address indexed _lostWallet, address indexed _newWallet, address indexed _investorOnchainID); - -/// @dev This event is emitted when the wallet of an investor is frozen or unfrozen. -/// @param _userAddress is the wallet of the investor that is concerned by the freezing status. -/// @param _isFrozen is the freezing status of the wallet. -/// @param _isFrozen equals `true` the wallet is frozen after emission of the event. -/// @param _isFrozen equals `false` the wallet is unfrozen after emission of the event. -/// @param _owner is the address of the agent who called the function to freeze the wallet. -event AddressFrozen(address indexed _userAddress, bool indexed _isFrozen, address indexed _owner); - -/// @dev This event is emitted when a certain amount of tokens is frozen on a wallet. -/// @param _userAddress is the wallet of the investor that is concerned by the freezing status. -/// @param _amount is the amount of tokens that are frozen. -event TokensFrozen(address indexed _userAddress, uint256 _amount); - -/// @dev This event is emitted when a certain amount of tokens is unfrozen on a wallet. -/// @param _userAddress is the wallet of the investor that is concerned by the freezing status. -/// @param _amount is the amount of tokens that are unfrozen. -event TokensUnfrozen(address indexed _userAddress, uint256 _amount); - -/// @dev This event is emitted when the token is paused. -/// @param _userAddress is the address of the wallet that called the pause function -event Paused(address _userAddress); - -/// @dev This event is emitted when the token is unpaused. -/// @param _userAddress is the address of the wallet that called the unpause function. -event Unpaused(address _userAddress); +import "../ERC-3643/IERC3643.sol"; /// @dev This event is emitted when restrictions on an agent's roles are updated. /// @param _agent is the address of the agent whose roles are being restricted. @@ -152,220 +99,10 @@ event DefaultAllowanceDisabled(address _user); event DefaultAllowanceEnabled(address _user); /// @dev interface -interface IToken is IERC20 { +interface IToken is IERC3643 { /// functions - /** - * @dev sets the token name - * @param _name the name of token to set - * Only the owner of the token smart contract can call this function - * emits a `UpdatedTokenInformation` event - */ - function setName(string calldata _name) external; - - /** - * @dev sets the token symbol - * @param _symbol the token symbol to set - * Only the owner of the token smart contract can call this function - * emits a `UpdatedTokenInformation` event - */ - function setSymbol(string calldata _symbol) external; - - /** - * @dev sets the onchain ID of the token - * @param _onchainID the address of the onchain ID to set - * Only the owner of the token smart contract can call this function - * emits a `UpdatedTokenInformation` event - */ - function setOnchainID(address _onchainID) external; - - /** - * @dev Pauses the token contract. When the contract is paused, investors cannot transfer tokens anymore. - * This function can only be called by an agent of the token, provided the agent is not restricted from pausing the token. - * emits a `Paused` event upon successful execution. - * To pause token transfers, the calling agent must have pausing capabilities enabled. - * If the agent is disabled from pausing, the function call will fail. - * The function can be called only when the contract is not already paused. - * error AgentNotAuthorized - Thrown if the agent is disabled from pausing the token, - * indicating they do not have the necessary permissions to execute this function. - */ - function pause() external; - - /** - * @dev Unpauses the token contract, allowing investors to resume token transfers under normal conditions - * This function can only be called by an agent of the token, provided the agent is not restricted from pausing the token. - * emits an `Unpaused` event upon successful execution. - * To unpause token transfers, the calling agent must have pausing capabilities enabled. - * If the agent is disabled from pausing, the function call will fail. - * The function can be called only when the contract is currently paused. - * error AgentNotAuthorized - Thrown if the agent is disabled from pausing the token, - * indicating they do not have the necessary permissions to execute this function. - */ - function unpause() external; - - /** - * @dev Sets an address's frozen status for this token, - * either freezing or unfreezing the address based on the provided boolean value. - * This function can be called by an agent of the token, assuming the agent is not restricted from freezing addresses. - * emits an `AddressFrozen` event upon successful execution. - * @param _userAddress The address for which to update the frozen status. - * @param _freeze The frozen status to be applied: `true` to freeze, `false` to unfreeze. - * @notice To change an address's frozen status, the calling agent must have the capability to freeze addresses enabled. - * If the agent is disabled from freezing addresses, the function call will fail. - * error AgentNotAuthorized - Thrown if the agent is disabled from freezing addresses, - * indicating they do not have the necessary permissions to execute this function. - */ - function setAddressFrozen(address _userAddress, bool _freeze) external; - - /** - * @dev Freezes a specified token amount for a given address, preventing those tokens from being transferred. - * This function can be called by an agent of the token, provided the agent is not restricted from freezing tokens. - * emits a `TokensFrozen` event upon successful execution. - * @param _userAddress The address for which to freeze tokens. - * @param _amount The amount of tokens to be frozen. - * @notice To freeze tokens for an address, the calling agent must have the capability to freeze tokens enabled. - * If the agent is disabled from freezing tokens, the function call will fail. - * error AgentNotAuthorized - Thrown if the agent is disabled from freezing tokens, - * indicating they do not have the necessary permissions to execute this function. - */ - function freezePartialTokens(address _userAddress, uint256 _amount) external; - - /** - * @dev Unfreezes a specified token amount for a given address, allowing those tokens to be transferred again. - * This function can be called by an agent of the token, assuming the agent is not restricted from unfreezing tokens. - * emits a `TokensUnfrozen` event upon successful execution. - * @param _userAddress The address for which to unfreeze tokens. - * @param _amount The amount of tokens to be unfrozen. - * @notice To unfreeze tokens for an address, the calling agent must have the capability to unfreeze tokens enabled. - * If the agent is disabled from unfreezing tokens, the function call will fail. - * error AgentNotAuthorized - Thrown if the agent is disabled from unfreezing tokens, - * indicating they do not have the necessary permissions to execute this function. - */ - function unfreezePartialTokens(address _userAddress, uint256 _amount) external; - - /** - * @dev sets the Identity Registry for the token - * @param _identityRegistry the address of the Identity Registry to set - * Only the owner of the token smart contract can call this function - * emits an `IdentityRegistryAdded` event - */ - function setIdentityRegistry(address _identityRegistry) external; - - /** - * @dev sets the compliance contract of the token - * @param _compliance the address of the compliance contract to set - * Only the owner of the token smart contract can call this function - * calls bindToken on the compliance contract - * emits a `ComplianceAdded` event - */ - function setCompliance(address _compliance) external; - - /** - * @dev Initiates a forced transfer of tokens between two whitelisted wallets. - * If the `from` address does not have sufficient free tokens (unfrozen tokens) - * but possesses a total balance equal to or greater than the specified `amount`, - * the frozen token amount is reduced to ensure enough free tokens for the transfer. - * In such cases, the remaining balance in the `from` account consists entirely of frozen tokens post-transfer. - * It is imperative that the `to` address is a verified and whitelisted address. - * @param _from The address of the sender. - * @param _to The address of the receiver. - * @param _amount The number of tokens to be transferred. - * This function can only be invoked by a wallet designated as an agent of the token, - * provided the agent is not restricted from initiating forced transfers of the token. - * Emits a `TokensUnfrozen` event if `_amount` is higher than the free balance of `_from`. - * Also emits a `Transfer` event. - * To execute this function, the calling agent must not be restricted from initiating forced transfers of the token. - * If the agent is restricted from this capability, the function call will fail. - * The function can only be called when the contract is not already paused. - * error `AgentNotAuthorized` - Thrown if the agent is restricted from initiating forced transfers of the token, - * indicating they do not have the necessary permissions to execute this function. - */ - function forcedTransfer( - address _from, - address _to, - uint256 _amount - ) external returns (bool); - - /** - * @dev Mints tokens to a specified address. - * This enhanced version of the default mint method allows tokens to be minted - * to an address only if it is a verified and whitelisted address according to the security token. - * @param _to Address to mint the tokens to. - * @param _amount Amount of tokens to mint. - * This function can only be called by a wallet designated as an agent of the token, - * provided the agent is not restricted from minting tokens. - * Emits a `Transfer` event upon successful minting. - * To execute this function, the calling agent must not be restricted from minting tokens. - * If the agent is restricted from this capability, the function call will fail. - */ - function mint(address _to, uint256 _amount) external; - - /** - * @dev Burns tokens from a specified address. - * If the account address does not have sufficient free tokens (unfrozen tokens) - * but possesses a total balance equal to or greater than the specified value, - * the frozen token amount is reduced to ensure enough free tokens for the burn. - * In such cases, the remaining balance in the account consists entirely of frozen tokens post-transaction. - * @param _userAddress Address to burn the tokens from. - * @param _amount Amount of tokens to burn. - * This function can only be called by a wallet designated as an agent of the token, - * provided the agent is not restricted from burning tokens. - * Emits a `TokensUnfrozen` event if `_amount` exceeds the free balance of `_userAddress`. - * Also emits a `Transfer` event. - * To execute this function, the calling agent must not be restricted from burning tokens. - * If the agent is restricted from this capability, the function call will fail. - */ - function burn(address _userAddress, uint256 _amount) external; - - /** - * @dev Initiates a recovery process to transfer tokens and associated states - * from a lost wallet to a new wallet for an investor. - * - * This function allows an authorized agent to recover tokens from a lost wallet, - * transferring them to a new wallet while preserving the investor's - * identity and status within the token ecosystem. The function ensures that all relevant data, - * including frozen tokens and address freezing status, is accurately transferred to the new wallet. - * - * @param _lostWallet The wallet that the investor lost, containing the tokens to be recovered. - * @param _newWallet The newly provided wallet to which tokens and associated statuses must be transferred. - * @param _investorOnchainID The ONCHAINID of the investor whose tokens are being recovered. - * - * Requirements: - * - The caller must be an agent authorized to perform recovery operations, with no restrictions on this capability. - * - The `_lostWallet` must have a non-zero token balance; otherwise, the recovery is unnecessary and will revert. - * - Either the `_lostWallet` or the `_newWallet` must be present in the identity registry; - * if neither is present, the function will revert. - * - * Operations: - * - Transfers the entire token balance from `_lostWallet` to `_newWallet`. - * - Transfers any frozen tokens from `_lostWallet` to `_newWallet`, updating the frozen token count accordingly. - * - Transfers the address freeze status from `_lostWallet` to `_newWallet`, - * ensuring the new wallet retains any restrictions if applicable. - * - Updates the identity registry: - * - If `_lostWallet` is listed in the identity registry, it will be removed, - * and `_newWallet` will be registered unless already present. - * - * Emits the following events: - * - `TokensUnfrozen` if there are frozen tokens on `_lostWallet` that are transferred. - * - `TokensFrozen` if frozen tokens are added to `_newWallet`. - * - `AddressFrozen` if the freeze status of either wallet changes. - * - `Transfer` to reflect the movement of tokens from `_lostWallet` to `_newWallet`. - * - `RecoverySuccess` upon successful completion of the recovery process. - * - * Reverts if: - * - The agent calling the function does not have the necessary permissions to perform recovery (`AgentNotAuthorized`). - * - The `_lostWallet` has no tokens to recover (`NoTokenToRecover`). - * - Neither `_lostWallet` nor `_newWallet` is present in the identity registry (`RecoveryNotPossible`). - * - * @return A boolean value indicating whether the recovery process was successful. - */ - function recoveryAddress( - address _lostWallet, - address _newWallet, - address _investorOnchainID - ) external returns (bool); - /** * @dev The owner of this address can allow or disallow spending without allowance. * Any `TransferFrom` from these targets won't need allowance (allow = true) or will need allowance (allow = false). @@ -384,113 +121,6 @@ interface IToken is IERC20 { */ function enableDefaultAllowance() external; - /** - * @dev function allowing to issue transfers in batch - * Require that the msg.sender and `to` addresses are not frozen. - * Require that the total value should not exceed available balance. - * Require that the `to` addresses are all verified addresses, - * IMPORTANT : THIS TRANSACTION COULD EXCEED GAS LIMIT IF `_toList.length` IS TOO HIGH, - * USE WITH CARE OR YOU COULD LOSE TX FEES WITH AN "OUT OF GAS" TRANSACTION - * @param _toList The addresses of the receivers - * @param _amounts The number of tokens to transfer to the corresponding receiver - * emits _toList.length `Transfer` events - */ - function batchTransfer(address[] calldata _toList, uint256[] calldata _amounts) external; - - /** - * @dev Initiates forced transfers in batch. - * Requires that each _amounts[i] does not exceed the available balance of _fromList[i]. - * Requires that the _toList addresses are all verified and whitelisted addresses. - * IMPORTANT: THIS TRANSACTION COULD EXCEED GAS LIMIT IF _fromList.length IS TOO HIGH. - * USE WITH CARE TO AVOID "OUT OF GAS" TRANSACTIONS AND POTENTIAL LOSS OF TX FEES. - * @param _fromList The addresses of the senders. - * @param _toList The addresses of the receivers. - * @param _amounts The number of tokens to transfer to the corresponding receiver. - * This function can only be called by a wallet designated as an agent of the token, - * provided the agent is not restricted from initiating forced transfers in batch. - * Emits `TokensUnfrozen` events for each `_amounts[i]` that exceeds the free balance of `_fromList[i]`. - * Also emits _fromList.length `Transfer` events upon successful batch transfer. - * To execute this function, the calling agent must not be restricted from initiating forced transfer. - * If the agent is restricted from this capability, the function call will fail. - */ - function batchForcedTransfer( - address[] calldata _fromList, - address[] calldata _toList, - uint256[] calldata _amounts - ) external; - - /** - * @dev Initiates minting of tokens in batch. - * Requires that the `_toList` addresses are all verified and whitelisted addresses. - * IMPORTANT: THIS TRANSACTION COULD EXCEED GAS LIMIT IF `_toList.length` IS TOO HIGH. - * USE WITH CARE TO AVOID "OUT OF GAS" TRANSACTIONS AND POTENTIAL LOSS OF TX FEES. - * @param _toList The addresses of the receivers. - * @param _amounts The number of tokens to mint to the corresponding receiver. - * This function can only be called by a wallet designated as an agent of the token, - * provided the agent is not restricted from minting tokens. - * Emits _toList.length `Transfer` events upon successful batch minting. - * To execute this function, the calling agent must not be restricted from minting tokens. - * If the agent is restricted from this capability, the function call will fail. - */ - function batchMint(address[] calldata _toList, uint256[] calldata _amounts) external; - - /** - * @dev Initiates burning of tokens in batch. - * Requires that the `_userAddresses` addresses are all verified and whitelisted addresses. - * IMPORTANT: THIS TRANSACTION COULD EXCEED GAS LIMIT IF `_userAddresses.length` IS TOO HIGH. - * USE WITH CARE TO AVOID "OUT OF GAS" TRANSACTIONS AND POTENTIAL LOSS OF TX FEES. - * @param _userAddresses The addresses of the wallets concerned by the burn. - * @param _amounts The number of tokens to burn from the corresponding wallets. - * This function can only be called by a wallet designated as an agent of the token, - * provided the agent is not restricted from burning tokens. - * Emits _userAddresses.length `Transfer` events upon successful batch burn. - * To execute this function, the calling agent must not be restricted from burning tokens. - * If the agent is restricted from this capability, the function call will fail. - */ - function batchBurn(address[] calldata _userAddresses, uint256[] calldata _amounts) external; - - /** - * @dev Initiates setting of frozen status for addresses in batch. - * IMPORTANT: THIS TRANSACTION COULD EXCEED GAS LIMIT IF `_userAddresses.length` IS TOO HIGH. - * USE WITH CARE TO AVOID "OUT OF GAS" TRANSACTIONS AND POTENTIAL LOSS OF TX FEES. - * @param _userAddresses The addresses for which to update frozen status. - * @param _freeze Frozen status of the corresponding address. - * This function can only be called by a wallet designated as an agent of the token, - * provided the agent is not restricted from setting frozen addresses. - * Emits _userAddresses.length `AddressFrozen` events upon successful batch update of frozen status. - * To execute this function, the calling agent must not be restricted from setting frozen addresses. - * If the agent is restricted from this capability, the function call will fail. - */ - function batchSetAddressFrozen(address[] calldata _userAddresses, bool[] calldata _freeze) external; - - /** - * @dev Initiates partial freezing of tokens in batch. - * IMPORTANT: THIS TRANSACTION COULD EXCEED GAS LIMIT IF `_userAddresses.length` IS TOO HIGH. - * USE WITH CARE TO AVOID "OUT OF GAS" TRANSACTIONS AND POTENTIAL LOSS OF TX FEES. - * @param _userAddresses The addresses on which tokens need to be partially frozen. - * @param _amounts The amount of tokens to freeze on the corresponding address. - * This function can only be called by a wallet designated as an agent of the token, - * provided the agent is not restricted from partially freezing tokens. - * Emits _userAddresses.length `TokensFrozen` events upon successful batch partial freezing. - * To execute this function, the calling agent must not be restricted from partially freezing tokens. - * If the agent is restricted from this capability, the function call will fail. - */ - function batchFreezePartialTokens(address[] calldata _userAddresses, uint256[] calldata _amounts) external; - - /** - * @dev Initiates partial unfreezing of tokens in batch. - * IMPORTANT: THIS TRANSACTION COULD EXCEED GAS LIMIT IF `_userAddresses.length` IS TOO HIGH. - * USE WITH CARE TO AVOID "OUT OF GAS" TRANSACTIONS AND POTENTIAL LOSS OF TX FEES. - * @param _userAddresses The addresses on which tokens need to be partially unfrozen. - * @param _amounts The amount of tokens to unfreeze on the corresponding address. - * This function can only be called by a wallet designated as an agent of the token, - * provided the agent is not restricted from partially freezing tokens. - * Emits _userAddresses.length `TokensUnfrozen` events upon successful batch partial unfreezing. - * To execute this function, the calling agent must not be restricted from partially freezing tokens. - * If the agent is restricted from this capability, the function call will fail. - */ - function batchUnfreezePartialTokens(address[] calldata _userAddresses, uint256[] calldata _amounts) external; - /** * @dev Set restrictions on agent's roles. * This function can only be called by the contract owner, as enforced by the `onlyOwner` modifier. @@ -502,76 +132,6 @@ interface IToken is IERC20 { */ function setAgentRestrictions(address agent, TokenRoles memory restrictions) external; - /** - * @dev Returns the number of decimals used to get its user representation. - * For example, if `decimals` equals `2`, a balance of `505` tokens should - * be displayed to a user as `5,05` (`505 / 1 ** 2`). - * - * Tokens usually opt for a value of 18, imitating the relationship between - * Ether and Wei. - * - * NOTE: This information is only used for _display_ purposes: it in - * no way affects any of the arithmetic of the contract, including - * balanceOf() and transfer(). - */ - function decimals() external view returns (uint8); - - /** - * @dev Returns the name of the token. - */ - function name() external view returns (string memory); - - /** - * @dev Returns the address of the onchainID of the token. - * the onchainID of the token gives all the information available - * about the token and is managed by the token issuer or his agent. - */ - function onchainID() external view returns (address); - - /** - * @dev Returns the symbol of the token, usually a shorter version of the - * name. - */ - function symbol() external view returns (string memory); - - /** - * @dev Returns the TREX version of the token. - * current version is 3.0.0 - */ - function version() external view returns (string memory); - - /** - * @dev Returns the Identity Registry linked to the token - */ - function identityRegistry() external view returns (IIdentityRegistry); - - /** - * @dev Returns the Compliance contract linked to the token - */ - function compliance() external view returns (IModularCompliance); - - /** - * @dev Returns true if the contract is paused, and false otherwise. - */ - function paused() external view returns (bool); - - /** - * @dev Returns the freezing status of a wallet - * if isFrozen returns `true` the wallet is frozen - * if isFrozen returns `false` the wallet is not frozen - * isFrozen returning `true` doesn't mean that the balance is free, tokens could be blocked by - * a partial freeze or the whole token could be blocked by pause - * @param _userAddress the address of the wallet on which isFrozen is called - */ - function isFrozen(address _userAddress) external view returns (bool); - - /** - * @dev Returns the amount of tokens that are partially frozen on a wallet - * the amount of frozen tokens is always <= to the total balance of the wallet - * @param _userAddress the address of the wallet on which getFrozenTokens is called - */ - function getFrozenTokens(address _userAddress) external view returns (uint256); - /** * @dev Returns A `TokenRoles` struct containing boolean flags for each restricted role. * Each flag set to `true` disables the corresponding capability for the agent. diff --git a/contracts/token/Token.sol b/contracts/token/Token.sol index c2742ba9..7e8fa0ec 100755 --- a/contracts/token/Token.sol +++ b/contracts/token/Token.sol @@ -455,14 +455,14 @@ contract Token is IToken, AgentRoleUpgradeable, TokenStorage, IERC165 { /** * @dev See {IToken-identityRegistry}. */ - function identityRegistry() external view override returns (IIdentityRegistry) { + function identityRegistry() external view override returns (IERC3643IdentityRegistry) { return _tokenIdentityRegistry; } /** * @dev See {IToken-compliance}. */ - function compliance() external view override returns (IModularCompliance) { + function compliance() external view override returns (IERC3643Compliance) { return _tokenCompliance; } @@ -635,7 +635,7 @@ contract Token is IToken, AgentRoleUpgradeable, TokenStorage, IERC165 { * @dev See {IToken-setIdentityRegistry}. */ function setIdentityRegistry(address _identityRegistry) public override onlyOwner { - _tokenIdentityRegistry = IIdentityRegistry(_identityRegistry); + _tokenIdentityRegistry = IERC3643IdentityRegistry(_identityRegistry); emit IdentityRegistryAdded(_identityRegistry); } @@ -646,7 +646,7 @@ contract Token is IToken, AgentRoleUpgradeable, TokenStorage, IERC165 { if (address(_tokenCompliance) != address(0)) { _tokenCompliance.unbindToken(address(this)); } - _tokenCompliance = IModularCompliance(_compliance); + _tokenCompliance = IERC3643Compliance(_compliance); _tokenCompliance.bindToken(address(this)); emit ComplianceAdded(_compliance); } @@ -670,10 +670,11 @@ contract Token is IToken, AgentRoleUpgradeable, TokenStorage, IERC165 { */ function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) { return - interfaceId == type(IERC20).interfaceId || // 0x36372b07 - interfaceId == type(IToken).interfaceId || // 0x4768ee17 - interfaceId == type(IERC173).interfaceId || // 0x7f5828d0 - interfaceId == type(IERC165).interfaceId; // 0x01ffc9a7 + interfaceId == type(IERC20).interfaceId || + interfaceId == type(IToken).interfaceId || + interfaceId == type(IERC173).interfaceId || + interfaceId == type(IERC165).interfaceId || + interfaceId == type(IERC3643).interfaceId; } /** diff --git a/contracts/token/TokenStorage.sol b/contracts/token/TokenStorage.sol index 1ce25063..19c03573 100644 --- a/contracts/token/TokenStorage.sol +++ b/contracts/token/TokenStorage.sol @@ -62,8 +62,8 @@ */ pragma solidity 0.8.26; -import "../compliance/modular/IModularCompliance.sol"; -import "../registry/interface/IIdentityRegistry.sol"; +import "../ERC-3643/IERC3643Compliance.sol"; +import "../ERC-3643/IERC3643IdentityRegistry.sol"; import "./TokenStructs.sol"; contract TokenStorage { @@ -86,10 +86,10 @@ contract TokenStorage { bool internal _tokenPaused = false; /// @dev Identity Registry contract used by the onchain validator system - IIdentityRegistry internal _tokenIdentityRegistry; + IERC3643IdentityRegistry internal _tokenIdentityRegistry; /// @dev Compliance contract linked to the onchain validator system - IModularCompliance internal _tokenCompliance; + IERC3643Compliance internal _tokenCompliance; mapping(address => TokenRoles) internal _agentsRestrictions; diff --git a/contracts/utils/InterfaceIdCalculator.sol b/contracts/utils/InterfaceIdCalculator.sol index 40be8b12..f9fa649e 100644 --- a/contracts/utils/InterfaceIdCalculator.sol +++ b/contracts/utils/InterfaceIdCalculator.sol @@ -72,6 +72,12 @@ import "../proxy/authority/IIAFactory.sol"; import "../factory/ITREXGateway.sol"; import "../DVA/IDVATransferManager.sol"; import "../compliance/modular/modules/IModule.sol"; +import "../compliance/modular/IModularCompliance.sol"; +import "../registry/interface/IClaimTopicsRegistry.sol"; +import "../registry/interface/IIdentityRegistry.sol"; +import "../registry/interface/IIdentityRegistryStorage.sol"; +import "../registry/interface/ITrustedIssuersRegistry.sol"; + contract InterfaceIdCalculator { /** @@ -82,9 +88,17 @@ contract InterfaceIdCalculator { return type(IERC20).interfaceId; } + /** + * @dev Returns the interface ID for the IERC3643 interface. + * IERC3643 interface ID is 0xb97d944c + */ + function getIERC3643InterfaceId() external pure returns (bytes4) { + return type(IERC3643).interfaceId; + } + /** * @dev Returns the interface ID for the IToken interface. - * IToken interface ID is 0x4768ee17 + * IToken interface ID is 0x5c0cda7e */ function getITokenInterfaceId() external pure returns (bytes4) { return type(IToken).interfaceId; @@ -107,35 +121,43 @@ contract InterfaceIdCalculator { } /** - * @dev Returns the interface ID for the IClaimTopicsRegistry interface. - * IClaimTopicsRegistry interface ID is 0x10928b13 + * @dev Returns the interface ID for the IERC3643ClaimTopicsRegistry interface. + * IERC3643ClaimTopicsRegistry interface ID is 0x10928b13 */ - function getIClaimTopicsRegistryInterfaceId() external pure returns (bytes4) { - return type(IClaimTopicsRegistry).interfaceId; + function getIERC3643ClaimTopicsRegistryInterfaceId() external pure returns (bytes4) { + return type(IERC3643ClaimTopicsRegistry).interfaceId; } /** * @dev Returns the interface ID for the IIdentityRegistry interface. - * IIdentityRegistry interface ID is 0x8ff89f73 + * IIdentityRegistry interface ID is 0xacb7b4db */ function getIIdentityRegistryInterfaceId() external pure returns (bytes4) { return type(IIdentityRegistry).interfaceId; } /** - * @dev Returns the interface ID for the IIdentityRegistryStorage interface. - * IIdentityRegistryStorage interface ID is 0x57defe0d + * @dev Returns the interface ID for the IERC3643IdentityRegistry interface. + * IERC3643IdentityRegistry interface ID is 0x8ff89f73 */ - function getIIdentityRegistryStorageInterfaceId() external pure returns (bytes4) { - return type(IIdentityRegistryStorage).interfaceId; + function getIERC3643IdentityRegistryInterfaceId() external pure returns (bytes4) { + return type(IERC3643IdentityRegistry).interfaceId; } /** - * @dev Returns the interface ID for the ITrustedIssuersRegistry interface. - * ITrustedIssuersRegistry interface ID is 0xb0f773b8 + * @dev Returns the interface ID for the IERC3643IdentityRegistryStorage interface. + * IERC3643IdentityRegistryStorage interface ID is 0x57defe0d */ - function getITrustedIssuersRegistryInterfaceId() external pure returns (bytes4) { - return type(ITrustedIssuersRegistry).interfaceId; + function getIERC3643IdentityRegistryStorageInterfaceId() external pure returns (bytes4) { + return type(IERC3643IdentityRegistryStorage).interfaceId; + } + + /** + * @dev Returns the interface ID for the IERC3643TrustedIssuersRegistry interface. + * IERC3643TrustedIssuersRegistry interface ID is 0xb0f773b8 + */ + function getIERC3643TrustedIssuersRegistryInterfaceId() external pure returns (bytes4) { + return type(IERC3643TrustedIssuersRegistry).interfaceId; } /** @@ -172,12 +194,20 @@ contract InterfaceIdCalculator { /** * @dev Returns the interface ID for the IModularCompliance interface. - * IModularCompliance interface ID is 0xef7cedae + * IModularCompliance interface ID is 0x4d6b83d6 */ function getIModularComplianceInterfaceId() external pure returns (bytes4) { return type(IModularCompliance).interfaceId; } + /** + * @dev Returns the interface ID for the IERC3643Compliance interface. + * IERC3643Compliance interface ID is 0x3144991c + */ + function getIERC3643ComplianceInterfaceId() external pure returns (bytes4) { + return type(IERC3643Compliance).interfaceId; + } + /** * @dev Returns the interface ID for the IModule interface. * IModule interface ID is 0xb795d01e diff --git a/test/compliance.test.ts b/test/compliance.test.ts index 9d7adf96..40f21014 100644 --- a/test/compliance.test.ts +++ b/test/compliance.test.ts @@ -525,6 +525,17 @@ describe('ModularCompliance', () => { expect(await compliance.supportsInterface(iModularComplianceInterfaceId)).to.equal(true); }); + it('should correctly identify the IERC3643Compliance interface ID', async () => { + const { + suite: { compliance }, + } = await loadFixture(deploySuiteWithModularCompliancesFixture); + const InterfaceIdCalculator = await ethers.getContractFactory('InterfaceIdCalculator'); + const interfaceIdCalculator = await InterfaceIdCalculator.deploy(); + + const iComplianceInterfaceId = await interfaceIdCalculator.getIERC3643ComplianceInterfaceId(); + expect(await compliance.supportsInterface(iComplianceInterfaceId)).to.equal(true); + }); + it('should correctly identify the IERC173 interface ID', async () => { const { suite: { compliance }, diff --git a/test/dvd.test.ts b/test/dvd.test.ts index 88935bbf..a27754c5 100644 --- a/test/dvd.test.ts +++ b/test/dvd.test.ts @@ -551,12 +551,10 @@ describe('DVDTransferManager', () => { describe('When token does not have an Identity Registry (probably not a ERC3643 token', () => { it('should return false', async () => { const { - suite: { transferManager, token }, + suite: { transferManager }, } = await loadFixture(deployFullSuiteWithTransferManager); - await token.setIdentityRegistry(ethers.ZeroAddress); - - expect(await transferManager.isTREX(token.target)).to.be.false; + expect(await transferManager.isTREX(transferManager.target)).to.be.false; }); }); }); diff --git a/test/registries/claim-topics-registry.test.ts b/test/registries/claim-topics-registry.test.ts index 6b18d539..e1e279df 100644 --- a/test/registries/claim-topics-registry.test.ts +++ b/test/registries/claim-topics-registry.test.ts @@ -101,14 +101,14 @@ describe('ClaimTopicsRegistry', () => { expect(await claimTopicsRegistry.supportsInterface(unsupportedInterfaceId)).to.equal(false); }); - it('should correctly identify the IClaimTopicsRegistry interface ID', async () => { + it('should correctly identify the IERC3643ClaimTopicsRegistry interface ID', async () => { const { suite: { claimTopicsRegistry }, } = await loadFixture(deployFullSuiteFixture); const InterfaceIdCalculator = await ethers.getContractFactory('InterfaceIdCalculator'); const interfaceIdCalculator = await InterfaceIdCalculator.deploy(); - const iClaimTopicsRegistryInterfaceId = await interfaceIdCalculator.getIClaimTopicsRegistryInterfaceId(); + const iClaimTopicsRegistryInterfaceId = await interfaceIdCalculator.getIERC3643ClaimTopicsRegistryInterfaceId(); expect(await claimTopicsRegistry.supportsInterface(iClaimTopicsRegistryInterfaceId)).to.equal(true); }); diff --git a/test/registries/identity-registry-storage.test.ts b/test/registries/identity-registry-storage.test.ts index cf85851b..01ab4638 100644 --- a/test/registries/identity-registry-storage.test.ts +++ b/test/registries/identity-registry-storage.test.ts @@ -370,14 +370,14 @@ describe('IdentityRegistryStorage', () => { expect(await identityRegistryStorage.supportsInterface(unsupportedInterfaceId)).to.equal(false); }); - it('should correctly identify the IIdentityRegistryStorage interface ID', async () => { + it('should correctly identify the IERC3643IdentityRegistryStorage interface ID', async () => { const { suite: { identityRegistryStorage }, } = await loadFixture(deployFullSuiteFixture); const InterfaceIdCalculator = await ethers.getContractFactory('InterfaceIdCalculator'); const interfaceIdCalculator = await InterfaceIdCalculator.deploy(); - const iIdentityRegistryStorageInterfaceId = await interfaceIdCalculator.getIIdentityRegistryStorageInterfaceId(); + const iIdentityRegistryStorageInterfaceId = await interfaceIdCalculator.getIERC3643IdentityRegistryStorageInterfaceId(); expect(await identityRegistryStorage.supportsInterface(iIdentityRegistryStorageInterfaceId)).to.equal(true); }); diff --git a/test/registries/identity-registry.test.ts b/test/registries/identity-registry.test.ts index 4a8ea631..ba0c7023 100644 --- a/test/registries/identity-registry.test.ts +++ b/test/registries/identity-registry.test.ts @@ -417,6 +417,17 @@ describe('IdentityRegistry', () => { expect(await identityRegistry.supportsInterface(iIdentityRegistryInterfaceId)).to.equal(true); }); + it('should correctly identify the IERC3643IdentityRegistry interface ID', async () => { + const { + suite: { identityRegistry }, + } = await loadFixture(deployFullSuiteFixture); + const InterfaceIdCalculator = await ethers.getContractFactory('InterfaceIdCalculator'); + const interfaceIdCalculator = await InterfaceIdCalculator.deploy(); + + const iIdentityRegistryInterfaceId = await interfaceIdCalculator.getIERC3643IdentityRegistryInterfaceId(); + expect(await identityRegistry.supportsInterface(iIdentityRegistryInterfaceId)).to.equal(true); + }); + it('should correctly identify the IERC173 interface ID', async () => { const { suite: { identityRegistry }, diff --git a/test/registries/trusted-issuers-registry.test.ts b/test/registries/trusted-issuers-registry.test.ts index c3ee8bdc..e7ba0392 100644 --- a/test/registries/trusted-issuers-registry.test.ts +++ b/test/registries/trusted-issuers-registry.test.ts @@ -290,14 +290,14 @@ describe('TrustedIssuersRegistry', () => { expect(await trustedIssuersRegistry.supportsInterface(unsupportedInterfaceId)).to.equal(false); }); - it('should correctly identify the ITrustedIssuersRegistry interface ID', async () => { + it('should correctly identify the IERC3643TrustedIssuersRegistry interface ID', async () => { const { suite: { trustedIssuersRegistry }, } = await loadFixture(deployFullSuiteFixture); const InterfaceIdCalculator = await ethers.getContractFactory('InterfaceIdCalculator'); const interfaceIdCalculator = await InterfaceIdCalculator.deploy(); - const iTrustedIssuersRegistryInterfaceId = await interfaceIdCalculator.getITrustedIssuersRegistryInterfaceId(); + const iTrustedIssuersRegistryInterfaceId = await interfaceIdCalculator.getIERC3643TrustedIssuersRegistryInterfaceId(); expect(await trustedIssuersRegistry.supportsInterface(iTrustedIssuersRegistryInterfaceId)).to.equal(true); }); diff --git a/test/token/token-information.test.ts b/test/token/token-information.test.ts index 0668b018..0de50cf7 100644 --- a/test/token/token-information.test.ts +++ b/test/token/token-information.test.ts @@ -366,6 +366,17 @@ describe('Token - Information', () => { expect(await token.supportsInterface(iTokenInterfaceId)).to.equal(true); }); + it('should correctly identify the IERC3643 interface ID', async () => { + const { + suite: { token }, + } = await loadFixture(deployFullSuiteFixture); + const InterfaceIdCalculator = await ethers.getContractFactory('InterfaceIdCalculator'); + const interfaceIdCalculator = await InterfaceIdCalculator.deploy(); + + const iErc3643InterfaceId = await interfaceIdCalculator.getIERC3643InterfaceId(); + expect(await token.supportsInterface(iErc3643InterfaceId)).to.equal(true); + }); + it('should correctly identify the IERC173 interface ID', async () => { const { suite: { token },