Skip to content

Commit

Permalink
Implement upgradeable proxies to compliance modules
Browse files Browse the repository at this point in the history
  • Loading branch information
aliarbak committed Mar 8, 2024
1 parent 0fa344b commit b9a1e75
Show file tree
Hide file tree
Showing 25 changed files with 1,600 additions and 237 deletions.
Binary file added .DS_Store
Binary file not shown.
147 changes: 147 additions & 0 deletions contracts/compliance/modular/modules/AbstractModuleUpgradeable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// SPDX-License-Identifier: GPL-3.0
//
// :+#####%%%%%%%%%%%%%%+
// .-*@@@%+.:+%@@@@@%%#***%@@%=
// :=*%@@@#=. :#@@% *@@@%=
// .-+*%@%*-.:+%@@@@@@+. -*+: .=#. :%@@@%-
// :=*@@@@%%@@@@@@@@@%@@@- .=#@@@%@%= =@@@@#.
// -=+#%@@%#*=:. :%@@@@%. -*@@#*@@@@@@@#=:- *@@@@+
// =@@%=:. :=: *@@@@@%#- =%*%@@@@#+-. =+ :%@@@%-
// -@@%. .+@@@ =+=-. @@#- +@@@%- =@@@@%:
// :@@@. .+@@#%: : .=*=-::.-%@@@+*@@= +@@@@#.
// %@@: +@%%* =%@@@@@@@@@@@#. .*@%- +@@@@*.
// #@@= .+@@@@%:=*@@@@@- :%@%: .*@@@@+
// *@@* +@@@#-@@%-:%@@* +@@#. :%@@@@-
// -@@% .:-=++*##%%%@@@@@@@@@@@@*. :@+.@@@%: .#@@+ =@@@@#:
// .@@@*-+*#%%%@@@@@@@@@@@@@@@@%%#**@@%@@@. *@=*@@# :#@%= .#@@@@#-
// -%@@@@@@@@@@@@@@@*+==-:-@@@= *@# .#@*-=*@@@@%= -%@@@* =@@@@@%-
// -+%@@@#. %@%%= -@@:+@: -@@* *@@*-:: -%@@%=. .*@@@@@#
// *@@@* +@* *@@##@@- #@*@@+ -@@= . :+@@@#: .-+@@@%+-
// +@@@%*@@:..=@@@@* .@@@* .#@#. .=+- .=%@@@*. :+#@@@@*=:
// =@@@@%@@@@@@@@@@@@@@@@@@@@@@%- :+#*. :*@@@%=. .=#@@@@%+:
// .%@@= ..... .=#@@+. .#@@@*: -*%@@@@%+.
// +@@#+===---:::... .=%@@*- +@@@+. -*@@@@@%+.
// -@@@@@@@@@@@@@@@@@@@@@@%@@@@= -@@@+ -#@@@@@#=.
// ..:::---===+++***###%%%@@@#- .#@@+ -*@@@@@#=.
// @@@@@@+. +@@*. .+@@@@@%=.
// -@@@@@= =@@%: -#@@@@%+.
// +@@@@@. =@@@= .+@@@@@*:
// #@@@@#:%@@#. :*@@@@#-
// @@@@@%@@@= :#@@@@+.
// :@@@@@@@#.:#@@@%-
// +@@@@@@-.*@@@*:
// #@@@@#.=@@@+.
// @@@@+-%@%=
// :@@@#%@%=
// +@@@@%-
// :#%%=
//
/**
* NOTICE
*
* The T-REX software is licensed under a proprietary license or the GPL v.3.
* If you choose to receive it under the GPL v.3 license, the following applies:
* T-REX is a suite of smart contracts implementing the ERC-3643 standard and
* developed by Tokeny to manage and transfer financial assets on EVM blockchains
*
* Copyright (C) 2023, Tokeny sàrl.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

pragma solidity 0.8.17;

import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "./IModule.sol";

abstract contract AbstractModuleUpgradeable is IModule, Initializable, OwnableUpgradeable, UUPSUpgradeable {
struct AbstractModuleStorage {
/// compliance contract binding status
mapping(address => bool) complianceBound;
}

// keccak256(abi.encode(uint256(keccak256("ERC3643.storage.AbstractModule")) - 1)) & ~bytes32(uint256(0xff))

This comment has been minimized.

Copy link
@Joachim-Lebrun

Joachim-Lebrun Mar 11, 2024

Collaborator

probably better to keep the storage slot from ERC-1822 as explorers detect it and display interfaces accordingly. For proxies of the T-REX suite we changed the storage slot to not display like an ERC-1822, as we are using a beacon proxy pattern. but here it is a direct link between proxies and implementation so we should do it

bytes32 private constant _ABSTRACT_MODULE_STORAGE_LOCATION =
0xf6cc97de1266c180cd39f3b311632644143ce7873d2927755382ad4b39e8ae00;

/**
* @dev Throws if `_compliance` is not a bound compliance contract address.
*/
modifier onlyBoundCompliance(address _compliance) {
AbstractModuleStorage storage s = _getAbstractModuleStorage();
require(s.complianceBound[_compliance], "compliance not bound");
_;
}

