Skip to content

Commit

Permalink
TREX-161 : Add erc 165 (#219)
Browse files Browse the repository at this point in the history
- import ERC-165
- Implement ERC-165 on T-REX
- Full Test coverage of ERC-165
- CHANGELOG
  • Loading branch information
Joachim-Lebrun authored Aug 19, 2024
1 parent 0395ed8 commit e2cb9c7
Show file tree
Hide file tree
Showing 39 changed files with 1,239 additions and 63 deletions.
1 change: 1 addition & 0 deletions .solcover.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ module.exports = {
"_testContracts",
"roles/permissioning/owner/",
"roles/permissioning/agent/",
"utils",
],
};
18 changes: 17 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,29 @@ All notable changes to this project will be documented in this file.
- Events: `DefaultAllowance`, `DefaultAllowanceDisabled`, `DefaultAllowanceEnabled`.
- Enhanced the `allowance` function to return `type(uint256).max` for addresses with default allowance enabled, unless the user has opted out.

- **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.

## [4.1.5]

### Update
- DvA Transfer Manager contract proxified
- The DvA manager contract freezes the tokens to be transferred instead of being a vault (so it must be a token agent)
- Only the token owner (rather than agents) can call setApprovalCriteria, as it is part of the main token settings.
-

## [4.1.4]

### Added
Expand Down
14 changes: 13 additions & 1 deletion contracts/DVA/DVATransferManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,10 @@ import "./IDVATransferManager.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import "../roles/IERC173.sol";

contract DVATransferManager is IDVATransferManager, Initializable, OwnableUpgradeable, UUPSUpgradeable {
contract DVATransferManager is IDVATransferManager, Initializable, OwnableUpgradeable, UUPSUpgradeable, IERC165 {

// Mapping for token approval criteria
mapping(address => ApprovalCriteria) private _approvalCriteria;
Expand Down Expand Up @@ -301,6 +303,16 @@ contract DVATransferManager is IDVATransferManager, Initializable, OwnableUpgrad
return "DVATransferManager";
}

/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) {
return
interfaceId == type(IDVATransferManager).interfaceId ||
interfaceId == type(IERC173).interfaceId ||
interfaceId == type(IERC165).interfaceId;
}

/**
* @dev See {IDVATransferManager-calculateTransferID}
*/
Expand Down
14 changes: 13 additions & 1 deletion contracts/compliance/modular/ModularCompliance.sol
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ import "./MCStorage.sol";
import "./modules/IModule.sol";
import "../../errors/ComplianceErrors.sol";
import "../../errors/InvalidArgumentErrors.sol";
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import "../../roles/IERC173.sol";

/// errors

Expand All @@ -89,7 +91,7 @@ error OnlyOwnerOrTokenCanCall();
error TokenNotBound();


contract ModularCompliance is IModularCompliance, OwnableUpgradeable, MCStorage {
contract ModularCompliance is IModularCompliance, OwnableUpgradeable, MCStorage, IERC165 {

/// modifiers

Expand Down Expand Up @@ -272,6 +274,16 @@ contract ModularCompliance is IModularCompliance, OwnableUpgradeable, MCStorage
return true;
}

/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) {
return
interfaceId == type(IModularCompliance).interfaceId ||
interfaceId == type(IERC173).interfaceId ||
interfaceId == type(IERC165).interfaceId;
}

/// @dev Extracts the Solidity ABI selector for the specified interaction.
/// @param callData Interaction data.
/// @return result The 4 byte function selector of the call encoded in
Expand Down
12 changes: 11 additions & 1 deletion contracts/compliance/modular/modules/AbstractModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,9 @@ pragma solidity 0.8.26;
import "./IModule.sol";
import "../../../errors/InvalidArgumentErrors.sol";
import "../../../errors/ComplianceErrors.sol";
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";