/**
* @dev Throws if called from an address that is not a bound compliance contract.
*/
modifier onlyComplianceCall() {
AbstractModuleStorage storage s = _getAbstractModuleStorage();
require(s.complianceBound[msg.sender], "only bound compliance can call");
_;
}

/**
* @dev See {IModule-bindCompliance}.
*/
function bindCompliance(address _compliance) external override {
AbstractModuleStorage storage s = _getAbstractModuleStorage();
require(_compliance != address(0), "invalid argument - zero address");
require(!s.complianceBound[_compliance], "compliance already bound");
require(msg.sender == _compliance, "only compliance contract can call");
s.complianceBound[_compliance] = true;
emit ComplianceBound(_compliance);
}

/**
* @dev See {IModule-unbindCompliance}.
*/
function unbindCompliance(address _compliance) external onlyComplianceCall override {
AbstractModuleStorage storage s = _getAbstractModuleStorage();
require(_compliance != address(0), "invalid argument - zero address");
require(msg.sender == _compliance, "only compliance contract can call");
s.complianceBound[_compliance] = false;
emit ComplianceUnbound(_compliance);
}

/**
* @dev See {IModule-isComplianceBound}.
*/
function isComplianceBound(address _compliance) external view override returns (bool) {
AbstractModuleStorage storage s = _getAbstractModuleStorage();
return s.complianceBound[_compliance];
}

// solhint-disable-next-line func-name-mixedcase
function __AbstractModule_init() internal onlyInitializing {
__Ownable_init();
__AbstractModule_init_unchained();
}

// solhint-disable-next-line no-empty-blocks, func-name-mixedcase
function __AbstractModule_init_unchained() internal onlyInitializing { }

// solhint-disable-next-line no-empty-blocks
function _authorizeUpgrade(address /*newImplementation*/) internal override virtual onlyOwner { }

function _getAbstractModuleStorage() private pure returns (AbstractModuleStorage storage s) {
// solhint-disable-next-line no-inline-assembly
assembly {
s.slot := _ABSTRACT_MODULE_STORAGE_LOCATION
}
}
}
12 changes: 10 additions & 2 deletions contracts/compliance/modular/modules/ConditionalTransferModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,13 @@ pragma solidity 0.8.17;

import "../IModularCompliance.sol";
import "../../../token/IToken.sol";
import "./AbstractModule.sol";
import "../../../roles/AgentRole.sol";
import "./AbstractModuleUpgradeable.sol";