abstract contract AbstractModule is IModule {
abstract contract AbstractModule is IModule, IERC165 {

/// compliance contract binding status
mapping(address => bool) private _complianceBound;
Expand Down Expand Up @@ -115,4 +116,13 @@ abstract contract AbstractModule is IModule {
return _complianceBound[_compliance];
}

/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) {
return
interfaceId == type(IModule).interfaceId ||
interfaceId == type(IERC165).interfaceId;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,11 @@ import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "./IModule.sol";
import "../../../errors/InvalidArgumentErrors.sol";
import "../../../errors/ComplianceErrors.sol";
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import "../../../roles/IERC173.sol";


abstract contract AbstractModuleUpgradeable is IModule, Initializable, OwnableUpgradeable, UUPSUpgradeable {
abstract contract AbstractModuleUpgradeable is IModule, Initializable, OwnableUpgradeable, UUPSUpgradeable, IERC165 {
struct AbstractModuleStorage {
/// compliance contract binding status
mapping(address => bool) complianceBound;
Expand Down Expand Up @@ -129,6 +131,16 @@ abstract contract AbstractModuleUpgradeable is IModule, Initializable, OwnableUp
return s.complianceBound[_compliance];
}

/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) {
return
interfaceId == type(IModule).interfaceId ||
interfaceId == type(IERC173).interfaceId ||
interfaceId == type(IERC165).interfaceId;
}

// solhint-disable-next-line func-name-mixedcase
function __AbstractModule_init() internal onlyInitializing {
__Ownable_init();
Expand Down
14 changes: 13 additions & 1 deletion contracts/factory/TREXGateway.sol
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../errors/InvalidArgumentErrors.sol";
import "../errors/RoleErrors.sol";
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import "../roles/IERC173.sol";

/// Errors

Expand Down Expand Up @@ -101,7 +103,7 @@ error DiscountOutOfRange();
error BatchMaxLengthExceeded(uint16 lengthLimit);


contract TREXGateway is ITREXGateway, AgentRole {
contract TREXGateway is ITREXGateway, AgentRole, IERC165 {

/// address of the TREX Factory that is managed by the Gateway
address private _factory;
Expand Down Expand Up @@ -345,4 +347,14 @@ contract TREXGateway is ITREXGateway, AgentRole {
function calculateFee(address deployer) public override view returns(uint256) {
return _deploymentFee.fee - ((_feeDiscount[deployer] * _deploymentFee.fee) / 10000);
}

/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) {
return
interfaceId == type(ITREXGateway).interfaceId ||
interfaceId == type(IERC173).interfaceId ||
interfaceId == type(IERC165).interfaceId;
}
}
11 changes: 10 additions & 1 deletion contracts/proxy/authority/IAFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ pragma solidity 0.8.26;

import "./TREXImplementationAuthority.sol";

contract IAFactory is IIAFactory {
contract IAFactory is IIAFactory, IERC165 {

/// variables

Expand Down Expand Up @@ -106,4 +106,13 @@ contract IAFactory is IIAFactory {
function deployedByFactory(address _ia) external view override returns (bool) {
return _deployedByFactory[_ia];
}

/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) {
return
interfaceId == type(IIAFactory).interfaceId ||
interfaceId == type(IERC165).interfaceId;
}
}
14 changes: 13 additions & 1 deletion contracts/proxy/authority/TREXImplementationAuthority.sol
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ import "../../factory/ITREXFactory.sol";
import "./IIAFactory.sol";
import "../../errors/CommonErrors.sol";
import "../../errors/InvalidArgumentErrors.sol";
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import "../../roles/IERC173.sol";

/// Errors

Expand Down Expand Up @@ -101,7 +103,7 @@ error VersionAlreadyInUse();
error VersionOfNewIAMustBeTheSameAsCurrentIA();


contract TREXImplementationAuthority is ITREXImplementationAuthority, Ownable {
contract TREXImplementationAuthority is ITREXImplementationAuthority, Ownable, IERC165 {

/// variables

Expand Down Expand Up @@ -347,6 +349,16 @@ contract TREXImplementationAuthority is ITREXImplementationAuthority, Ownable {
return ITREXFactory(_trexFactory).getImplementationAuthority();
}

/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) {
return
interfaceId == type(ITREXImplementationAuthority).interfaceId ||
interfaceId == type(IERC173).interfaceId ||
interfaceId == type(IERC165).interfaceId;
}

/**
* @dev casting function Version => bytes to allow compare values easier
*/
Expand Down
14 changes: 13 additions & 1 deletion contracts/registry/implementation/ClaimTopicsRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ pragma solidity 0.8.26;
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "../storage/CTRStorage.sol";
import "../interface/IClaimTopicsRegistry.sol";
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import "../../roles/IERC173.sol";

/// Errors

Expand All @@ -76,7 +78,7 @@ error MaxTopicsReached(uint256 _max);
error ClaimTopicAlreadyExists();


contract ClaimTopicsRegistry is IClaimTopicsRegistry, OwnableUpgradeable, CTRStorage {
contract ClaimTopicsRegistry is IClaimTopicsRegistry, OwnableUpgradeable, CTRStorage, IERC165 {

function init() external initializer {
__Ownable_init();
Expand Down Expand Up @@ -116,4 +118,14 @@ contract ClaimTopicsRegistry is IClaimTopicsRegistry, OwnableUpgradeable, CTRSto
function getClaimTopics() external view override returns (uint256[] memory) {
return _claimTopics;
}

/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) {
return
interfaceId == type(IClaimTopicsRegistry).interfaceId ||
interfaceId == type(IERC173).interfaceId ||
interfaceId == type(IERC165).interfaceId;
}
}
14 changes: 13 additions & 1 deletion contracts/registry/implementation/IdentityRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,11 @@ import "../../roles/AgentRoleUpgradeable.sol";
import "../interface/IIdentityRegistryStorage.sol";
import "../storage/IRStorage.sol";
import "../../errors/InvalidArgumentErrors.sol";
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import "../../roles/IERC173.sol";


contract IdentityRegistry is IIdentityRegistry, AgentRoleUpgradeable, IRStorage {
contract IdentityRegistry is IIdentityRegistry, AgentRoleUpgradeable, IRStorage, IERC165 {

/**
* @dev the constructor initiates the Identity Registry smart contract
Expand Down Expand Up @@ -279,4 +281,14 @@ contract IdentityRegistry is IIdentityRegistry, AgentRoleUpgradeable, IRStorage
function identity(address _userAddress) public view override returns (IIdentity) {
return _tokenIdentityStorage.storedIdentity(_userAddress);
}

/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) {
return
interfaceId == type(IIdentityRegistry).interfaceId ||
interfaceId == type(IERC173).interfaceId ||
interfaceId == type(IERC165).interfaceId;
}
}
14 changes: 13 additions & 1 deletion contracts/registry/implementation/IdentityRegistryStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ import "../../roles/AgentRoleUpgradeable.sol";
import "../interface/IIdentityRegistryStorage.sol";
import "../storage/IRSStorage.sol";
import "../../errors/InvalidArgumentErrors.sol";
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import "../../roles/IERC173.sol";

/// Errors

Expand All @@ -85,7 +87,7 @@ error IdentityRegistryNotStored();
error MaxIRByIRSReached(uint256 _max);


contract IdentityRegistryStorage is IIdentityRegistryStorage, AgentRoleUpgradeable, IRSStorage {
contract IdentityRegistryStorage is IIdentityRegistryStorage, AgentRoleUpgradeable, IRSStorage, IERC165 {

function init() external initializer {
__Ownable_init();
Expand Down Expand Up @@ -193,4 +195,14 @@ contract IdentityRegistryStorage is IIdentityRegistryStorage, AgentRoleUpgradeab
function storedInvestorCountry(address _userAddress) external view override returns (uint16) {
return _identities[_userAddress].investorCountry;
}

/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) {
return
interfaceId == type(IIdentityRegistryStorage).interfaceId ||
interfaceId == type(IERC173).interfaceId ||
interfaceId == type(IERC165).interfaceId;
}
}
14 changes: 13 additions & 1 deletion contracts/registry/implementation/TrustedIssuersRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "../interface/ITrustedIssuersRegistry.sol";
import "../storage/TIRStorage.sol";
import "../../errors/InvalidArgumentErrors.sol";
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import "../../roles/IERC173.sol";

/// Errors

Expand Down Expand Up @@ -95,7 +97,7 @@ error TrustedIssuerAlreadyExists();
error TrustedIssuerDoesNotExist();


contract TrustedIssuersRegistry is ITrustedIssuersRegistry, OwnableUpgradeable, TIRStorage {
contract TrustedIssuersRegistry is ITrustedIssuersRegistry, OwnableUpgradeable, TIRStorage, IERC165 {

/// Functions

Expand Down Expand Up @@ -226,4 +228,14 @@ contract TrustedIssuersRegistry is ITrustedIssuersRegistry, OwnableUpgradeable,
}
return false;
}

/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) {
return
interfaceId == type(ITrustedIssuersRegistry).interfaceId ||
interfaceId == type(IERC173).interfaceId ||
interfaceId == type(IERC165).interfaceId;
}
}
4 changes: 2 additions & 2 deletions contracts/roles/AgentRole.sol
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,11 @@ import "../errors/RoleErrors.sol";

/// Events

/// @dev This event is emmited when an agent is added.
/// @dev This event is emitted when an agent is added.
/// @param _agent Address of agent contract
event AgentAdded(address indexed _agent);

/// @dev This event is emmited when an agent is removed.
/// @dev This event is emitted when an agent is removed.
/// @param _agent Address of agent contract
event AgentRemoved(address indexed _agent);

Expand Down
Loading

0 comments on commit e2cb9c7

Please # to comment.