/**
* this module allows to require the pre-validation of a transfer before allowing it to be executed
*/
contract ConditionalTransferModule is AbstractModule {
contract ConditionalTransferModule is AbstractModuleUpgradeable {
/// Mapping between transfer details and their approval status (amount of transfers approved) per compliance
mapping(address => mapping(bytes32 => uint)) private _transfersApproved;

Expand All @@ -94,6 +94,14 @@ contract ConditionalTransferModule is AbstractModule {
*/
event ApprovalRemoved(address _from, address _to, uint _amount, address _token);

/**
* @dev initializes the contract and sets the initial state.
* @notice This function should only be called once during the contract deployment.
*/
function initialize() external initializer {
__AbstractModule_init();
}

/**
* @dev Approves transfers in batch
* once a transfer is approved, the sender is allowed to execute it
Expand Down
12 changes: 10 additions & 2 deletions contracts/compliance/modular/modules/CountryAllowModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ pragma solidity 0.8.17;

import "../IModularCompliance.sol";
import "../../../token/IToken.sol";
import "./AbstractModule.sol";
import "./AbstractModuleUpgradeable.sol";

contract CountryAllowModule is AbstractModule {
contract CountryAllowModule is AbstractModuleUpgradeable {
/// Mapping between country and their allowance status per compliance contract
mapping(address => mapping(uint16 => bool)) private _allowedCountries;

Expand All @@ -92,6 +92,14 @@ contract CountryAllowModule is AbstractModule {

/// functions

/**
* @dev initializes the contract and sets the initial state.
* @notice This function should only be called once during the contract deployment.
*/
function initialize() external initializer {
__AbstractModule_init();
}

/**
* @dev Adds country allowance in batch.
* Identities from those countries will be allowed to manipulate Tokens linked to this Compliance.
Expand Down
12 changes: 10 additions & 2 deletions contracts/compliance/modular/modules/CountryRestrictModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ pragma solidity 0.8.17;

import "../IModularCompliance.sol";
import "../../../token/IToken.sol";
import "./AbstractModule.sol";
import "./AbstractModuleUpgradeable.sol";

contract CountryRestrictModule is AbstractModule {
contract CountryRestrictModule is AbstractModuleUpgradeable {
/// Mapping between country and their restriction status per compliance contract
mapping(address => mapping(uint16 => bool)) private _restrictedCountries;

Expand All @@ -84,6 +84,14 @@ contract CountryRestrictModule is AbstractModule {
*/
event RemovedRestrictedCountry(address indexed _compliance, uint16 _country);

/**
* @dev initializes the contract and sets the initial state.
* @notice This function should only be called once during the contract deployment.
*/
function initialize() external initializer {
__AbstractModule_init();
}

/**
* @dev Adds country restriction.
* Identities from those countries will be forbidden to manipulate Tokens linked to this Compliance.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,9 @@ pragma solidity 0.8.17;
import "../IModularCompliance.sol";
import "../../../token/IToken.sol";
import "../../../roles/AgentRole.sol";
import "./AbstractModule.sol";
import "./AbstractModuleUpgradeable.sol";

import "@openzeppelin/contracts/access/Ownable.sol";

contract ExchangeMonthlyLimitsModule is AbstractModule, Ownable {
contract ExchangeMonthlyLimitsModule is AbstractModuleUpgradeable {
/// Struct of transfer Counters
struct ExchangeTransferCounter {
uint256 monthlyCount;
Expand Down Expand Up @@ -112,6 +110,14 @@ contract ExchangeMonthlyLimitsModule is AbstractModule, Ownable {

error ONCHAINIDNotTaggedAsExchange(address _exchangeID);

/**
* @dev initializes the contract and sets the initial state.
* @notice This function should only be called once during the contract deployment.
*/
function initialize() external initializer {
__AbstractModule_init();
}

/**
* @dev Set the limit of tokens allowed to be transferred monthly.
* @param _exchangeID ONCHAINID of the exchange
Expand Down
12 changes: 10 additions & 2 deletions contracts/compliance/modular/modules/MaxBalanceModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ pragma solidity 0.8.17;
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "../IModularCompliance.sol";
import "../../../token/IToken.sol";
import "./AbstractModule.sol";
import "./AbstractModuleUpgradeable.sol";

contract MaxBalanceModule is AbstractModule {
contract MaxBalanceModule is AbstractModuleUpgradeable {

/// state variables

Expand Down Expand Up @@ -103,6 +103,14 @@ contract MaxBalanceModule is AbstractModule {

/// functions

/**
* @dev initializes the contract and sets the initial state.
* @notice This function should only be called once during the contract deployment.
*/
function initialize() external initializer {
__AbstractModule_init();
}

/**
* @dev sets max balance limit for a bound compliance contract
* @param _max max amount of tokens owned by an individual
Expand Down
12 changes: 10 additions & 2 deletions contracts/compliance/modular/modules/SupplyLimitModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ pragma solidity ^0.8.17;

import "../IModularCompliance.sol";
import "../../../token/IToken.sol";
import "./AbstractModule.sol";
import "./AbstractModuleUpgradeable.sol";

contract SupplyLimitModule is AbstractModule {
contract SupplyLimitModule is AbstractModuleUpgradeable {
/// supply limits array
mapping(address => uint256) private _supplyLimits;

Expand All @@ -77,6 +77,14 @@ contract SupplyLimitModule is AbstractModule {
*/
event SupplyLimitSet(address _compliance, uint256 _limit);

/**
* @dev initializes the contract and sets the initial state.
* @notice This function should only be called once during the contract deployment.
*/
function initialize() external initializer {
__AbstractModule_init();
}

/**
* @dev sets supply limit.
* Supply limit has to be smaller or equal to the actual supply.
Expand Down
14 changes: 10 additions & 4 deletions contracts/compliance/modular/modules/TimeExchangeLimitsModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,9 @@ pragma solidity 0.8.17;
import "../IModularCompliance.sol";
import "../../../token/IToken.sol";
import "../../../roles/AgentRole.sol";
import "./AbstractModule.sol";
import "./AbstractModuleUpgradeable.sol";

import "@openzeppelin/contracts/access/Ownable.sol";

contract TimeExchangeLimitsModule is AbstractModule, Ownable {
contract TimeExchangeLimitsModule is AbstractModuleUpgradeable {
/// Struct of transfer Counters
struct ExchangeTransferCounter {
uint256 value;
Expand Down Expand Up @@ -129,6 +127,14 @@ contract TimeExchangeLimitsModule is AbstractModule, Ownable {

error LimitsArraySizeExceeded(address compliance, uint arraySize);

/**
* @dev initializes the contract and sets the initial state.
* @notice This function should only be called once during the contract deployment.
*/
function initialize() external initializer {
__AbstractModule_init();
}

/**
* @dev Sets the limit of tokens allowed to be transferred to the given exchangeID in a given period of time
* @param _exchangeID ONCHAINID of the exchange
Expand Down
12 changes: 10 additions & 2 deletions contracts/compliance/modular/modules/TimeTransfersLimitsModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ pragma solidity 0.8.17;
import "../IModularCompliance.sol";
import "../../../token/IToken.sol";
import "../../../roles/AgentRole.sol";
import "./AbstractModule.sol";
import "./AbstractModuleUpgradeable.sol";

contract TimeTransfersLimitsModule is AbstractModule {
contract TimeTransfersLimitsModule is AbstractModuleUpgradeable {
/// Struct of transfer Counters
struct TransferCounter {
uint256 value;
Expand Down Expand Up @@ -104,6 +104,14 @@ contract TimeTransfersLimitsModule is AbstractModule {

error LimitsArraySizeExceeded(address compliance, uint arraySize);

/**
* @dev initializes the contract and sets the initial state.
* @notice This function should only be called once during the contract deployment.
*/
function initialize() external initializer {
__AbstractModule_init();
}

/**
* @dev Sets the limit of tokens allowed to be transferred in the given time frame.
* @param _limit The limit time and value
Expand Down
Loading

0 comments on commit b9a1e75

Please sign in to comment.