diff --git a/CHANGELOG.md b/CHANGELOG.md
index 55abf03d..952710ba 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,15 +2,36 @@
Please follow
Last version: [v2.0.2](https://github.com/CMTA/RuleEngine/releases/tag/v2.0.2)(unaudited) |
| CMTAT 2.3.0 | [RuleEngine v1.0.2](https://github.com/CMTA/RuleEngine/releases/tag/v1.0.2) |
| CMTAT 2.0 (unaudited) | [RuleEngine 1.0](https://github.com/CMTA/RuleEngine/releases/tag/1.0) (unaudited) |
| CMTAT 1.0 | No ruleEngine available |
@@ -162,21 +155,135 @@ A possible rule is a whitelist rule where only the address inside the whitelist
Since the version 2.4.0, the requirement to use a RuleEngine are the following:
-The `RuleEngine` has to import an implement the interface `IRuleEngine` which declares the function `operateOnTransfer`.
+> The `RuleEngine` has to import an implement the interface `IRuleEngine` which declares the function `operateOnTransfer`.
This interface can be found in [./contracts/interfaces/engine/IRuleEngine.sol](./contracts/interfaces/engine/IRuleEngine.sol).
Before each transfer, the CMTAT calls the function `operateOnTransfer` which is the entrypoint for the RuleEngine.
-### AuthorizationEngine
+#### AuthorizationEngine
+
+> Warning: this engine may be deleted in the future
The `AuthorizationEngine` is an external contract to add supplementary check on the functions `grantRole` and `revokeRole`from the CMTAT.
This contract is managed in the `AuthorizationModule`.
-The `AuthorizationEngine` has to import an implement the interface `IAuthorizationEngine` which declares the functions `operateOnGrantRole` and `operateOnRevokeRole`
+The `AuthorizationEngine` has to import an implement the interface [IAuthorizationEngine.sol](./contracts/interfaces/engine/IAuthorizationEngine.sol) which declares the functions `operateOnGrantRole` and `operateOnRevokeRole`
+
+Currently, there is only a prototype available: [CMTA/AuthorizationEngine](https://github.com/CMTA/AuthorizationEngine)
+
+#### DebtEngine
+
+This engine replaces the modules Debt and Credit included since CMTAT version.
-This interface can be found in [./contracts/interfaces/engine/IAuthorizationEngine.sol](./contracts/interfaces/engine/IAuthorizationEngine.sol).
+CMTAT only implements two functions , available in the interface [IDebtEngine](./contracts/interfaces/engine/IDebtEngine.sol) to get information from the debtEngine.
+
+```solidity
+interface IDebtEngine is IDebtGlobal {
+ function debt() external view returns(IDebtGlobal.DebtBase memory);
+ function creditEvents() external view returns(IDebtGlobal.CreditEvents memory);
+}
+```
+
+Use an external contract provides two advantages:
+
+- Reduce code size of CMTAT, which is near of the maximal size limit
+- Allow to manage this information for several different tokens (CMTAT or not).
+
+Here is the list of the different version available for each CMTAT version.
+
+| Name | DebtEngine |
+| ------------------------ | ------------------------------------------------------------ |
+| CMTAT v2.5.0 (unaudited) | [DebtEngine v0.2.0](https://github.com/CMTA/DebtEngine/releases/tag/v0.2.0) (unaudited) |
+
+#### DocumentEngine (IERC-1643)
+
+The `DocumentEngine` is an external contract to support [*ERC-1643*](https://github.com/ethereum/EIPs/issues/1643) inside CMTAT, a standard proposition to manage document on-chain. This standard is notably used by [ERC-1400](https://github.com/ethereum/eips/issues/1411) from Polymath.
+
+This EIP defines a document with three attributes:
+
+- A short name (represented as a `bytes32`)
+- A generic URI (represented as a `string`) that could point to a website or other document portal.
+- The hash of the document contents associated with it on-chain.
+
+CMTAT only implements two functions from this standard, available in the interface [IERC1643](./contracts/interfaces/engined/draft-IERC1643.sol) to get the documents from the documentEngine.
+
+```solidity
+interface IERC1643 {
+function getDocument(bytes32 _name) external view returns (string memory , bytes32, uint256);
+function getAllDocuments() external view returns (bytes32[] memory);
+}
+```
+
+The `DocumentEngine` has to import an implement this interface. To manage the documents, the engine is completely free on how to do it.
+
+Use an external contract provides two advantages:
+
+- Reduce code size of CMTAT, which is near of the maximal size limit
+- Allow to manage documents for several different tokens (CMTAT or not).
+
+Here is the list of the different version available for each CMTAT version.
+
+| Name | DocumentEngine |
+| ------------------------ | ------------------------------------------------------------ |
+| CMTAT v2.5.0 (unaudited) | [DocumentEngine v0.3.0](https://github.com/CMTA/DocumentEngine/releases/tag/v0.3.0) (unaudited) |
+
+## Deployment model
+
+| Model | Contract |
+| --------------------------- | ---------------------------------------------------- |
+| Standalone | [CMTAT_STANDALONE](./contracts/CMTAT_STANDALONE.sol) |
+| Transparent or Beacon Proxy | [CMTAT_PROXY](./contracts/CMTAT_PROXY.sol) |
+| UUPS Proxy | [CMTAT_PROXY_UUPS](./contracts/CMTAT_PROXY_UUPS.sol) |
+
+
+
+### Standalone
+
+To deploy CMTAT without a proxy, in standalone mode, you need to use the contract version `CMTAT_STANDALONE`.
+
+### With a proxy
+
+The CMTAT supports deployment via a proxy contract. Furthermore, using a proxy permits to upgrade the contract, using a standard proxy upgrade pattern.
+
+- The implementation contract to use with a TransparentProxy is the `CMTAT_PROXY`.
+- The implementation contract to use with a UUPSProxy is the `CMTAT_PROXY_UUPS`.
+
+Please see the OpenZeppelin [upgradeable contracts documentation](https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable) for more information about the proxy requirements applied to the contract.
+
+Please see the OpenZeppelin [Upgrades plugins](https://docs.openzeppelin.com/upgrades-plugins/1.x/) for more information about plugin upgrades in general.
+
+Note that deployment via a proxy is not mandatory, but is recommended by CMTA.
+
+### Factory
+
+Factory contracts are available to deploy the CMTAT with a beacon proxy, a transparent proxy or an UUPS proxy.
+
+- [CMTAT_BEACON_FACTORY.sol](./contracts/deployment/CMTAT_BEACON_FACTORY.sol)
+
+- [CMTAT_TRANSPARENT_FACTORY.sol](./contracts/deployment/CMTAT_TP_FACTORY.sol)
+- [CMTAT_UUPS_FACTORY.sol](./contracts/deployment/CMTAT_UUPS_FACTORY.sol)
+
+#### Beacon Proxy Factory
+
+The factory will use the same beacon for each beacon proxy. This beacon provides the address of the implementation contract, a CMTAT_PROXY contract. If you upgrade the beacon to point to a new implementation, it will change the implementation contract for all beacon proxy.
+
+![factory-Beacon Factory.drawio](./doc/schema/drawio/factory-BeaconFactory.drawio.png)
+
+#### Transparent Proxy Factory
+
+The factory will use the same implementation for each transparent proxy deployed. Each transparent proxy has its owned proxy admin, deployed inside the constructor of the transparent proxy. Each transparent proxy can upgrade their implementation to a new one independently and without impact on other proxies.
+
+![factory-Transparent Factory.drawio](./doc/schema/drawio/factory-TransparentFactory.drawio.png)
+
+#### UUPS ProxyFactory
+
+The factory will use the same implementation for each UUPS proxy deployed. Each UUPS proxy can upgrade their implementation to a new one independently and without impact on other proxies.
+
+Contrary to the Transparent Proxy, the logic to upgrade the proxy is situated in the implementation and not in the proxy.
+
+This is the reason whey there is a specific CMTAT contract which includes this logic to use: [CMTAT_PROXY_UUPS.sol](./contracts/CMTAT_PROXY_UUPS.sol)
## Security
@@ -224,6 +331,7 @@ You will find the report produced by [Slither](https://github.com/crytic/slither
| Last version | [slither-report.md](doc/audits/tools/slither-report.md) |
| v2.3.0 | [v2.3.0-slither-report.md](doc/audits/tools/v2.3.0-slither-report.md) |
| v2.3.1 | [v2.3.1-slither-report.md](doc/audits/tools/v2.3.1-slither-report.md) |
+| v2.4.0 | [v2.4.0-slither-report.md](doc/audits/tools/v2.4.0-slither-report.md) |
### Test
@@ -252,15 +360,19 @@ CMTA providers further documentation describing the CMTAT framework in a platfor
- [CMTA Token (CMTAT)](https://cmta.ch/standards/cmta-token-cmtat)
- [Standard for the tokenization of shares of Swiss corporations using the distributed ledger technology](https://cmta.ch/standards/standard-for-the-tokenization-of-shares-of-swiss-corporations-using-the-distributed-ledger-technology)
-## Further reading
+### Further reading
- [CMTA - A comparison of different security token standards](https://cmta.ch/news-articles/a-comparison-of-different-security-token-standards)
- [Taurus - Security Token Standards: A Closer Look at CMTAT](https://www.taurushq.com/blog/security-token-standards-a-closer-look-at-cmtat/)
- [Taurus - Equity Tokenization: How to Pay Dividend On-Chain Using CMTAT](https://www.taurushq.com/blog/equity-tokenization-how-to-pay-dividend-on-chain-using-cmtat/)
+- [Taurus - Token Transfer Management: How to Apply Restrictions with CMTAT and ERC-1404](https://www.taurushq.com/blog/token-transfer-management-how-to-apply-restrictions-with-cmtat-and-erc-1404/)
+- [Taurus - Addressing the Privacy and Compliance Challenge in Public Blockchain Token Transactions](https://www.taurushq.com/blog/enhancing-token-transaction-privacy-on-public-blockchains-while-ensuring-compliance/)
## Others implementations
Two versions are available for the blockchain [Tezos](https://tezos.com)
- [CMTAT FA2](https://github.com/CMTA/CMTAT-Tezos-FA2) Official version written in SmartPy
- [@ligo/cmtat](https://github.com/ligolang/CMTAT-Ligo/) Unofficial version written in Ligo
+ - See also [Tokenization of securities on Tezos by Frank Hillard](https://medium.com/@frank.hillard_62931/tokenization-of-securities-on-tezos-2e3c3e90fc5a)
+
## Contract size
diff --git a/contracts/CMTAT_PROXY.sol b/contracts/CMTAT_PROXY.sol
index 62963847..a65debe8 100644
--- a/contracts/CMTAT_PROXY.sol
+++ b/contracts/CMTAT_PROXY.sol
@@ -4,6 +4,10 @@ pragma solidity ^0.8.20;
import "./modules/CMTAT_BASE.sol";
+
+/**
+* @title CMTAT version for a proxy deployment (Transparent or Beacon proxy)
+*/
contract CMTAT_PROXY is CMTAT_BASE {
/**
* @notice Contract version for the deployment with a proxy
@@ -16,6 +20,4 @@ contract CMTAT_PROXY is CMTAT_BASE {
// Disable the possibility to initialize the implementation
_disableInitializers();
}
-
- uint256[50] private __gap;
}
diff --git a/contracts/CMTAT_PROXY_UUPS.sol b/contracts/CMTAT_PROXY_UUPS.sol
new file mode 100644
index 00000000..2114b285
--- /dev/null
+++ b/contracts/CMTAT_PROXY_UUPS.sol
@@ -0,0 +1,54 @@
+//SPDX-License-Identifier: MPL-2.0
+
+pragma solidity ^0.8.20;
+import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
+import "./modules/CMTAT_BASE.sol";
+
+
+/**
+* @title CMTAT version for a proxy deployment with UUPS proxy
+*/
+contract CMTAT_PROXY_UUPS is CMTAT_BASE, UUPSUpgradeable {
+ bytes32 public constant PROXY_UPGRADE_ROLE = keccak256("PROXY_UPGRADE_ROLE");
+ /**
+ * @notice Contract version for the deployment with a proxy
+ * @param forwarderIrrevocable address of the forwarder, required for the gasless support
+ */
+ /// @custom:oz-upgrades-unsafe-allow constructor
+ constructor(
+ address forwarderIrrevocable
+ ) MetaTxModule(forwarderIrrevocable) {
+ // Disable the possibility to initialize the implementation
+ _disableInitializers();
+ }
+
+ /*//////////////////////////////////////////////////////////////
+ PUBLIC/EXTERNAL FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+
+ /**
+ * @notice
+ * initialize the proxy contract
+ * The calls to this function will revert if the contract was deployed without a proxy
+ * @param admin address of the admin of contract (Access Control)
+ * @param ERC20Attributes_ ERC20 name, symbol and decimals
+ * @param baseModuleAttributes_ tokenId, terms, information
+ * @param engines_ external contract
+ */
+ function initialize( address admin,
+ ICMTATConstructor.ERC20Attributes memory ERC20Attributes_,
+ ICMTATConstructor.BaseModuleAttributes memory baseModuleAttributes_,
+ ICMTATConstructor.Engine memory engines_ ) public override initializer {
+ CMTAT_BASE.initialize( admin,
+ ERC20Attributes_,
+ baseModuleAttributes_,
+ engines_);
+ __UUPSUpgradeable_init_unchained();
+ }
+
+
+ /*//////////////////////////////////////////////////////////////
+ INTERNAL/PRIVATE FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+ function _authorizeUpgrade(address) internal override onlyRole(PROXY_UPGRADE_ROLE) {}
+}
diff --git a/contracts/CMTAT_STANDALONE.sol b/contracts/CMTAT_STANDALONE.sol
index dfe10c6d..e56e1dfa 100644
--- a/contracts/CMTAT_STANDALONE.sol
+++ b/contracts/CMTAT_STANDALONE.sol
@@ -4,50 +4,34 @@ pragma solidity ^0.8.20;
import "./modules/CMTAT_BASE.sol";
+
+/**
+* @title CMTAT version for a standalone deployment (without proxy)
+*/
contract CMTAT_STANDALONE is CMTAT_BASE {
/**
* @notice Contract version for standalone deployment
* @param forwarderIrrevocable address of the forwarder, required for the gasless support
* @param admin address of the admin of contract (Access Control)
- * @param authorizationEngineIrrevocable
- * @param nameIrrevocable name of the token
- * @param symbolIrrevocable name of the symbol
- * @param decimalsIrrevocable number of decimals used to get its user representation, should be 0 to be compliant with the CMTAT specifications.
- * @param tokenId_ name of the tokenId
- * @param terms_ terms associated with the token
- * @param ruleEngine_ address of the ruleEngine to apply rules to transfers
- * @param information_ additional information to describe the token
- * @param flag_ add information under the form of bit(0, 1)
+ * @param ERC20Attributes_ ERC20 name, symbol and decimals
+ * @param baseModuleAttributes_ tokenId, terms, information
+ * @param engines_ external contract
*/
/// @custom:oz-upgrades-unsafe-allow constructor
constructor(
address forwarderIrrevocable,
address admin,
- IAuthorizationEngine authorizationEngineIrrevocable,
- string memory nameIrrevocable,
- string memory symbolIrrevocable,
- uint8 decimalsIrrevocable,
- string memory tokenId_,
- string memory terms_,
- IRuleEngine ruleEngine_,
- string memory information_,
- uint256 flag_
+ ICMTATConstructor.ERC20Attributes memory ERC20Attributes_,
+ ICMTATConstructor.BaseModuleAttributes memory baseModuleAttributes_,
+ ICMTATConstructor.Engine memory engines_
) MetaTxModule(forwarderIrrevocable) {
// Initialize the contract to avoid front-running
// Warning : do not initialize the proxy
initialize(
admin,
- authorizationEngineIrrevocable,
- nameIrrevocable,
- symbolIrrevocable,
- decimalsIrrevocable,
- tokenId_,
- terms_,
- ruleEngine_,
- information_,
- flag_
+ ERC20Attributes_,
+ baseModuleAttributes_,
+ engines_
);
}
-
- // No storage gap because the contract is deployed in standalone mode
}
diff --git a/contracts/deployment/CMTAT_BEACON_FACTORY.sol b/contracts/deployment/CMTAT_BEACON_FACTORY.sol
index c8c60d13..947c45b9 100644
--- a/contracts/deployment/CMTAT_BEACON_FACTORY.sol
+++ b/contracts/deployment/CMTAT_BEACON_FACTORY.sol
@@ -2,37 +2,25 @@
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol";
-
+import '@openzeppelin/contracts/utils/Create2.sol';
import '@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol';
import "../CMTAT_PROXY.sol";
-import "../modules/CMTAT_BASE.sol";
-import "../libraries/FactoryErrors.sol";
-import '@openzeppelin/contracts/access/AccessControl.sol';
+import "./libraries/CMTATFactoryRoot.sol";
+
/**
* @notice Factory to deploy beacon proxy
*
*/
-contract CMTAT_BEACON_FACTORY is AccessControl {
- // Private
- mapping(uint256 => address) private cmtats;
- uint256 private cmtatCounterId;
+contract CMTAT_BEACON_FACTORY is AccessControl, CMTATFactoryRoot {
// public
- /// @dev Role to deploy CMTAT
- bytes32 public constant CMTAT_DEPLOYER_ROLE = keccak256("CMTAT_DEPLOYER_ROLE");
UpgradeableBeacon public immutable beacon;
- address[] public cmtatsList;
- event CMTAT(address indexed CMTAT, uint256 id);
-
/**
* @param implementation_ contract implementation
* @param factoryAdmin admin
* @param beaconOwner owner
*/
- constructor(address implementation_, address factoryAdmin, address beaconOwner) {
- if(factoryAdmin == address(0)){
- revert FactoryErrors.CMTAT_Factory_AddressZeroNotAllowedForFactoryAdmin();
- }
+ constructor(address implementation_, address factoryAdmin, address beaconOwner, bool useCustomSalt_)CMTATFactoryRoot(factoryAdmin, useCustomSalt_) {
if(beaconOwner == address(0)){
revert FactoryErrors.CMTAT_Factory_AddressZeroNotAllowedForBeaconOwner();
}
@@ -40,56 +28,41 @@ contract CMTAT_BEACON_FACTORY is AccessControl {
revert FactoryErrors.CMTAT_Factory_AddressZeroNotAllowedForLogicContract();
}
beacon = new UpgradeableBeacon(implementation_, beaconOwner);
- _grantRole(DEFAULT_ADMIN_ROLE, factoryAdmin);
- _grantRole(CMTAT_DEPLOYER_ROLE, factoryAdmin);
}
+ /*//////////////////////////////////////////////////////////////
+ PUBLIC/EXTERNAL FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
/**
* @notice deploy CMTAT with a beacon proxy
*
*/
function deployCMTAT(
+ bytes32 deploymentSaltInput,
// CMTAT function initialize
- address admin,
- IAuthorizationEngine authorizationEngineIrrevocable,
- string memory nameIrrevocable,
- string memory symbolIrrevocable,
- uint8 decimalsIrrevocable,
- string memory tokenId_,
- string memory terms_,
- IRuleEngine ruleEngine_,
- string memory information_,
- uint256 flag_
+ CMTAT_ARGUMENT calldata cmtatArgument
) public onlyRole(CMTAT_DEPLOYER_ROLE) returns(BeaconProxy cmtat) {
- cmtat = new BeaconProxy(
- address(beacon),
- abi.encodeWithSelector(
- CMTAT_PROXY(address(0)).initialize.selector,
- admin,
- authorizationEngineIrrevocable,
- nameIrrevocable,
- symbolIrrevocable,
- decimalsIrrevocable,
- tokenId_,
- terms_,
- ruleEngine_,
- information_,
- flag_
- )
- );
- cmtats[cmtatCounterId] = address(cmtat);
- emit CMTAT(address(cmtat), cmtatCounterId);
- cmtatCounterId++;
- cmtatsList.push(address(cmtat));
+ bytes32 deploymentSalt = _checkAndDetermineDeploymentSalt(deploymentSaltInput);
+ bytes memory bytecode = _getBytecode(
+ // CMTAT function initialize
+ cmtatArgument);
+ cmtat = _deployBytecode(bytecode, deploymentSalt);
return cmtat;
}
/**
- * @notice get CMTAT proxy address
- *
+ * @param deploymentSalt salt for the deployment
+ * @param cmtatArgument argument for the function initialize
+ * @notice get the proxy address depending on a particular salt
*/
- function getAddress(uint256 cmtatID_) external view returns (address) {
- return cmtats[cmtatID_];
+ function computedProxyAddress(
+ bytes32 deploymentSalt,
+ // CMTAT function initialize
+ CMTAT_ARGUMENT calldata cmtatArgument) public view returns (address) {
+ bytes memory bytecode = _getBytecode(
+ // CMTAT function initialize
+ cmtatArgument);
+ return Create2.computeAddress(deploymentSalt, keccak256(bytecode), address(this) );
}
/**
@@ -99,4 +72,38 @@ contract CMTAT_BEACON_FACTORY is AccessControl {
function implementation() public view returns (address) {
return beacon.implementation();
}
+
+ /*//////////////////////////////////////////////////////////////
+ INTERNAL FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+
+ /**
+ * @notice Deploy CMTAT and push the created CMTAT in the list
+ */
+ function _deployBytecode(bytes memory bytecode, bytes32 deploymentSalt) internal returns (BeaconProxy cmtat) {
+ address cmtatAddress = Create2.deploy(0, deploymentSalt, bytecode);
+ cmtat = BeaconProxy(payable(cmtatAddress));
+ cmtats[cmtatCounterId] = address(cmtat);
+ emit CMTAT(address(cmtat), cmtatCounterId);
+ ++cmtatCounterId;
+ cmtatsList.push(address(cmtat));
+ return cmtat;
+ }
+
+
+ /**
+ * @notice return the smart contract bytecode
+ */
+ function _getBytecode(
+ // CMTAT function initialize
+ CMTAT_ARGUMENT calldata cmtatArgument) internal view returns(bytes memory bytecode) {
+ bytes memory _implementation = abi.encodeWithSelector(
+ CMTAT_PROXY(address(0)).initialize.selector,
+ cmtatArgument.CMTATAdmin,
+ cmtatArgument.ERC20Attributes,
+ cmtatArgument.baseModuleAttributes,
+ cmtatArgument.engines
+ );
+ bytecode = abi.encodePacked(type(BeaconProxy).creationCode, abi.encode(address(beacon), _implementation));
+ }
}
\ No newline at end of file
diff --git a/contracts/deployment/CMTAT_TP_FACTORY.sol b/contracts/deployment/CMTAT_TP_FACTORY.sol
index 785747c2..5a0c9129 100644
--- a/contracts/deployment/CMTAT_TP_FACTORY.sol
+++ b/contracts/deployment/CMTAT_TP_FACTORY.sol
@@ -3,84 +3,90 @@ pragma solidity ^0.8.20;
import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import "../CMTAT_PROXY.sol";
-import "../libraries/FactoryErrors.sol";
-import '@openzeppelin/contracts/access/AccessControl.sol';
+import "@openzeppelin/contracts/utils/Create2.sol";
+import "./libraries/CMTATFactoryInvariant.sol";
+import "./libraries/CMTATFactoryBase.sol";
+
+
/**
-* @notice Factory to deploy transparent proxy
+* @notice Factory to deploy CMTAT with a transparent proxy
*
*/
-contract CMTAT_TP_FACTORY is AccessControl {
- // Private
- mapping(uint256 => address) private cmtats;
- uint256 private cmtatID;
- event CMTAT(address indexed CMTAT, uint256 id);
- // Public
- /// @dev Role to deploy CMTAT
- bytes32 public constant CMTAT_DEPLOYER_ROLE = keccak256("CMTAT_DEPLOYER_ROLE");
- address public immutable logic;
- address[] public cmtatsList;
+contract CMTAT_TP_FACTORY is CMTATFactoryBase {
-
+ constructor(address logic_, address factoryAdmin, bool useCustomSalt_) CMTATFactoryBase(logic_, factoryAdmin,useCustomSalt_){}
- /**
- * @param logic_ contract implementation
- * @param factoryAdmin admin
+ /*//////////////////////////////////////////////////////////////
+ PUBLIC/EXTERNAL FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+ /**
+ * @notice deploy a transparent proxy with a proxy admin contract
*/
- constructor(address logic_, address factoryAdmin) {
- if(logic_ == address(0)){
- revert FactoryErrors.CMTAT_Factory_AddressZeroNotAllowedForLogicContract();
- }
- if(factoryAdmin == address(0)){
- revert FactoryErrors.CMTAT_Factory_AddressZeroNotAllowedForFactoryAdmin();
- }
- logic = logic_;
- _grantRole(DEFAULT_ADMIN_ROLE, factoryAdmin);
- _grantRole(CMTAT_DEPLOYER_ROLE, factoryAdmin);
- }
-
function deployCMTAT(
+ bytes32 deploymentSaltInput,
address proxyAdminOwner,
// CMTAT function initialize
- address admin,
- IAuthorizationEngine authorizationEngineIrrevocable,
- string memory nameIrrevocable,
- string memory symbolIrrevocable,
- uint8 decimalsIrrevocable,
- string memory tokenId_,
- string memory terms_,
- IRuleEngine ruleEngine_,
- string memory information_,
- uint256 flag_
+ CMTAT_ARGUMENT calldata cmtatArgument
) public onlyRole(CMTAT_DEPLOYER_ROLE) returns(TransparentUpgradeableProxy cmtat) {
- cmtat = new TransparentUpgradeableProxy(
- logic,
- proxyAdminOwner,
- abi.encodeWithSelector(
- CMTAT_PROXY(address(0)).initialize.selector,
- admin,
- authorizationEngineIrrevocable,
- nameIrrevocable,
- symbolIrrevocable,
- decimalsIrrevocable,
- tokenId_,
- terms_,
- ruleEngine_,
- information_,
- flag_
- )
- );
- cmtats[cmtatID] = address(cmtat);
- emit CMTAT(address(cmtat), cmtatID);
- cmtatID++;
- cmtatsList.push(address(cmtat));
+ bytes32 deploymentSalt = _checkAndDetermineDeploymentSalt(deploymentSaltInput);
+ bytes memory bytecode = _getBytecode(proxyAdminOwner,
+ // CMTAT function initialize
+ cmtatArgument);
+ cmtat = _deployBytecode(bytecode, deploymentSalt);
+
return cmtat;
}
/**
- * @notice get CMTAT proxy address
- *
+ * @param deploymentSalt salt for the deployment
+ * @param proxyAdminOwner admin of the proxy
+ * @param cmtatArgument argument for the function initialize
+ * @notice get the proxy address depending on a particular salt
*/
- function getAddress(uint256 cmtatID_) external view returns (address) {
- return cmtats[cmtatID_];
+ function computedProxyAddress(
+ bytes32 deploymentSalt,
+ address proxyAdminOwner,
+ // CMTAT function initialize
+ CMTAT_ARGUMENT calldata cmtatArgument) public view returns (address) {
+ bytes memory bytecode = _getBytecode(proxyAdminOwner,
+ // CMTAT function initialize
+ cmtatArgument);
+ return Create2.computeAddress(deploymentSalt, keccak256(bytecode), address(this) );
}
+
+
+ /*//////////////////////////////////////////////////////////////
+ INTERNAL FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+
+
+ /**
+ * @notice Deploy CMTAT and push the created CMTAT in the list
+ */
+ function _deployBytecode(bytes memory bytecode, bytes32 deploymentSalt) internal returns (TransparentUpgradeableProxy cmtat) {
+ address cmtatAddress = Create2.deploy(0, deploymentSalt, bytecode);
+ cmtat = TransparentUpgradeableProxy(payable(cmtatAddress));
+ cmtats[cmtatCounterId] = address(cmtat);
+ emit CMTAT(address(cmtat), cmtatCounterId);
+ ++cmtatCounterId;
+ cmtatsList.push(address(cmtat));
+ return cmtat;
+ }
+
+
+ /**
+ * @notice return the smart contract bytecode
+ */
+ function _getBytecode( address proxyAdminOwner,
+ // CMTAT function initialize
+ CMTAT_ARGUMENT calldata cmtatArgument) internal view returns(bytes memory bytecode) {
+ bytes memory implementation = abi.encodeWithSelector(
+ CMTAT_PROXY(address(0)).initialize.selector,
+ cmtatArgument.CMTATAdmin,
+ cmtatArgument.ERC20Attributes,
+ cmtatArgument.baseModuleAttributes,
+ cmtatArgument.engines
+ );
+ bytecode = abi.encodePacked(type(TransparentUpgradeableProxy).creationCode, abi.encode(logic, proxyAdminOwner, implementation));
+ }
}
\ No newline at end of file
diff --git a/contracts/deployment/CMTAT_UUPS_FACTORY.sol b/contracts/deployment/CMTAT_UUPS_FACTORY.sol
new file mode 100644
index 00000000..10642f5f
--- /dev/null
+++ b/contracts/deployment/CMTAT_UUPS_FACTORY.sol
@@ -0,0 +1,91 @@
+//SPDX-License-Identifier: MPL-2.0
+pragma solidity ^0.8.20;
+
+import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
+import "../CMTAT_PROXY_UUPS.sol";
+import "@openzeppelin/contracts/utils/Create2.sol";
+import "./libraries/CMTATFactoryInvariant.sol";
+import "./libraries/CMTATFactoryBase.sol";
+
+
+/**
+* @notice Factory to deploy CMTAT with a UUPS proxy
+*
+*/
+contract CMTAT_UUPS_FACTORY is CMTATFactoryBase {
+ /**
+ * @param logic_ contract implementation
+ * @param factoryAdmin admin
+ */
+ constructor(address logic_, address factoryAdmin, bool useCustomSalt_) CMTATFactoryBase(logic_, factoryAdmin,useCustomSalt_){}
+
+
+ /*//////////////////////////////////////////////////////////////
+ PUBLIC/EXTERNAL FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+ /**
+ * @notice deploy a transparent proxy with a proxy admin contract
+ */
+ function deployCMTAT(
+ bytes32 deploymentSaltInput,
+ // CMTAT function initialize
+ CMTAT_ARGUMENT calldata cmtatArgument
+ ) public onlyRole(CMTAT_DEPLOYER_ROLE) returns(ERC1967Proxy cmtat) {
+ bytes32 deploymentSalt = _checkAndDetermineDeploymentSalt(deploymentSaltInput);
+ bytes memory bytecode = _getBytecode(
+ // CMTAT function initialize
+ cmtatArgument);
+ cmtat = _deployBytecode(bytecode, deploymentSalt);
+
+ return cmtat;
+ }
+
+ /**
+ * @param deploymentSalt salt for the deployment
+ * @param cmtatArgument argument for the function initialize
+ * @notice get the proxy address depending on a particular salt
+ */
+ function computedProxyAddress(
+ bytes32 deploymentSalt,
+ // CMTAT function initialize
+ CMTAT_ARGUMENT calldata cmtatArgument) public view returns (address) {
+ bytes memory bytecode = _getBytecode(
+ // CMTAT function initialize
+ cmtatArgument);
+ return Create2.computeAddress(deploymentSalt, keccak256(bytecode), address(this) );
+ }
+
+ /*//////////////////////////////////////////////////////////////
+ INTERNAL FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+
+ /**
+ * @notice Deploy CMTAT and push the created CMTAT in the list
+ */
+ function _deployBytecode(bytes memory bytecode, bytes32 deploymentSalt) internal returns (ERC1967Proxy cmtat) {
+ address cmtatAddress = Create2.deploy(0, deploymentSalt, bytecode);
+ cmtat = ERC1967Proxy(payable(cmtatAddress));
+ cmtats[cmtatCounterId] = address(cmtat);
+ emit CMTAT(address(cmtat), cmtatCounterId);
+ ++cmtatCounterId;
+ cmtatsList.push(address(cmtat));
+ return cmtat;
+ }
+
+
+ /**
+ * @notice return the smart contract bytecode
+ */
+ function _getBytecode(
+ // CMTAT function initialize
+ CMTAT_ARGUMENT calldata cmtatArgument) internal view returns(bytes memory bytecode) {
+ bytes memory implementation = abi.encodeWithSelector(
+ CMTAT_PROXY_UUPS(address(0)).initialize.selector,
+ cmtatArgument.CMTATAdmin,
+ cmtatArgument.ERC20Attributes,
+ cmtatArgument.baseModuleAttributes,
+ cmtatArgument.engines
+ );
+ bytecode = abi.encodePacked(type(ERC1967Proxy).creationCode, abi.encode(logic, implementation));
+ }
+}
\ No newline at end of file
diff --git a/contracts/deployment/libraries/CMTATFactoryBase.sol b/contracts/deployment/libraries/CMTATFactoryBase.sol
new file mode 100644
index 00000000..8561c1ec
--- /dev/null
+++ b/contracts/deployment/libraries/CMTATFactoryBase.sol
@@ -0,0 +1,24 @@
+//SPDX-License-Identifier: MPL-2.0
+pragma solidity ^0.8.20;
+
+import "./CMTATFactoryRoot.sol";
+
+/**
+* @notice Code common to TP and UUPS Factory
+*
+*/
+abstract contract CMTATFactoryBase is CMTATFactoryRoot {
+ /* ============ State Variables ============ */
+ address public immutable logic;
+ /* ============ Constructor ============ */
+ /**
+ * @param logic_ contract implementation
+ * @param factoryAdmin admin
+ */
+ constructor(address logic_, address factoryAdmin, bool useCustomSalt_)CMTATFactoryRoot( factoryAdmin, useCustomSalt_) {
+ if(logic_ == address(0)){
+ revert FactoryErrors.CMTAT_Factory_AddressZeroNotAllowedForLogicContract();
+ }
+ logic = logic_;
+ }
+}
\ No newline at end of file
diff --git a/contracts/deployment/libraries/CMTATFactoryInvariant.sol b/contracts/deployment/libraries/CMTATFactoryInvariant.sol
new file mode 100644
index 00000000..69b53be3
--- /dev/null
+++ b/contracts/deployment/libraries/CMTATFactoryInvariant.sol
@@ -0,0 +1,24 @@
+//SPDX-License-Identifier: MPL-2.0
+pragma solidity ^0.8.20;
+
+
+import "../../interfaces/ICMTATConstructor.sol";
+
+/**
+* @notice List of Invariant (struct, constant, events)
+*
+*/
+abstract contract CMTATFactoryInvariant {
+ /* ============ Structs ============ */
+ struct CMTAT_ARGUMENT{
+ address CMTATAdmin;
+ ICMTATConstructor.ERC20Attributes ERC20Attributes;
+ ICMTATConstructor.BaseModuleAttributes baseModuleAttributes;
+ ICMTATConstructor.Engine engines;
+ }
+ /* ============ State Variables ============ */
+ /// @dev Role to deploy CMTAT
+ bytes32 public constant CMTAT_DEPLOYER_ROLE = keccak256("CMTAT_DEPLOYER_ROLE");
+ /* ============ Events ============ */
+ event CMTAT(address indexed CMTAT, uint256 id);
+}
\ No newline at end of file
diff --git a/contracts/deployment/libraries/CMTATFactoryRoot.sol b/contracts/deployment/libraries/CMTATFactoryRoot.sol
new file mode 100644
index 00000000..9afedc20
--- /dev/null
+++ b/contracts/deployment/libraries/CMTATFactoryRoot.sol
@@ -0,0 +1,70 @@
+//SPDX-License-Identifier: MPL-2.0
+pragma solidity ^0.8.20;
+
+import "../../libraries/FactoryErrors.sol";
+import '@openzeppelin/contracts/access/AccessControl.sol';
+import "./CMTATFactoryInvariant.sol";
+/**
+* @notice Code common to Beacon, TP and UUPS factory
+*
+*/
+abstract contract CMTATFactoryRoot is AccessControl, CMTATFactoryInvariant {
+ /* ============ State Variables ============ */
+ // Public
+ address[] public cmtatsList;
+ bool immutable public useCustomSalt;
+ uint256 public cmtatCounterId;
+ /// mapping
+ mapping(uint256 => address) internal cmtats;
+ mapping(bytes32 => bool) internal customSaltUsed;
+
+ /* ============ Constructor ============ */
+ /**
+ * @param factoryAdmin admin
+ */
+ constructor(address factoryAdmin, bool useCustomSalt_) {
+ if(factoryAdmin == address(0)){
+ revert FactoryErrors.CMTAT_Factory_AddressZeroNotAllowedForFactoryAdmin();
+ }
+ if(useCustomSalt_){
+ useCustomSalt = useCustomSalt_;
+ }
+ _grantRole(DEFAULT_ADMIN_ROLE, factoryAdmin);
+ _grantRole(CMTAT_DEPLOYER_ROLE, factoryAdmin);
+ }
+
+
+ /*//////////////////////////////////////////////////////////////
+ PUBLIC/EXTERNAL FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+
+ /**
+ * @notice get CMTAT proxy address
+ *
+ */
+ function CMTATProxyAddress(uint256 cmtatCounterId_) external view returns (address) {
+ return cmtats[cmtatCounterId_];
+ }
+
+ /*//////////////////////////////////////////////////////////////
+ INTERNAL FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+
+ /**
+ * @param deploymentSalt salt for deployment
+ * @dev
+ * if useCustomSalt is at false, the salt used is the current value of cmtatCounterId
+ */
+ function _checkAndDetermineDeploymentSalt(bytes32 deploymentSalt) internal returns(bytes32 saltBytes){
+ if(useCustomSalt){
+ if(customSaltUsed[deploymentSalt]){
+ revert FactoryErrors.CMTAT_Factory_SaltAlreadyUsed();
+ }else {
+ customSaltUsed[deploymentSalt] = true;
+ saltBytes = deploymentSalt;
+ }
+ }else{
+ saltBytes = bytes32(keccak256(abi.encodePacked(cmtatCounterId)));
+ }
+ }
+}
\ No newline at end of file
diff --git a/contracts/interfaces/ICMTATConstructor.sol b/contracts/interfaces/ICMTATConstructor.sol
new file mode 100644
index 00000000..e3ee7cef
--- /dev/null
+++ b/contracts/interfaces/ICMTATConstructor.sol
@@ -0,0 +1,36 @@
+//SPDX-License-Identifier: MPL-2.0
+pragma solidity ^0.8.20;
+import "./engine/IDebtEngine.sol";
+import "./engine/IRuleEngine.sol";
+import "./engine/IAuthorizationEngine.sol";
+import "./engine/draft-IERC1643.sol";
+
+
+
+/**
+* @notice interface to represent arguments used for CMTAT constructor / initialize
+*/
+interface ICMTATConstructor {
+ struct Engine {
+ IRuleEngine ruleEngine;
+ IDebtEngine debtEngine;
+ IAuthorizationEngine authorizationEngine;
+ IERC1643 documentEngine;
+ }
+ struct ERC20Attributes {
+ // name of the token,
+ string nameIrrevocable;
+ // name of the symbol
+ string symbolIrrevocable;
+ // number of decimals of the token, must be 0 to be compliant with Swiss law as per CMTAT specifications (non-zero decimal number may be needed for other use cases)
+ uint8 decimalsIrrevocable;
+ }
+ struct BaseModuleAttributes {
+ // name of the tokenId
+ string tokenId;
+ // terms associated with the token
+ string terms;
+ // additional information to describe the token
+ string information;
+ }
+}
diff --git a/contracts/interfaces/ICMTATSnapshot.sol b/contracts/interfaces/ICMTATSnapshot.sol
index 4cbd4d38..64129d70 100644
--- a/contracts/interfaces/ICMTATSnapshot.sol
+++ b/contracts/interfaces/ICMTATSnapshot.sol
@@ -3,7 +3,7 @@
pragma solidity ^0.8.20;
/**
-* @notice interface to represent a CMTAT with snapshot
+* @notice minimum interface to represent a CMTAT with snapshot
*/
interface ICMTATSnapshot {
/**
diff --git a/contracts/interfaces/engine/IAuthorizationEngine.sol b/contracts/interfaces/engine/IAuthorizationEngine.sol
index 000f4e0c..0e3f740b 100644
--- a/contracts/interfaces/engine/IAuthorizationEngine.sol
+++ b/contracts/interfaces/engine/IAuthorizationEngine.sol
@@ -2,6 +2,9 @@
pragma solidity ^0.8.20;
+/*
+* @dev minimum interface to define an AuthorizationEngine
+*/
interface IAuthorizationEngine {
/**
* @dev Returns true if the operation is authorized, and false otherwise.
diff --git a/contracts/interfaces/engine/IDebtEngine.sol b/contracts/interfaces/engine/IDebtEngine.sol
new file mode 100644
index 00000000..fb36ce07
--- /dev/null
+++ b/contracts/interfaces/engine/IDebtEngine.sol
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: MPL-2.0
+
+pragma solidity ^0.8.20;
+import "./IDebtGlobal.sol";
+
+/*
+* @dev minimum interface to define a DebtEngine
+*/
+interface IDebtEngine is IDebtGlobal {
+ /**
+ * @dev Returns debt information
+ */
+ function debt() external view returns(IDebtGlobal.DebtBase memory);
+ /**
+ * @dev Returns credit events
+ */
+ function creditEvents() external view returns(IDebtGlobal.CreditEvents memory);
+
+}
diff --git a/contracts/interfaces/IDebtGlobal.sol b/contracts/interfaces/engine/IDebtGlobal.sol
similarity index 100%
rename from contracts/interfaces/IDebtGlobal.sol
rename to contracts/interfaces/engine/IDebtGlobal.sol
diff --git a/contracts/interfaces/engine/IRuleEngine.sol b/contracts/interfaces/engine/IRuleEngine.sol
index bd2586a1..a0774a02 100644
--- a/contracts/interfaces/engine/IRuleEngine.sol
+++ b/contracts/interfaces/engine/IRuleEngine.sol
@@ -4,6 +4,9 @@ pragma solidity ^0.8.20;
import "../draft-IERC1404/draft-IERC1404Wrapper.sol";
+/*
+* @dev minimum interface to define a RuleEngine
+*/
interface IRuleEngine is IERC1404Wrapper {
/**
* @dev Returns true if the operation is a success, and false otherwise.
diff --git a/contracts/interfaces/engine/draft-IERC1643.sol b/contracts/interfaces/engine/draft-IERC1643.sol
new file mode 100644
index 00000000..c902df6d
--- /dev/null
+++ b/contracts/interfaces/engine/draft-IERC1643.sol
@@ -0,0 +1,11 @@
+//SPDX-License-Identifier: MPL-2.0
+
+pragma solidity ^0.8.20;
+
+/// @title IERC1643 Document Management
+/// (part of the ERC1400 Security Token Standards)
+interface IERC1643 {
+ // Document Management
+ function getDocument(bytes32 _name) external view returns (string memory , bytes32, uint256);
+ function getAllDocuments() external view returns (bytes32[] memory);
+}
\ No newline at end of file
diff --git a/contracts/libraries/Errors.sol b/contracts/libraries/Errors.sol
index 28840db9..d5beb510 100644
--- a/contracts/libraries/Errors.sol
+++ b/contracts/libraries/Errors.sol
@@ -2,6 +2,9 @@
pragma solidity ^0.8.20;
+/*
+* @dev CMTAT custom errors
+*/
library Errors {
// CMTAT
error CMTAT_InvalidTransfer(address from, address to, uint256 amount);
@@ -50,9 +53,6 @@ library Errors {
// DebtModule
error CMTAT_DebtModule_SameValue();
- // BaseModule
- error CMTAT_BaseModule_SameValue();
-
// ValidationModule
error CMTAT_ValidationModule_SameValue();
@@ -61,6 +61,9 @@ library Errors {
error CMTAT_AuthorizationModule_InvalidAuthorization();
error CMTAT_AuthorizationModule_AuthorizationEngineAlreadySet();
+ // DocumentModule
+ error CMTAT_DocumentModule_SameValue();
+
// PauseModule
error CMTAT_PauseModule_ContractIsDeactivated();
}
diff --git a/contracts/libraries/FactoryErrors.sol b/contracts/libraries/FactoryErrors.sol
index a64e226b..df964c51 100644
--- a/contracts/libraries/FactoryErrors.sol
+++ b/contracts/libraries/FactoryErrors.sol
@@ -2,8 +2,12 @@
pragma solidity ^0.8.20;
+/*
+* @dev Factory contract custom errors
+*/
library FactoryErrors {
error CMTAT_Factory_AddressZeroNotAllowedForFactoryAdmin();
error CMTAT_Factory_AddressZeroNotAllowedForBeaconOwner();
error CMTAT_Factory_AddressZeroNotAllowedForLogicContract();
+ error CMTAT_Factory_SaltAlreadyUsed();
}
diff --git a/contracts/mocks/AuthorizationEngineMock.sol b/contracts/mocks/AuthorizationEngineMock.sol
index fbe72d6f..2b858a16 100644
--- a/contracts/mocks/AuthorizationEngineMock.sol
+++ b/contracts/mocks/AuthorizationEngineMock.sol
@@ -4,6 +4,7 @@ pragma solidity ^0.8.20;
import "../interfaces/engine/IAuthorizationEngine.sol";
+
/*
* @title a mock for testing, not suitable for production
*/
diff --git a/contracts/mocks/DebtEngineMock.sol b/contracts/mocks/DebtEngineMock.sol
new file mode 100644
index 00000000..f4047dbf
--- /dev/null
+++ b/contracts/mocks/DebtEngineMock.sol
@@ -0,0 +1,32 @@
+
+// SPDX-License-Identifier: MPL-2.0
+pragma solidity ^0.8.20;
+import "../interfaces/engine/IDebtEngine.sol";
+interface IDebtEngineMock is IDebtEngine {
+ function setDebt(DebtBase calldata debt_) external;
+ function setCreditEvents(CreditEvents calldata creditEvents) external;
+}
+
+/*
+* @title a DebtEngine mock for testing, not suitable for production
+*/
+contract DebtEngineMock is IDebtEngineMock {
+ DebtBase private _debt;
+ CreditEvents private _creditEvents;
+
+ function debt() external view override returns (DebtBase memory) {
+ return _debt;
+ }
+
+ function creditEvents() external view override returns (CreditEvents memory) {
+ return _creditEvents;
+ }
+
+ function setDebt(DebtBase calldata debt_) external override {
+ _debt = debt_;
+ }
+
+ function setCreditEvents(CreditEvents calldata creditEvents_) external override {
+ _creditEvents = creditEvents_;
+ }
+}
\ No newline at end of file
diff --git a/contracts/mocks/DocumentEngineMock.sol b/contracts/mocks/DocumentEngineMock.sol
new file mode 100644
index 00000000..297ce5b8
--- /dev/null
+++ b/contracts/mocks/DocumentEngineMock.sol
@@ -0,0 +1,96 @@
+
+// SPDX-License-Identifier: MPL-2.0
+pragma solidity ^0.8.20;
+import "../interfaces/engine/draft-IERC1643.sol";
+interface IERC1643Whole is IERC1643{
+
+ // Document Management
+ function setDocument(bytes32 _name, string memory _uri, bytes32 _documentHash) external;
+ function removeDocument(bytes32 _name) external;
+
+ // Document Events
+ event DocumentRemoved(bytes32 indexed _name, string _uri, bytes32 _documentHash);
+ event DocumentUpdated(bytes32 indexed _name, string _uri, bytes32 _documentHash);
+
+}
+/*
+* @title a DocumentEngine mock for testing, not suitable for production
+*/
+contract DocumentEngineMock is IERC1643Whole {
+ struct Document {
+ string uri;
+ bytes32 documentHash;
+ uint256 lastModified;
+ }
+
+ mapping(bytes32 => Document) private documents;
+ bytes32[] private documentNames;
+
+ /// @dev Error thrown when a document does not exist
+ error DocumentDoesNotExist();
+
+ /// @notice Retrieves the document details by name
+ /// @param name_ The name of the document
+ /// @return uri The URI of the document
+ /// @return documentHash The hash of the document contents
+ /// @return lastModified The timestamp of the last modification
+ function getDocument(bytes32 name_)
+ external
+ view
+ override
+ returns (string memory uri, bytes32 documentHash, uint256 lastModified)
+ {
+ if (bytes(documents[name_].uri).length == 0) {
+ return("", 0x0, 0);
+ }
+
+ Document storage doc = documents[name_];
+ return (doc.uri, doc.documentHash, doc.lastModified);
+ }
+
+ /// @notice Sets or updates a document
+ /// @param name_ The name of the document
+ /// @param uri_ The URI of the document
+ /// @param documentHash_ The hash of the document contents
+ function setDocument(bytes32 name_, string memory uri_, bytes32 documentHash_) external override {
+ Document storage doc = documents[name_];
+ bool isUpdate = bytes(doc.uri).length != 0;
+
+ doc.uri = uri_;
+ doc.documentHash = documentHash_;
+ doc.lastModified = block.timestamp;
+
+ if (!isUpdate) {
+ documentNames.push(name_);
+ }
+
+ emit DocumentUpdated(name_, uri_, documentHash_);
+ }
+
+ /// @notice Removes a document
+ /// @param name_ The name of the document
+ function removeDocument(bytes32 name_) external override {
+ if (bytes(documents[name_].uri).length == 0) {
+ revert DocumentDoesNotExist();
+ }
+
+ Document memory doc = documents[name_];
+ delete documents[name_];
+
+ for (uint256 i = 0; i < documentNames.length; i++) {
+ if (documentNames[i] == name_) {
+ documentNames[i] = documentNames[documentNames.length - 1];
+ documentNames.pop();
+ break;
+ }
+ }
+
+ emit DocumentRemoved(name_, doc.uri, doc.documentHash);
+ }
+
+ /// @notice Retrieves all document names
+ /// @return An array of document names
+ function getAllDocuments() external view override returns (bytes32[] memory) {
+ return documentNames;
+ }
+}
\ No newline at end of file
diff --git a/contracts/mocks/MinimalForwarderMock.sol b/contracts/mocks/MinimalForwarderMock.sol
index 3dd609d6..727645b8 100644
--- a/contracts/mocks/MinimalForwarderMock.sol
+++ b/contracts/mocks/MinimalForwarderMock.sol
@@ -2,8 +2,12 @@
pragma solidity ^0.8.20;
-import "../../openzeppelin-contracts-upgradeable/contracts/metatx/ERC2771ForwarderUpgradeable.sol";
+import "@openzeppelin/contracts-upgradeable/metatx/ERC2771ForwarderUpgradeable.sol";
+
+/*
+* @title a MinimalForwarderMock for testing, not suitable for production
+*/
contract MinimalForwarderMock is ERC2771ForwarderUpgradeable {
function initialize(string memory name) public initializer {
__EIP712_init_unchained(name, "1");
diff --git a/contracts/mocks/RuleEngine/RuleEngineMock.sol b/contracts/mocks/RuleEngine/RuleEngineMock.sol
index 4dc0a065..37b45328 100644
--- a/contracts/mocks/RuleEngine/RuleEngineMock.sol
+++ b/contracts/mocks/RuleEngine/RuleEngineMock.sol
@@ -7,7 +7,7 @@ import "./interfaces/IRuleEngineMock.sol";
import "./RuleMock.sol";
/*
-* @title a mock for testing, not suitable for production
+* @title a RuleEngine mock for testing, not suitable for production
*/
contract RuleEngineMock is IRuleEngineMock {
IRule[] internal _rules;
diff --git a/contracts/mocks/RuleEngine/RuleMock.sol b/contracts/mocks/RuleEngine/RuleMock.sol
index 1bf71277..a9621295 100644
--- a/contracts/mocks/RuleEngine/RuleMock.sol
+++ b/contracts/mocks/RuleEngine/RuleMock.sol
@@ -5,6 +5,7 @@ pragma solidity ^0.8.20;
import "./interfaces/IRule.sol";
import "./CodeList.sol";
+
/*
* @title a mock for testing, not suitable for production
*/
diff --git a/contracts/modules/CMTAT_BASE.sol b/contracts/modules/CMTAT_BASE.sol
index 57bfc1bd..dfe445cf 100644
--- a/contracts/modules/CMTAT_BASE.sol
+++ b/contracts/modules/CMTAT_BASE.sol
@@ -3,8 +3,8 @@
pragma solidity ^0.8.20;
// required OZ imports here
-import "../../openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol";
-import "../../openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol";
+import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
+import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol";
import "./wrapper/core/BaseModule.sol";
import "./wrapper/core/ERC20BurnModule.sol";
@@ -20,86 +20,70 @@ import "./wrapper/extensions/ERC20SnapshotModule.sol";
import "./wrapper/controllers/ValidationModule.sol";
import "./wrapper/extensions/MetaTxModule.sol";
-import "./wrapper/extensions/DebtModule/DebtBaseModule.sol";
-import "./wrapper/extensions/DebtModule/CreditEventsModule.sol";
+import "./wrapper/extensions/DebtModule.sol";
+import "./wrapper/extensions/DocumentModule.sol";
import "./security/AuthorizationModule.sol";
-
+import "../interfaces/ICMTATConstructor.sol";
import "../libraries/Errors.sol";
abstract contract CMTAT_BASE is
Initializable,
ContextUpgradeable,
+ // Core
BaseModule,
PauseModule,
ERC20MintModule,
ERC20BurnModule,
EnforcementModule,
ValidationModule,
- MetaTxModule,
ERC20BaseModule,
+ // Extension
+ MetaTxModule,
ERC20SnapshotModule,
- DebtBaseModule,
- CreditEventsModule
-{
+ DebtModule,
+ DocumentModule
+{
+
+ /*//////////////////////////////////////////////////////////////
+ INITIALIZER FUNCTION
+ //////////////////////////////////////////////////////////////*/
/**
* @notice
* initialize the proxy contract
* The calls to this function will revert if the contract was deployed without a proxy
* @param admin address of the admin of contract (Access Control)
- * @param nameIrrevocable name of the token
- * @param symbolIrrevocable name of the symbol
- * @param decimalsIrrevocable number of decimals of the token, must be 0 to be compliant with Swiss law as per CMTAT specifications (non-zero decimal number may be needed for other use cases)
- * @param tokenId_ name of the tokenId
- * @param terms_ terms associated with the token
- * @param ruleEngine_ address of the ruleEngine to apply rules to transfers
- * @param information_ additional information to describe the token
- * @param flag_ add information under the form of bit(0, 1)
+ * @param ERC20Attributes_ ERC20 name, symbol and decimals
+ * @param baseModuleAttributes_ tokenId, terms, information
+ * @param engines_ external contract
*/
function initialize(
address admin,
- IAuthorizationEngine authorizationEngineIrrevocable,
- string memory nameIrrevocable,
- string memory symbolIrrevocable,
- uint8 decimalsIrrevocable,
- string memory tokenId_,
- string memory terms_,
- IRuleEngine ruleEngine_,
- string memory information_,
- uint256 flag_
- ) public initializer {
+ ICMTATConstructor.ERC20Attributes memory ERC20Attributes_,
+ ICMTATConstructor.BaseModuleAttributes memory baseModuleAttributes_,
+ ICMTATConstructor.Engine memory engines_
+ ) public virtual initializer {
__CMTAT_init(
admin,
- authorizationEngineIrrevocable,
- nameIrrevocable,
- symbolIrrevocable,
- decimalsIrrevocable,
- tokenId_,
- terms_,
- ruleEngine_,
- information_,
- flag_
+ ERC20Attributes_,
+ baseModuleAttributes_,
+ engines_
);
}
+
/**
* @dev calls the different initialize functions from the different modules
*/
function __CMTAT_init(
address admin,
- IAuthorizationEngine authorizationEngineIrrevocable,
- string memory nameIrrevocable,
- string memory symbolIrrevocable,
- uint8 decimalsIrrevocable,
- string memory tokenId_,
- string memory terms_,
- IRuleEngine ruleEngine_,
- string memory information_,
- uint256 flag_
+ ICMTATConstructor.ERC20Attributes memory ERC20Attributes_,
+ ICMTATConstructor.BaseModuleAttributes memory baseModuleAttributes_,
+ ICMTATConstructor.Engine memory engines_
) internal onlyInitializing {
/* OpenZeppelin library */
// OZ init_unchained functions are called firstly due to inheritance
__Context_init_unchained();
- __ERC20_init_unchained(nameIrrevocable, symbolIrrevocable);
+ __ERC20_init_unchained(ERC20Attributes_.nameIrrevocable, ERC20Attributes_.symbolIrrevocable);
// AccessControlUpgradeable inherits from ERC165Upgradeable
__ERC165_init_unchained();
// AuthorizationModule inherits from AccessControlUpgradeable
@@ -115,16 +99,16 @@ abstract contract CMTAT_BASE is
__SnapshotModuleBase_init_unchained();
__ERC20Snapshot_init_unchained();
- __Validation_init_unchained(ruleEngine_);
+ __Validation_init_unchained(engines_ .ruleEngine);
/* Wrapper */
// AuthorizationModule_init_unchained is called firstly due to inheritance
- __AuthorizationModule_init_unchained(admin, authorizationEngineIrrevocable);
+ __AuthorizationModule_init_unchained(admin, engines_ .authorizationEngine);
__ERC20BurnModule_init_unchained();
__ERC20MintModule_init_unchained();
// EnforcementModule_init_unchained is called before ValidationModule_init_unchained due to inheritance
__EnforcementModule_init_unchained();
- __ERC20BaseModule_init_unchained(decimalsIrrevocable);
+ __ERC20BaseModule_init_unchained(ERC20Attributes_.decimalsIrrevocable);
// PauseModule_init_unchained is called before ValidationModule_init_unchained due to inheritance
__PauseModule_init_unchained();
__ValidationModule_init_unchained();
@@ -134,12 +118,11 @@ abstract contract CMTAT_BASE is
Add this call in case you add the SnapshotModule
*/
__ERC20SnasphotModule_init_unchained();
-
+ __DocumentModule_init_unchained(engines_ .documentEngine);
+ __DebtModule_init_unchained(engines_ .debtEngine);
/* Other modules */
- __DebtBaseModule_init_unchained();
- __CreditEvents_init_unchained();
- __Base_init_unchained(tokenId_, terms_, information_, flag_);
+ __Base_init_unchained(baseModuleAttributes_.tokenId, baseModuleAttributes_.terms, baseModuleAttributes_.information);
/* own function */
__CMTAT_init_unchained();
@@ -149,6 +132,11 @@ abstract contract CMTAT_BASE is
// no variable to initialize
}
+
+ /*//////////////////////////////////////////////////////////////
+ PUBLIC/EXTERNAL FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+
/**
* @notice Returns the number of decimals used to get its user representation.
*/
@@ -191,6 +179,9 @@ abstract contract CMTAT_BASE is
mint(to, amountToMint);
}
+ /*//////////////////////////////////////////////////////////////
+ INTERNAL/PRIVATE FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
/**
* @dev
*
@@ -211,8 +202,9 @@ abstract contract CMTAT_BASE is
ERC20SnapshotModuleInternal._snapshotUpdate(from, to);
ERC20Upgradeable._update(from, to, amount);
}
-
- /************* MetaTx Module *************/
+ /*//////////////////////////////////////////////////////////////
+ METAXTX MODULE
+ //////////////////////////////////////////////////////////////*/
/**
* @dev This surcharge is not necessary if you do not use the MetaTxModule
*/
@@ -245,6 +237,4 @@ abstract contract CMTAT_BASE is
{
return ERC2771ContextUpgradeable._msgData();
}
-
- uint256[50] private __gap;
}
diff --git a/contracts/modules/internal/ERC20SnapshotModuleInternal.sol b/contracts/modules/internal/ERC20SnapshotModuleInternal.sol
index 24e9e713..654b7186 100644
--- a/contracts/modules/internal/ERC20SnapshotModuleInternal.sol
+++ b/contracts/modules/internal/ERC20SnapshotModuleInternal.sol
@@ -2,7 +2,7 @@
pragma solidity ^0.8.20;
-import "../../../openzeppelin-contracts-upgradeable/contracts/token/ERC20/ERC20Upgradeable.sol";
+import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import {Arrays} from '@openzeppelin/contracts/utils/Arrays.sol';
import "./base/SnapshotModuleBase.sol";
import "../../interfaces/ICMTATSnapshot.sol";
@@ -17,19 +17,16 @@ import "../../interfaces/ICMTATSnapshot.sol";
abstract contract ERC20SnapshotModuleInternal is ICMTATSnapshot, SnapshotModuleBase, ERC20Upgradeable {
using Arrays for uint256[];
-
- /**
- * @dev
- * list of scheduled snapshot (time)
- * This list is sorted in ascending order
- */
- uint256[] private _scheduledSnapshots;
-
+ /* ============ Initializer Function ============ */
function __ERC20Snapshot_init_unchained() internal onlyInitializing {
// Nothing to do
// _currentSnapshotTime & _currentSnapshotIndex are initialized to zero
}
+
+ /*//////////////////////////////////////////////////////////////
+ PUBLIC/EXTERNAL FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
/**
* @notice Return snapshotBalanceOf and snapshotTotalSupply to avoid multiple calls
* @return ownerBalance , totalSupply - see snapshotBalanceOf and snapshotTotalSupply
@@ -59,11 +56,6 @@ abstract contract ERC20SnapshotModuleInternal is ICMTATSnapshot, SnapshotModuleB
ownerBalances = new uint256[][](times.length);
totalSupply = new uint256[](times.length);
for(uint256 iT = 0; iT < times.length; ++iT){
- /*ownerBalances[iT] = new uint256[](addresses.length);
- for(uint256 jA = 0; jA < addresses.length; ++jA){
- ownerBalances[iT][jA] = snapshotBalanceOf(times[iT], addresses[jA]);
- }
- totalSupply[iT] = snapshotTotalSupply(times[iT]);*/
(ownerBalances[iT], totalSupply[iT]) = snapshotInfoBatch(times[iT],addresses);
}
}
@@ -76,9 +68,10 @@ abstract contract ERC20SnapshotModuleInternal is ICMTATSnapshot, SnapshotModuleB
uint256 time,
address owner
) public view returns (uint256) {
+ SnapshotModuleBaseStorage storage $ = _getSnapshotModuleBaseStorage();
(bool snapshotted, uint256 value) = _valueAt(
time,
- _accountBalanceSnapshots[owner]
+ $._accountBalanceSnapshots[owner]
);
return snapshotted ? value : balanceOf(owner);
@@ -90,13 +83,17 @@ abstract contract ERC20SnapshotModuleInternal is ICMTATSnapshot, SnapshotModuleB
* @return value stored in the snapshot, or the actual totalSupply if no snapshot
*/
function snapshotTotalSupply(uint256 time) public view returns (uint256) {
+ SnapshotModuleBaseStorage storage $ = _getSnapshotModuleBaseStorage();
(bool snapshotted, uint256 value) = _valueAt(
time,
- _totalSupplySnapshots
+ $._totalSupplySnapshots
);
return snapshotted ? value : totalSupply();
}
+ /*//////////////////////////////////////////////////////////////
+ INTERNAL/PRIVATE FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
/**
* @dev Update balance and/or total supply snapshots before the values are modified. This is implemented
@@ -128,15 +125,15 @@ abstract contract ERC20SnapshotModuleInternal is ICMTATSnapshot, SnapshotModuleB
* @dev See {OpenZeppelin - ERC20Snapshot}
*/
function _updateAccountSnapshot(address account) private {
- _updateSnapshot(_accountBalanceSnapshots[account], balanceOf(account));
+ SnapshotModuleBaseStorage storage $ = _getSnapshotModuleBaseStorage();
+ _updateSnapshot($._accountBalanceSnapshots[account], balanceOf(account));
}
/**
* @dev See {OpenZeppelin - ERC20Snapshot}
*/
function _updateTotalSupplySnapshot() private {
- _updateSnapshot(_totalSupplySnapshots, totalSupply());
+ SnapshotModuleBaseStorage storage $ = _getSnapshotModuleBaseStorage();
+ _updateSnapshot($._totalSupplySnapshots, totalSupply());
}
-
- uint256[50] private __gap;
}
diff --git a/contracts/modules/internal/EnforcementModuleInternal.sol b/contracts/modules/internal/EnforcementModuleInternal.sol
index 63230bfb..a7c0b4c4 100644
--- a/contracts/modules/internal/EnforcementModuleInternal.sol
+++ b/contracts/modules/internal/EnforcementModuleInternal.sol
@@ -2,9 +2,9 @@
pragma solidity ^0.8.20;
-import "../../../openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol";
-import "../../../openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol";
-import "../../../openzeppelin-contracts-upgradeable/contracts/token/ERC20/ERC20Upgradeable.sol";
+import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol";
+import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
+import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
/**
* @dev Enforcement module.
@@ -15,6 +15,7 @@ abstract contract EnforcementModuleInternal is
Initializable,
ContextUpgradeable
{
+ /* ============ Events ============ */
/**
* @notice Emitted when an address is frozen.
*/
@@ -35,19 +36,40 @@ abstract contract EnforcementModuleInternal is
string reason
);
- mapping(address => bool) private _frozen;
+ /* ============ ERC-7201 ============ */
+ // keccak256(abi.encode(uint256(keccak256("CMTAT.storage.EnforcementModuleInternal")) - 1)) & ~bytes32(uint256(0xff))
+ bytes32 private constant EnforcementModuleInternalStorageLocation = 0x0c7bc8a17be064111d299d7669f49519cb26c58611b72d9f6ccc40a1e1184e00;
+
+ /* ==== ERC-7201 State Variables === */
+ struct EnforcementModuleInternalStorage {
+ mapping(address => bool) _frozen;
+ }
+
+
+ /*//////////////////////////////////////////////////////////////
+ INITIALIZER FUNCTION
+ //////////////////////////////////////////////////////////////*/
function __Enforcement_init_unchained() internal onlyInitializing {
// no variable to initialize
}
+ /*//////////////////////////////////////////////////////////////
+ PUBLIC/EXTERNAL FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+
/**
* @dev Returns true if the account is frozen, and false otherwise.
*/
function frozen(address account) public view virtual returns (bool) {
- return _frozen[account];
+ EnforcementModuleInternalStorage storage $ = _getEnforcementModuleInternalStorage();
+ return $._frozen[account];
}
+ /*//////////////////////////////////////////////////////////////
+ INTERNAL/PRIVATE FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+
/**
* @dev Freezes an address.
* @param account the account to freeze
@@ -58,10 +80,11 @@ abstract contract EnforcementModuleInternal is
address account,
string calldata reason
) internal virtual returns (bool) {
- if (_frozen[account]) {
+ EnforcementModuleInternalStorage storage $ = _getEnforcementModuleInternalStorage();
+ if ($._frozen[account]) {
return false;
}
- _frozen[account] = true;
+ $._frozen[account] = true;
emit Freeze(_msgSender(), account, reason, reason);
return true;
}
@@ -75,14 +98,20 @@ abstract contract EnforcementModuleInternal is
address account,
string calldata reason
) internal virtual returns (bool) {
- if (!_frozen[account]) {
+ EnforcementModuleInternalStorage storage $ = _getEnforcementModuleInternalStorage();
+ if (!$._frozen[account]) {
return false;
}
- _frozen[account] = false;
+ $._frozen[account] = false;
emit Unfreeze(_msgSender(), account, reason, reason);
return true;
}
- uint256[50] private __gap;
+ /* ============ ERC-7201 ============ */
+ function _getEnforcementModuleInternalStorage() private pure returns (EnforcementModuleInternalStorage storage $) {
+ assembly {
+ $.slot := EnforcementModuleInternalStorageLocation
+ }
+ }
}
diff --git a/contracts/modules/internal/ValidationModuleInternal.sol b/contracts/modules/internal/ValidationModuleInternal.sol
index 6219f105..7ec094f5 100644
--- a/contracts/modules/internal/ValidationModuleInternal.sol
+++ b/contracts/modules/internal/ValidationModuleInternal.sol
@@ -2,8 +2,8 @@
pragma solidity ^0.8.20;
-import "../../../openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol";
-import "../../../openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol";
+import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol";
+import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "../../interfaces/engine/IRuleEngine.sol";
/**
* @dev Validation module.
@@ -14,22 +14,44 @@ abstract contract ValidationModuleInternal is
Initializable,
ContextUpgradeable
{
+ /* ============ Events ============ */
/**
* @dev Emitted when a rule engine is set.
*/
event RuleEngine(IRuleEngine indexed newRuleEngine);
-
- IRuleEngine public ruleEngine;
-
+ /* ============ ERC-7201 ============ */
+ // keccak256(abi.encode(uint256(keccak256("CMTAT.storage.ValidationModuleInternal")) - 1)) & ~bytes32(uint256(0xff))
+ bytes32 private constant ValidationModuleInternalStorageLocation = 0xb3e8f29e401cfa802cad91001b5f9eb50decccdb111d80cb07177ab650b04700;
+ /* ==== ERC-7201 State Variables === */
+ struct ValidationModuleInternalStorage {
+ IRuleEngine _ruleEngine;
+ }
+ /* ============ Initializer Function ============ */
function __Validation_init_unchained(
IRuleEngine ruleEngine_
) internal onlyInitializing {
if (address(ruleEngine_) != address(0)) {
- ruleEngine = ruleEngine_;
- emit RuleEngine(ruleEngine);
+ ValidationModuleInternalStorage storage $ = _getValidationModuleInternalStorage();
+ $._ruleEngine = ruleEngine_;
+ emit RuleEngine(ruleEngine_);
}
}
+
+ /*//////////////////////////////////////////////////////////////
+ PUBLIC/EXTERNAL FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+
+ function ruleEngine() public view returns(IRuleEngine){
+ ValidationModuleInternalStorage storage $ = _getValidationModuleInternalStorage();
+ return $._ruleEngine;
+ }
+
+
+ /*//////////////////////////////////////////////////////////////
+ INTERNAL/PRIVATE FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+
/**
* @dev before making a call to this function, you have to check if a ruleEngine is set.
*/
@@ -38,7 +60,8 @@ abstract contract ValidationModuleInternal is
address to,
uint256 amount
) internal view returns (bool) {
- return ruleEngine.validateTransfer(from, to, amount);
+ ValidationModuleInternalStorage storage $ = _getValidationModuleInternalStorage();
+ return $._ruleEngine.validateTransfer(from, to, amount);
}
/**
@@ -47,7 +70,8 @@ abstract contract ValidationModuleInternal is
function _messageForTransferRestriction(
uint8 restrictionCode
) internal view returns (string memory) {
- return ruleEngine.messageForTransferRestriction(restrictionCode);
+ ValidationModuleInternalStorage storage $ = _getValidationModuleInternalStorage();
+ return $._ruleEngine.messageForTransferRestriction(restrictionCode);
}
/**
@@ -58,12 +82,20 @@ abstract contract ValidationModuleInternal is
address to,
uint256 amount
) internal view returns (uint8) {
- return ruleEngine.detectTransferRestriction(from, to, amount);
+ ValidationModuleInternalStorage storage $ = _getValidationModuleInternalStorage();
+ return $._ruleEngine.detectTransferRestriction(from, to, amount);
}
function _operateOnTransfer(address from, address to, uint256 amount) virtual internal returns (bool) {
- return ruleEngine.operateOnTransfer(from, to, amount);
+ ValidationModuleInternalStorage storage $ = _getValidationModuleInternalStorage();
+ return $._ruleEngine.operateOnTransfer(from, to, amount);
}
- uint256[50] private __gap;
+
+ /* ============ ERC-7201 ============ */
+ function _getValidationModuleInternalStorage() internal pure returns (ValidationModuleInternalStorage storage $) {
+ assembly {
+ $.slot := ValidationModuleInternalStorageLocation
+ }
+ }
}
diff --git a/contracts/modules/internal/base/SnapshotModuleBase.sol b/contracts/modules/internal/base/SnapshotModuleBase.sol
index 1290cbd2..d099e467 100644
--- a/contracts/modules/internal/base/SnapshotModuleBase.sol
+++ b/contracts/modules/internal/base/SnapshotModuleBase.sol
@@ -2,7 +2,7 @@
pragma solidity ^0.8.20;
-import "../../../../openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol";
+import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {Arrays} from '@openzeppelin/contracts/utils/Arrays.sol';
import "../../../libraries/Errors.sol";
@@ -13,22 +13,12 @@ import "../../../libraries/Errors.sol";
* Useful to take a snapshot of token holder balance and total supply at a specific time
* Inspired by Openzeppelin - ERC20Snapshot but use the time as Id instead of a counter.
* Contrary to OpenZeppelin, the function _getCurrentSnapshotId is not available
- because overriding this function can break the contract.
+ * because overriding this function can break the contract.
*/
abstract contract SnapshotModuleBase is Initializable {
using Arrays for uint256[];
-
- /**
- @notice Emitted when the snapshot with the specified oldTime was scheduled or rescheduled at the specified newTime.
- */
- event SnapshotSchedule(uint256 indexed oldTime, uint256 indexed newTime);
-
- /**
- * @notice Emitted when the scheduled snapshot with the specified time was cancelled.
- */
- event SnapshotUnschedule(uint256 indexed time);
-
+ /* ============ Structs ============ *
/**
* @dev See {OpenZeppelin - ERC20Snapshot}
* Snapshotted values have arrays of ids (time) and the value corresponding to that id.
@@ -39,68 +29,88 @@ abstract contract SnapshotModuleBase is Initializable {
uint256[] ids;
uint256[] values;
}
-
- /**
- * @dev See {OpenZeppelin - ERC20Snapshot}
- */
- mapping(address => Snapshots) internal _accountBalanceSnapshots;
- Snapshots internal _totalSupplySnapshots;
-
+ /* ============ Events ============ */
/**
- * @dev time instead of a counter for OpenZeppelin
+ @notice Emitted when the snapshot with the specified oldTime was scheduled or rescheduled at the specified newTime.
*/
- // Initialized to zero
- uint256 private _currentSnapshotTime;
- // Initialized to zero
- uint256 private _currentSnapshotIndex;
+ event SnapshotSchedule(uint256 indexed oldTime, uint256 indexed newTime);
/**
- * @dev
- * list of scheduled snapshot (time)
- * This list is sorted in ascending order
+ * @notice Emitted when the scheduled snapshot with the specified time was cancelled.
*/
- uint256[] private _scheduledSnapshots;
+ event SnapshotUnschedule(uint256 indexed time);
+ /* ============ ERC-7201 ============ */
+ // keccak256(abi.encode(uint256(keccak256("CMTAT.storage.SnapshotModuleBase")) - 1)) & ~bytes32(uint256(0xff))
+ bytes32 private constant SnapshotModuleBaseStorageLocation = 0x649d9af4a0486294740af60c5e3bf61210e7b49108a80b1f369042ea9fd02000;
+ /* ==== ERC-7201 State Variables === */
+ struct SnapshotModuleBaseStorage {
+ /**
+ * @dev See {OpenZeppelin - ERC20Snapshot}
+ */
+ mapping(address => Snapshots) _accountBalanceSnapshots;
+ Snapshots _totalSupplySnapshots;
+ /**
+ * @dev time instead of a counter for OpenZeppelin
+ */
+ // Initialized to zero
+ uint256 _currentSnapshotTime;
+ // Initialized to zero
+ uint256 _currentSnapshotIndex;
+ /**
+ * @dev
+ * list of scheduled snapshot (time)
+ * This list is sorted in ascending order
+ */
+ uint256[] _scheduledSnapshots;
+ }
+ /*//////////////////////////////////////////////////////////////
+ INITIALIZER FUNCTION
+ //////////////////////////////////////////////////////////////*/
function __SnapshotModuleBase_init_unchained() internal onlyInitializing {
// Nothing to do
// _currentSnapshotTime & _currentSnapshotIndex are initialized to zero
}
-
+ /*//////////////////////////////////////////////////////////////
+ PUBLIC/EXTERNAL FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
/**
*
* @notice Get all snapshots
*/
function getAllSnapshots() public view returns (uint256[] memory) {
- return _scheduledSnapshots;
+ SnapshotModuleBaseStorage storage $ = _getSnapshotModuleBaseStorage();
+ return $._scheduledSnapshots;
}
- /**
+ /**
* @dev
* Get the next scheduled snapshots
*/
function getNextSnapshots() public view returns (uint256[] memory) {
+ SnapshotModuleBaseStorage storage $ = _getSnapshotModuleBaseStorage();
uint256[] memory nextScheduledSnapshot = new uint256[](0);
// no snapshot were planned
- if (_scheduledSnapshots.length > 0) {
+ if ($._scheduledSnapshots.length > 0) {
(
uint256 timeLowerBound,
uint256 indexLowerBound
) = _findScheduledMostRecentPastSnapshot();
// All snapshots are situated in the futur
- if ((timeLowerBound == 0) && (_currentSnapshotTime == 0)) {
- return _scheduledSnapshots;
+ if ((timeLowerBound == 0) && ($._currentSnapshotTime == 0)) {
+ return $._scheduledSnapshots;
} else {
// There are snapshots situated in the futur
- if (indexLowerBound + 1 != _scheduledSnapshots.length) {
+ if (indexLowerBound + 1 != $._scheduledSnapshots.length) {
// All next snapshots are located after the snapshot specified by indexLowerBound
- uint256 arraySize = _scheduledSnapshots.length -
+ uint256 arraySize = $._scheduledSnapshots.length -
indexLowerBound -
1;
nextScheduledSnapshot = new uint256[](arraySize);
// No need of unchecked block since Soliditiy 0.8.22
for (uint256 i; i < arraySize; ++i) {
- nextScheduledSnapshot[i] = _scheduledSnapshots[
+ nextScheduledSnapshot[i] = $._scheduledSnapshots[
indexLowerBound + 1 + i
];
}
@@ -110,24 +120,23 @@ abstract contract SnapshotModuleBase is Initializable {
return nextScheduledSnapshot;
}
+ /*//////////////////////////////////////////////////////////////
+ INTERNAL/PRIVATE FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
/**
* @dev schedule a snapshot at the specified time
* You can only add a snapshot after the last previous
*/
function _scheduleSnapshot(uint256 time) internal {
+ SnapshotModuleBaseStorage storage $ = _getSnapshotModuleBaseStorage();
// Check the time firstly to avoid an useless read of storage
- if (time <= block.timestamp) {
- revert Errors.CMTAT_SnapshotModule_SnapshotScheduledInThePast(
- time,
- block.timestamp
- );
- }
+ _checkTimeInThePast(time);
- if (_scheduledSnapshots.length > 0) {
+ if ($._scheduledSnapshots.length > 0) {
// We check the last snapshot on the list
- uint256 nextSnapshotTime = _scheduledSnapshots[
- _scheduledSnapshots.length - 1
+ uint256 nextSnapshotTime = $._scheduledSnapshots[
+ $._scheduledSnapshots.length - 1
];
if (time < nextSnapshotTime) {
revert Errors
@@ -139,7 +148,7 @@ abstract contract SnapshotModuleBase is Initializable {
revert Errors.CMTAT_SnapshotModule_SnapshotAlreadyExists();
}
}
- _scheduledSnapshots.push(time);
+ $._scheduledSnapshots.push(time);
emit SnapshotSchedule(0, time);
}
@@ -147,31 +156,27 @@ abstract contract SnapshotModuleBase is Initializable {
* @dev schedule a snapshot at the specified time
*/
function _scheduleSnapshotNotOptimized(uint256 time) internal {
- if (time <= block.timestamp) {
- revert Errors.CMTAT_SnapshotModule_SnapshotScheduledInThePast(
- time,
- block.timestamp
- );
- }
+ SnapshotModuleBaseStorage storage $ = _getSnapshotModuleBaseStorage();
+ _checkTimeInThePast(time);
(bool isFound, uint256 index) = _findScheduledSnapshotIndex(time);
// Perfect match
if (isFound) {
revert Errors.CMTAT_SnapshotModule_SnapshotAlreadyExists();
}
// if no upper bound match found, we push the snapshot at the end of the list
- if (index == _scheduledSnapshots.length) {
- _scheduledSnapshots.push(time);
+ if (index == $._scheduledSnapshots.length) {
+ $._scheduledSnapshots.push(time);
} else {
- _scheduledSnapshots.push(
- _scheduledSnapshots[_scheduledSnapshots.length - 1]
+ $._scheduledSnapshots.push(
+ $._scheduledSnapshots[$._scheduledSnapshots.length - 1]
);
- for (uint256 i = _scheduledSnapshots.length - 2; i > index; ) {
- _scheduledSnapshots[i] = _scheduledSnapshots[i - 1];
+ for (uint256 i = $._scheduledSnapshots.length - 2; i > index; ) {
+ $._scheduledSnapshots[i] = $._scheduledSnapshots[i - 1];
unchecked {
--i;
}
}
- _scheduledSnapshots[index] = time;
+ $._scheduledSnapshots[index] = time;
}
emit SnapshotSchedule(0, time);
}
@@ -180,25 +185,16 @@ abstract contract SnapshotModuleBase is Initializable {
* @dev reschedule a scheduled snapshot at the specified newTime
*/
function _rescheduleSnapshot(uint256 oldTime, uint256 newTime) internal {
+ SnapshotModuleBaseStorage storage $ = _getSnapshotModuleBaseStorage();
// Check the time firstly to avoid an useless read of storage
- if (oldTime <= block.timestamp) {
- revert Errors.CMTAT_SnapshotModule_SnapshotAlreadyDone();
- }
- if (newTime <= block.timestamp) {
- revert Errors.CMTAT_SnapshotModule_SnapshotScheduledInThePast(
- newTime,
- block.timestamp
- );
- }
- if (_scheduledSnapshots.length == 0) {
+ _checkTimeSnapshotAlreadyDone(oldTime);
+ _checkTimeInThePast(newTime);
+ if ($._scheduledSnapshots.length == 0) {
revert Errors.CMTAT_SnapshotModule_NoSnapshotScheduled();
}
- (bool foundOld, uint256 index) = _findScheduledSnapshotIndex(oldTime);
- if (!foundOld) {
- revert Errors.CMTAT_SnapshotModule_SnapshotNotFound();
- }
- if (index + 1 < _scheduledSnapshots.length) {
- uint256 nextSnapshotTime = _scheduledSnapshots[index + 1];
+ uint256 index = _findAndRevertScheduledSnapshotIndex(oldTime);
+ if (index + 1 < $._scheduledSnapshots.length) {
+ uint256 nextSnapshotTime = $._scheduledSnapshots[index + 1];
if (newTime > nextSnapshotTime) {
revert Errors
.CMTAT_SnapshotModule_SnapshotTimestampAfterNextSnapshot(
@@ -210,14 +206,14 @@ abstract contract SnapshotModuleBase is Initializable {
}
}
if (index > 0) {
- if (newTime <= _scheduledSnapshots[index - 1])
+ if (newTime <= $._scheduledSnapshots[index - 1])
revert Errors
.CMTAT_SnapshotModule_SnapshotTimestampBeforePreviousSnapshot(
newTime,
- _scheduledSnapshots[index - 1]
+ $._scheduledSnapshots[index - 1]
);
}
- _scheduledSnapshots[index] = newTime;
+ $._scheduledSnapshots[index] = newTime;
emit SnapshotSchedule(oldTime, newTime);
}
@@ -226,18 +222,17 @@ abstract contract SnapshotModuleBase is Initializable {
* @dev unschedule the last scheduled snapshot
*/
function _unscheduleLastSnapshot(uint256 time) internal {
+ SnapshotModuleBaseStorage storage $ = _getSnapshotModuleBaseStorage();
// Check the time firstly to avoid an useless read of storage
- if (time <= block.timestamp) {
- revert Errors.CMTAT_SnapshotModule_SnapshotAlreadyDone();
- }
- if (_scheduledSnapshots.length == 0) {
+ _checkTimeSnapshotAlreadyDone(time);
+ if ($._scheduledSnapshots.length == 0) {
revert Errors.CMTAT_SnapshotModule_NoSnapshotScheduled();
}
// All snapshot time are unique, so we do not check the indice
- if (time != _scheduledSnapshots[_scheduledSnapshots.length - 1]) {
+ if (time !=$._scheduledSnapshots[$._scheduledSnapshots.length - 1]) {
revert Errors.CMTAT_SnapshotModule_SnapshotNotFound();
}
- _scheduledSnapshots.pop();
+ $._scheduledSnapshots.pop();
emit SnapshotUnschedule(time);
}
@@ -248,18 +243,15 @@ abstract contract SnapshotModuleBase is Initializable {
* - Reduce the array size by deleting the last snapshot
*/
function _unscheduleSnapshotNotOptimized(uint256 time) internal {
- if (time <= block.timestamp) {
- revert Errors.CMTAT_SnapshotModule_SnapshotAlreadyDone();
- }
- (bool isFound, uint256 index) = _findScheduledSnapshotIndex(time);
- if (!isFound) {
- revert Errors.CMTAT_SnapshotModule_SnapshotNotFound();
- }
+ SnapshotModuleBaseStorage storage $ = _getSnapshotModuleBaseStorage();
+ _checkTimeSnapshotAlreadyDone(time);
+
+ uint256 index = _findAndRevertScheduledSnapshotIndex(time);
// No need of unchecked block since Soliditiy 0.8.22
- for (uint256 i = index; i + 1 < _scheduledSnapshots.length; ++i ) {
- _scheduledSnapshots[i] = _scheduledSnapshots[i + 1];
+ for (uint256 i = index; i + 1 < $._scheduledSnapshots.length; ++i ) {
+ $._scheduledSnapshots[i] = $._scheduledSnapshots[i + 1];
}
- _scheduledSnapshots.pop();
+ $._scheduledSnapshots.pop();
}
/**
@@ -306,7 +298,8 @@ abstract contract SnapshotModuleBase is Initializable {
Snapshots storage snapshots,
uint256 currentValue
) internal {
- uint256 current = _currentSnapshotTime;
+ SnapshotModuleBaseStorage storage $ = _getSnapshotModuleBaseStorage();
+ uint256 current = $._currentSnapshotTime;
if (_lastSnapshot(snapshots.ids) < current) {
snapshots.ids.push(current);
snapshots.values.push(currentValue);
@@ -319,13 +312,14 @@ abstract contract SnapshotModuleBase is Initializable {
* if a snapshot exists, clear all past scheduled snapshot
*/
function _setCurrentSnapshot() internal {
+ SnapshotModuleBaseStorage storage $ = _getSnapshotModuleBaseStorage();
(
uint256 scheduleSnapshotTime,
uint256 scheduleSnapshotIndex
) = _findScheduledMostRecentPastSnapshot();
if (scheduleSnapshotTime > 0) {
- _currentSnapshotTime = scheduleSnapshotTime;
- _currentSnapshotIndex = scheduleSnapshotIndex;
+ $._currentSnapshotTime = scheduleSnapshotTime;
+ $._currentSnapshotIndex = scheduleSnapshotIndex;
}
}
@@ -349,12 +343,13 @@ abstract contract SnapshotModuleBase is Initializable {
function _findScheduledSnapshotIndex(
uint256 time
) private view returns (bool, uint256) {
- uint256 indexFound = _scheduledSnapshots.findUpperBound(time);
- uint256 _scheduledSnapshotsLength = _scheduledSnapshots.length;
+ SnapshotModuleBaseStorage storage $ = _getSnapshotModuleBaseStorage();
+ uint256 indexFound = $._scheduledSnapshots.findUpperBound(time);
+ uint256 _scheduledSnapshotsLength = $._scheduledSnapshots.length;
// Exact match
if (
indexFound != _scheduledSnapshotsLength &&
- _scheduledSnapshots[indexFound] == time
+ $._scheduledSnapshots[indexFound] == time
) {
return (true, indexFound);
}
@@ -377,11 +372,12 @@ abstract contract SnapshotModuleBase is Initializable {
view
returns (uint256 time, uint256 index)
{
- uint256 currentArraySize = _scheduledSnapshots.length;
+ SnapshotModuleBaseStorage storage $ = _getSnapshotModuleBaseStorage();
+ uint256 currentArraySize = $._scheduledSnapshots.length;
// no snapshot or the current snapshot already points on the last snapshot
if (
currentArraySize == 0 ||
- ((_currentSnapshotIndex + 1 == currentArraySize) && (time != 0))
+ (($._currentSnapshotIndex + 1 == currentArraySize) && (time != 0))
) {
return (0, currentArraySize);
}
@@ -389,9 +385,9 @@ abstract contract SnapshotModuleBase is Initializable {
uint256 mostRecent;
index = currentArraySize;
// No need of unchecked block since Soliditiy 0.8.22
- for (uint256 i = _currentSnapshotIndex; i < currentArraySize; ++i ) {
- if (_scheduledSnapshots[i] <= block.timestamp) {
- mostRecent = _scheduledSnapshots[i];
+ for (uint256 i = $._currentSnapshotIndex; i < currentArraySize; ++i ) {
+ if ($._scheduledSnapshots[i] <= block.timestamp) {
+ mostRecent = $._scheduledSnapshots[i];
index = i;
} else {
// All snapshot are planned in the futur
@@ -401,5 +397,36 @@ abstract contract SnapshotModuleBase is Initializable {
return (mostRecent, index);
}
- uint256[50] private __gap;
+ /* ============ Utility functions ============ */
+
+
+ function _findAndRevertScheduledSnapshotIndex(
+ uint256 time
+ ) private view returns (uint256){
+ (bool isFound, uint256 index) = _findScheduledSnapshotIndex(time);
+ if (!isFound) {
+ revert Errors.CMTAT_SnapshotModule_SnapshotNotFound();
+ }
+ return index;
+ }
+ function _checkTimeInThePast(uint256 time) internal view{
+ if (time <= block.timestamp) {
+ revert Errors.CMTAT_SnapshotModule_SnapshotScheduledInThePast(
+ time,
+ block.timestamp
+ );
+ }
+ }
+ function _checkTimeSnapshotAlreadyDone(uint256 time) internal view{
+ if (time <= block.timestamp) {
+ revert Errors.CMTAT_SnapshotModule_SnapshotAlreadyDone();
+ }
+ }
+
+ /* ============ ERC-7201 ============ */
+ function _getSnapshotModuleBaseStorage() internal pure returns (SnapshotModuleBaseStorage storage $) {
+ assembly {
+ $.slot := SnapshotModuleBaseStorageLocation
+ }
+ }
}
diff --git a/contracts/modules/security/AuthorizationModule.sol b/contracts/modules/security/AuthorizationModule.sol
index 7870b318..fea79fd9 100644
--- a/contracts/modules/security/AuthorizationModule.sol
+++ b/contracts/modules/security/AuthorizationModule.sol
@@ -2,16 +2,24 @@
pragma solidity ^0.8.20;
-import "../../../openzeppelin-contracts-upgradeable/contracts/access/AccessControlUpgradeable.sol";
+import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "../../libraries/Errors.sol";
import "../../interfaces/engine/IAuthorizationEngine.sol";
abstract contract AuthorizationModule is AccessControlUpgradeable {
- IAuthorizationEngine private authorizationEngine;
+ /* ============ Events ============ */
/**
* @dev Emitted when a rule engine is set.
*/
event AuthorizationEngine(IAuthorizationEngine indexed newAuthorizationEngine);
+ /* ============ ERC-7201 ============ */
+ // keccak256(abi.encode(uint256(keccak256("CMTAT.storage.AuthorizationModule")) - 1)) & ~bytes32(uint256(0xff))
+ bytes32 private constant AuthorizationModuleStorageLocation = 0x59b7f077fa4ad020f9053fd2197fef0113b19f0b11dcfe516e88cbc0e9226d00;
+ /* ==== ERC-7201 State Variables === */
+ struct AuthorizationModuleStorage {
+ IAuthorizationEngine _authorizationEngine;
+ }
+ /* ============ Initializer Function ============ */
/**
* @dev
*
@@ -25,13 +33,24 @@ abstract contract AuthorizationModule is AccessControlUpgradeable {
revert Errors.CMTAT_AuthorizationModule_AddressZeroNotAllowed();
}
_grantRole(DEFAULT_ADMIN_ROLE, admin);
- if (address(authorizationEngine) != address (0)) {
- authorizationEngine = authorizationEngine_;
+ if (address(authorizationEngine_) != address (0)) {
+ AuthorizationModuleStorage storage $ = _getAuthorizationModuleStorage();
+ $._authorizationEngine = authorizationEngine_;
+ emit AuthorizationEngine(authorizationEngine_);
}
-
+ }
+
+ /*//////////////////////////////////////////////////////////////
+ PUBLIC/EXTERNAL FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+
+ function authorizationEngine() public view virtual returns (IAuthorizationEngine) {
+ AuthorizationModuleStorage storage $ = _getAuthorizationModuleStorage();
+ return $._authorizationEngine;
}
+
/*
* @notice set an authorizationEngine if not already set
* @dev once an AuthorizationEngine is set, it is not possible to unset it
@@ -39,16 +58,18 @@ abstract contract AuthorizationModule is AccessControlUpgradeable {
function setAuthorizationEngine(
IAuthorizationEngine authorizationEngine_
) external onlyRole(DEFAULT_ADMIN_ROLE) {
- if (address(authorizationEngine) != address (0)){
+ AuthorizationModuleStorage storage $ = _getAuthorizationModuleStorage();
+ if (address($._authorizationEngine) != address (0)){
revert Errors.CMTAT_AuthorizationModule_AuthorizationEngineAlreadySet();
}
- authorizationEngine = authorizationEngine_;
+ $._authorizationEngine = authorizationEngine_;
emit AuthorizationEngine(authorizationEngine_);
}
function grantRole(bytes32 role, address account) public override onlyRole(getRoleAdmin(role)) {
- if (address(authorizationEngine) != address (0)) {
- bool result = authorizationEngine.operateOnGrantRole(role, account);
+ AuthorizationModuleStorage storage $ = _getAuthorizationModuleStorage();
+ if (address($._authorizationEngine) != address (0)) {
+ bool result = $._authorizationEngine.operateOnGrantRole(role, account);
if(!result) {
// Operation rejected by the authorizationEngine
revert Errors.CMTAT_AuthorizationModule_InvalidAuthorization();
@@ -58,8 +79,9 @@ abstract contract AuthorizationModule is AccessControlUpgradeable {
}
function revokeRole(bytes32 role, address account) public override onlyRole(getRoleAdmin(role)) {
- if (address(authorizationEngine) != address (0)) {
- bool result = authorizationEngine.operateOnRevokeRole(role, account);
+ AuthorizationModuleStorage storage $ = _getAuthorizationModuleStorage();
+ if (address($._authorizationEngine) != address (0)) {
+ bool result = $._authorizationEngine.operateOnRevokeRole(role, account);
if(!result) {
// Operation rejected by the authorizationEngine
revert Errors.CMTAT_AuthorizationModule_InvalidAuthorization();
@@ -82,5 +104,16 @@ abstract contract AuthorizationModule is AccessControlUpgradeable {
return AccessControlUpgradeable.hasRole(role, account);
}
- uint256[50] private __gap;
+
+ /*//////////////////////////////////////////////////////////////
+ INTERNAL/PRIVATE FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+
+
+ /* ============ ERC-7201 ============ */
+ function _getAuthorizationModuleStorage() private pure returns (AuthorizationModuleStorage storage $) {
+ assembly {
+ $.slot := AuthorizationModuleStorageLocation
+ }
+ }
}
diff --git a/contracts/modules/wrapper/controllers/ValidationModule.sol b/contracts/modules/wrapper/controllers/ValidationModule.sol
index 63fe5183..45426f98 100644
--- a/contracts/modules/wrapper/controllers/ValidationModule.sol
+++ b/contracts/modules/wrapper/controllers/ValidationModule.sol
@@ -20,13 +20,20 @@ abstract contract ValidationModule is
EnforcementModule,
IERC1404Wrapper
{
+ /* ============ State Variables ============ */
string constant TEXT_TRANSFER_OK = "No restriction";
string constant TEXT_UNKNOWN_CODE = "Unknown code";
+ /* ============ Initializer Function ============ */
function __ValidationModule_init_unchained() internal onlyInitializing {
// no variable to initialize
}
+
+ /*//////////////////////////////////////////////////////////////
+ PUBLIC/EXTERNAL FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+
/*
* @notice set a RuleEngine
* @param ruleEngine_ the call will be reverted if the new value of ruleEngine is the same as the current one
@@ -34,14 +41,15 @@ abstract contract ValidationModule is
function setRuleEngine(
IRuleEngine ruleEngine_
) external onlyRole(DEFAULT_ADMIN_ROLE) {
- if (ruleEngine == ruleEngine_){
+ ValidationModuleInternalStorage storage $ = _getValidationModuleInternalStorage();
+ if ($._ruleEngine == ruleEngine_){
revert Errors.CMTAT_ValidationModule_SameValue();
}
- ruleEngine = ruleEngine_;
+ $._ruleEngine = ruleEngine_;
emit RuleEngine(ruleEngine_);
}
- /**
+ /**
* @dev ERC1404 returns the human readable explaination corresponding to the error code returned by detectTransferRestriction
* @param restrictionCode The error code returned by detectTransferRestriction
* @return message The human readable explaination corresponding to the error code returned by detectTransferRestriction
@@ -49,6 +57,7 @@ abstract contract ValidationModule is
function messageForTransferRestriction(
uint8 restrictionCode
) external view override returns (string memory message) {
+ ValidationModuleInternalStorage storage $ = _getValidationModuleInternalStorage();
if (restrictionCode == uint8(REJECTED_CODE_BASE.TRANSFER_OK)) {
return TEXT_TRANSFER_OK;
} else if (
@@ -66,7 +75,7 @@ abstract contract ValidationModule is
uint8(REJECTED_CODE_BASE.TRANSFER_REJECTED_TO_FROZEN)
) {
return TEXT_TRANSFER_REJECTED_TO_FROZEN;
- } else if (address(ruleEngine) != address(0)) {
+ } else if (address($._ruleEngine) != address(0)) {
return _messageForTransferRestriction(restrictionCode);
} else {
return TEXT_UNKNOWN_CODE;
@@ -85,13 +94,14 @@ abstract contract ValidationModule is
address to,
uint256 amount
) public view override returns (uint8 code) {
+ ValidationModuleInternalStorage storage $ = _getValidationModuleInternalStorage();
if (paused()) {
return uint8(REJECTED_CODE_BASE.TRANSFER_REJECTED_PAUSED);
} else if (frozen(from)) {
return uint8(REJECTED_CODE_BASE.TRANSFER_REJECTED_FROM_FROZEN);
} else if (frozen(to)) {
return uint8(REJECTED_CODE_BASE.TRANSFER_REJECTED_TO_FROZEN);
- } else if (address(ruleEngine) != address(0)) {
+ } else if (address($._ruleEngine) != address(0)) {
return _detectTransferRestriction(from, to, amount);
} else {
return uint8(REJECTED_CODE_BASE.TRANSFER_OK);
@@ -106,12 +116,17 @@ abstract contract ValidationModule is
if (!_validateTransferByModule(from, to, amount)) {
return false;
}
- if (address(ruleEngine) != address(0)) {
+ ValidationModuleInternalStorage storage $ = _getValidationModuleInternalStorage();
+ if (address($._ruleEngine) != address(0)) {
return _validateTransfer(from, to, amount);
}
return true;
}
+
+ /*//////////////////////////////////////////////////////////////
+ INTERNAL/PRIVATE FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
function _validateTransferByModule(
address from,
address to,
@@ -127,11 +142,10 @@ abstract contract ValidationModule is
if (!_validateTransferByModule(from, to, amount)){
return false;
}
- if (address(ruleEngine) != address(0)) {
+ ValidationModuleInternalStorage storage $ = _getValidationModuleInternalStorage();
+ if (address($._ruleEngine) != address(0)) {
return ValidationModuleInternal._operateOnTransfer(from, to, amount);
}
return true;
}
-
- uint256[50] private __gap;
}
diff --git a/contracts/modules/wrapper/core/BaseModule.sol b/contracts/modules/wrapper/core/BaseModule.sol
index 1b2a3e86..b5bf3275 100644
--- a/contracts/modules/wrapper/core/BaseModule.sol
+++ b/contracts/modules/wrapper/core/BaseModule.sol
@@ -2,17 +2,17 @@
pragma solidity ^0.8.20;
-// required OZ imports here
import "../../security/AuthorizationModule.sol";
-import "../../../libraries/Errors.sol";
abstract contract BaseModule is AuthorizationModule {
+ /* ============ State Variables ============ */
/**
* @notice
* Get the current version of the smart contract
*/
- string public constant VERSION = "2.4.0";
- /* Events */
+ string public constant VERSION = "2.5.0";
+
+ /* ============ Events ============ */
event Term(string indexed newTermIndexed, string newTerm);
event TokenId(string indexed newTokenIdIndexed, string newTokenId);
event Information(
@@ -20,17 +20,17 @@ abstract contract BaseModule is AuthorizationModule {
string newInformation
);
event Flag(uint256 indexed newFlag);
+ /* ============ ERC-7201 ============ */
+ // keccak256(abi.encode(uint256(keccak256("CMTAT.storage.BaseModule")) - 1)) & ~bytes32(uint256(0xff))
+ bytes32 private constant BaseModuleStorageLocation = 0xa98e72f7f70574363edb12c42a03ac1feb8cc898a6e0a30f6eefbab7093e0d00;
- /* Variables */
- string public tokenId;
- string public terms;
- string public information;
- // additional attribute to store information as an uint256
- uint256 public flag;
-
-
-
- /* Initializers */
+ /* ==== ERC-7201 State Variables === */
+ struct BaseModuleStorage {
+ string _tokenId;
+ string _terms;
+ string _information;
+ }
+ /* ============ Initializer Function ============ */
/**
* @dev Sets the values for {name} and {symbol}.
*
@@ -40,23 +40,40 @@ abstract contract BaseModule is AuthorizationModule {
function __Base_init_unchained(
string memory tokenId_,
string memory terms_,
- string memory information_,
- uint256 flag_
+ string memory information_
) internal onlyInitializing {
- tokenId = tokenId_;
- terms = terms_;
- information = information_;
- flag = flag_;
+ BaseModuleStorage storage $ = _getBaseModuleStorage();
+ $._tokenId = tokenId_;
+ $._terms = terms_;
+ $._information = information_;
+ }
+
+ /*//////////////////////////////////////////////////////////////
+ PUBLIC/EXTERNAL FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+
+ function tokenId() public view virtual returns (string memory) {
+ BaseModuleStorage storage $ = _getBaseModuleStorage();
+ return $._tokenId;
+ }
+
+ function terms() public view virtual returns (string memory) {
+ BaseModuleStorage storage $ = _getBaseModuleStorage();
+ return $._terms;
+ }
+ function information() public view virtual returns (string memory) {
+ BaseModuleStorage storage $ = _getBaseModuleStorage();
+ return $._information;
}
- /* Methods */
/**
* @notice the tokenId will be changed even if the new value is the same as the current one
*/
function setTokenId(
string calldata tokenId_
) public onlyRole(DEFAULT_ADMIN_ROLE) {
- tokenId = tokenId_;
+ BaseModuleStorage storage $ = _getBaseModuleStorage();
+ $._tokenId = tokenId_;
emit TokenId(tokenId_, tokenId_);
}
@@ -66,7 +83,8 @@ abstract contract BaseModule is AuthorizationModule {
function setTerms(
string calldata terms_
) public onlyRole(DEFAULT_ADMIN_ROLE) {
- terms = terms_;
+ BaseModuleStorage storage $ = _getBaseModuleStorage();
+ $._terms = terms_;
emit Term(terms_, terms_);
}
@@ -76,20 +94,21 @@ abstract contract BaseModule is AuthorizationModule {
function setInformation(
string calldata information_
) public onlyRole(DEFAULT_ADMIN_ROLE) {
- information = information_;
+ BaseModuleStorage storage $ = _getBaseModuleStorage();
+ $._information = information_;
emit Information(information_, information_);
}
- /**
- * @notice The call will be reverted if the new value of flag is the same as the current one
- */
- function setFlag(uint256 flag_) public onlyRole(DEFAULT_ADMIN_ROLE) {
- if (flag == flag_) {
- revert Errors.CMTAT_BaseModule_SameValue();
+
+ /*//////////////////////////////////////////////////////////////
+ INTERNAL/PRIVATE FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+
+ /* ============ ERC-7201 ============ */
+ function _getBaseModuleStorage() private pure returns (BaseModuleStorage storage $) {
+ assembly {
+ $.slot := BaseModuleStorageLocation
}
- flag = flag_;
- emit Flag(flag_);
}
- uint256[50] private __gap;
}
diff --git a/contracts/modules/wrapper/core/ERC20BaseModule.sol b/contracts/modules/wrapper/core/ERC20BaseModule.sol
index ad0ee813..298e0b35 100644
--- a/contracts/modules/wrapper/core/ERC20BaseModule.sol
+++ b/contracts/modules/wrapper/core/ERC20BaseModule.sol
@@ -3,24 +3,35 @@
pragma solidity ^0.8.20;
// required OZ imports here
-import "../../../../openzeppelin-contracts-upgradeable/contracts/token/ERC20/ERC20Upgradeable.sol";
+import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import "../../../libraries/Errors.sol";
+/**
+ * @title ERC20Base module
+ * @dev
+ *
+ * Contains ERC-20 base functions and extension
+ * Inherits from ERC-20
+ *
+ */
abstract contract ERC20BaseModule is ERC20Upgradeable {
- /* Events */
+ /* ============ Events ============ */
/**
* @notice Emitted when the specified `spender` spends the specified `value` tokens owned by the specified `owner` reducing the corresponding allowance.
* @dev The allowance can be also "spend" with the function BurnFrom, but in this case, the emitted event is BurnFrom.
*/
event Spend(address indexed owner, address indexed spender, uint256 value);
+ /* ============ ERC-7201 ============ */
+ // keccak256(abi.encode(uint256(keccak256("CMTAT.storage.ERC20BaseModule")) - 1)) & ~bytes32(uint256(0xff))
+ bytes32 private constant ERC20BaseModuleStorageLocation = 0x9bd8d607565c0370ae5f91651ca67fd26d4438022bf72037316600e29e6a3a00;
+ /* ==== ERC-7201 State Variables === */
+ struct ERC20BaseModuleStorage {
+ uint8 _decimals;
+ }
- /* Variables */
- uint8 private _decimals;
-
- /* Initializers */
-
+ /* ============ Initializer Function ============ */
/**
- * @dev Sets the values for decimals.
+ * @dev Initializers: Sets the values for decimals.
*
* this value is immutable: it can only be set once during
* construction/initialization.
@@ -28,17 +39,20 @@ abstract contract ERC20BaseModule is ERC20Upgradeable {
function __ERC20BaseModule_init_unchained(
uint8 decimals_
) internal onlyInitializing {
- _decimals = decimals_;
+ ERC20BaseModuleStorage storage $ = _getERC20BaseModuleStorage();
+ $._decimals = decimals_;
}
-
- /* Methods */
+ /*//////////////////////////////////////////////////////////////
+ PUBLIC/EXTERNAL FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
/**
*
* @notice Returns the number of decimals used to get its user representation.
* @inheritdoc ERC20Upgradeable
*/
function decimals() public view virtual override returns (uint8) {
- return _decimals;
+ ERC20BaseModuleStorage storage $ = _getERC20BaseModuleStorage();
+ return $._decimals;
}
/**
@@ -110,5 +124,16 @@ abstract contract ERC20BaseModule is ERC20Upgradeable {
totalSupply = ERC20Upgradeable.totalSupply();
}
- uint256[50] private __gap;
+
+ /*//////////////////////////////////////////////////////////////
+ INTERNAL/PRIVATE FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+
+
+ /* ============ ERC-7201 ============ */
+ function _getERC20BaseModuleStorage() private pure returns (ERC20BaseModuleStorage storage $) {
+ assembly {
+ $.slot := ERC20BaseModuleStorageLocation
+ }
+ }
}
diff --git a/contracts/modules/wrapper/core/ERC20BurnModule.sol b/contracts/modules/wrapper/core/ERC20BurnModule.sol
index b1482e9c..0ff60bb8 100644
--- a/contracts/modules/wrapper/core/ERC20BurnModule.sol
+++ b/contracts/modules/wrapper/core/ERC20BurnModule.sol
@@ -2,12 +2,22 @@
pragma solidity ^0.8.20;
-import "../../../../openzeppelin-contracts-upgradeable/contracts/token/ERC20/ERC20Upgradeable.sol";
+import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import "../../security/AuthorizationModule.sol";
import "../../../interfaces/ICCIPToken.sol";
+
+/**
+ * @title ERC20Burn module.
+ * @dev
+ *
+ * Contains all burn functions, inherits from ERC-20
+ */
abstract contract ERC20BurnModule is ERC20Upgradeable, ICCIPBurnFromERC20, AuthorizationModule {
+ /* ============ State Variables ============ */
bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE");
bytes32 public constant BURNER_FROM_ROLE = keccak256("BURNER_FROM_ROLE");
+
+ /* ============ Events ============ */
/**
* @notice Emitted when the specified `value` amount of tokens owned by `owner`are destroyed with the given `reason`
*/
@@ -16,10 +26,17 @@ abstract contract ERC20BurnModule is ERC20Upgradeable, ICCIPBurnFromERC20, Autho
* @notice Emitted when the specified `spender` burns the specified `value` tokens owned by the specified `owner` reducing the corresponding allowance.
*/
event BurnFrom(address indexed owner, address indexed spender, uint256 value);
+
+
+ /* ============ Initializer Function ============ */
function __ERC20BurnModule_init_unchained() internal onlyInitializing {
// no variable to initialize
}
+ /*//////////////////////////////////////////////////////////////
+ PUBLIC/EXTERNAL FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+
/**
* @notice Destroys a `value` amount of tokens from `account`, by transferring it to address(0).
* @dev
@@ -109,6 +126,4 @@ abstract contract ERC20BurnModule is ERC20Upgradeable, ICCIPBurnFromERC20, Autho
// Specific event for the operation
emit BurnFrom(account, sender, value);
}
-
- uint256[50] private __gap;
}
diff --git a/contracts/modules/wrapper/core/ERC20MintModule.sol b/contracts/modules/wrapper/core/ERC20MintModule.sol
index 3fdafc82..4f6effa0 100644
--- a/contracts/modules/wrapper/core/ERC20MintModule.sol
+++ b/contracts/modules/wrapper/core/ERC20MintModule.sol
@@ -2,22 +2,35 @@
pragma solidity ^0.8.20;
-import "../../../../openzeppelin-contracts-upgradeable/contracts/token/ERC20/ERC20Upgradeable.sol";
+import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import "../../security/AuthorizationModule.sol";
import "../../../interfaces/ICCIPToken.sol";
+
+/**
+ * @title ERC20Mint module.
+ * @dev
+ *
+ * Contains all mint functions, inherits from ERC-20
+ */
abstract contract ERC20MintModule is ERC20Upgradeable, ICCIPMintERC20, AuthorizationModule {
- // MintModule
+ /* ============ State Variables ============ */
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
+ /* ============ Events ============ */
/**
* @notice Emitted when the specified `value` amount of new tokens are created and
* allocated to the specified `account`.
*/
event Mint(address indexed account, uint256 value);
+
+ /* ============ Initializer Function ============ */
function __ERC20MintModule_init_unchained() internal onlyInitializing {
// no variable to initialize
}
+ /*//////////////////////////////////////////////////////////////
+ PUBLIC/EXTERNAL FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
/**
* @notice Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0)
* @param account token receiver
@@ -69,6 +82,4 @@ abstract contract ERC20MintModule is ERC20Upgradeable, ICCIPMintERC20, Authoriza
emit Mint(accounts[i], values[i]);
}
}
-
- uint256[50] private __gap;
}
diff --git a/contracts/modules/wrapper/core/EnforcementModule.sol b/contracts/modules/wrapper/core/EnforcementModule.sol
index 80562be5..731b2757 100644
--- a/contracts/modules/wrapper/core/EnforcementModule.sol
+++ b/contracts/modules/wrapper/core/EnforcementModule.sol
@@ -6,7 +6,8 @@ import "../../security/AuthorizationModule.sol";
import "../../internal/EnforcementModuleInternal.sol";
/**
- * @dev Enforcement module.
+ * @title Enforcement module.
+ * @dev
*
* Allows the issuer to freeze transfers from a given address
*/
@@ -14,7 +15,7 @@ abstract contract EnforcementModule is
EnforcementModuleInternal,
AuthorizationModule
{
- // EnforcementModule
+ /* ============ State Variables ============ */
bytes32 public constant ENFORCER_ROLE = keccak256("ENFORCER_ROLE");
string internal constant TEXT_TRANSFER_REJECTED_FROM_FROZEN =
"Address FROM is frozen";
@@ -22,10 +23,14 @@ abstract contract EnforcementModule is
string internal constant TEXT_TRANSFER_REJECTED_TO_FROZEN =
"Address TO is frozen";
+ /* ============ Initializer Function ============ */
function __EnforcementModule_init_unchained() internal onlyInitializing {
// no variable to initialize
}
+ /*//////////////////////////////////////////////////////////////
+ PUBLIC/EXTERNAL FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
/**
* @notice Freezes an address.
* @param account the account to freeze
@@ -51,6 +56,4 @@ abstract contract EnforcementModule is
) public onlyRole(ENFORCER_ROLE) returns (bool) {
return _unfreeze(account, reason);
}
-
- uint256[50] private __gap;
}
diff --git a/contracts/modules/wrapper/core/PauseModule.sol b/contracts/modules/wrapper/core/PauseModule.sol
index b94b9973..77a55c49 100644
--- a/contracts/modules/wrapper/core/PauseModule.sol
+++ b/contracts/modules/wrapper/core/PauseModule.sol
@@ -2,12 +2,13 @@
pragma solidity ^0.8.20;
-import "../../../../openzeppelin-contracts-upgradeable/contracts/utils/PausableUpgradeable.sol";
+import "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
import "../../security/AuthorizationModule.sol";
/**
- *
- * @dev Put in pause or deactivate the contract
+ * @title Pause Module
+ * @dev
+ * Put in pause or deactivate the contract
* The issuer must be able to “pause” the smart contract,
* to prevent execution of transactions on the distributed ledger until the issuer puts an end to the pause.
*
@@ -16,17 +17,27 @@ import "../../security/AuthorizationModule.sol";
* event of a large bug.
*/
abstract contract PauseModule is PausableUpgradeable, AuthorizationModule {
- // PauseModule
+ /* ============ State Variables ============ */
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
string internal constant TEXT_TRANSFER_REJECTED_PAUSED =
"All transfers paused";
- bool private isDeactivated;
+ /* ============ Events ============ */
event Deactivated(address account);
-
+ /* ============ ERC-7201 ============ */
+ // keccak256(abi.encode(uint256(keccak256("CMTAT.storage.ERC20BaseModule")) - 1)) & ~bytes32(uint256(0xff))
+ bytes32 private constant PauseModuleStorageLocation = 0x9bd8d607565c0370ae5f91651ca67fd26d4438022bf72037316600e29e6a3a00;
+ /* ==== ERC-7201 State Variables === */
+ struct PauseModuleStorage {
+ bool _isDeactivated;
+ }
+ /* ============ Initializer Function ============ */
function __PauseModule_init_unchained() internal onlyInitializing {
// no variable to initialize
}
-
+
+ /*//////////////////////////////////////////////////////////////
+ PUBLIC/EXTERNAL FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
/**
* @notice Pauses all token transfers.
* @dev See {ERC20Pausable} and {Pausable-_pause}.
@@ -49,7 +60,8 @@ abstract contract PauseModule is PausableUpgradeable, AuthorizationModule {
* - the caller must have the `PAUSER_ROLE`.
*/
function unpause() public onlyRole(PAUSER_ROLE) {
- if(isDeactivated){
+ PauseModuleStorage storage $ = _getPauseModuleStorage();
+ if($._isDeactivated){
revert Errors.CMTAT_PauseModule_ContractIsDeactivated();
}
_unpause();
@@ -68,7 +80,8 @@ abstract contract PauseModule is PausableUpgradeable, AuthorizationModule {
public
onlyRole(DEFAULT_ADMIN_ROLE)
{
- isDeactivated = true;
+ PauseModuleStorage storage $ = _getPauseModuleStorage();
+ $._isDeactivated = true;
_pause();
emit Deactivated(_msgSender());
}
@@ -77,8 +90,20 @@ abstract contract PauseModule is PausableUpgradeable, AuthorizationModule {
* @notice Returns true if the contract is deactivated, and false otherwise.
*/
function deactivated() view public returns (bool){
- return isDeactivated;
+ PauseModuleStorage storage $ = _getPauseModuleStorage();
+ return $._isDeactivated;
}
- uint256[50] private __gap;
+
+ /*//////////////////////////////////////////////////////////////
+ INTERNAL/PRIVATE FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+
+
+ /* ============ ERC-7201 ============ */
+ function _getPauseModuleStorage() private pure returns (PauseModuleStorage storage $) {
+ assembly {
+ $.slot := PauseModuleStorageLocation
+ }
+ }
}
diff --git a/contracts/modules/wrapper/extensions/DebtModule.sol b/contracts/modules/wrapper/extensions/DebtModule.sol
new file mode 100644
index 00000000..389a012f
--- /dev/null
+++ b/contracts/modules/wrapper/extensions/DebtModule.sol
@@ -0,0 +1,100 @@
+//SPDX-License-Identifier: MPL-2.0
+
+pragma solidity ^0.8.20;
+
+import "../../security/AuthorizationModule.sol";
+import "../../../libraries/Errors.sol";
+import "../../../interfaces/engine/IDebtEngine.sol";
+
+/**
+ * @title Debt module
+ * @dev
+ *
+ * Retrieve debt and creditEvents information from a debtEngine
+ */
+abstract contract DebtModule is AuthorizationModule, IDebtEngine {
+ /* ============ State Variables ============ */
+ bytes32 public constant DEBT_ROLE = keccak256("DEBT_ROLE");
+ /* ============ ERC-7201 ============ */
+ // keccak256(abi.encode(uint256(keccak256("CMTAT.storage.DebtModule")) - 1)) & ~bytes32(uint256(0xff))
+ bytes32 private constant DebtModuleStorageLocation = 0xf8a315cc5f2213f6481729acd86e55db7ccc930120ccf9fb78b53dcce75f7c00;
+
+ /* ==== ERC-7201 State Variables === */
+ struct DebtModuleStorage {
+ IDebtEngine _debtEngine;
+ }
+ /* ============ Events ============ */
+ /**
+ * @dev Emitted when a rule engine is set.
+ */
+ event DebtEngine(IDebtEngine indexed newDebtEngine);
+
+
+ /* ============ Initializer Function ============ */
+ /**
+ * @dev
+ *
+ * - The grant to the admin role is done by AccessControlDefaultAdminRules
+ * - The control of the zero address is done by AccessControlDefaultAdminRules
+ *
+ */
+ function __DebtModule_init_unchained(IDebtEngine debtEngine_)
+ internal onlyInitializing {
+ if (address(debtEngine_) != address (0)) {
+ DebtModuleStorage storage $ = _getDebtModuleStorage();
+ $._debtEngine = debtEngine_;
+ emit DebtEngine(debtEngine_);
+ }
+
+
+ }
+ /*//////////////////////////////////////////////////////////////
+ PUBLIC/EXTERNAL FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+ function debtEngine() public view virtual returns (IDebtEngine) {
+ DebtModuleStorage storage $ = _getDebtModuleStorage();
+ return $._debtEngine;
+ }
+
+ /*
+ * @notice set an authorizationEngine if not already set
+ *
+ */
+ function setDebtEngine(
+ IDebtEngine debtEngine_
+ ) external onlyRole(DEBT_ROLE) {
+ DebtModuleStorage storage $ = _getDebtModuleStorage();
+ if ($._debtEngine == debtEngine_){
+ revert Errors.CMTAT_DebtModule_SameValue();
+ }
+ $._debtEngine = debtEngine_;
+ emit DebtEngine(debtEngine_);
+ }
+
+ function debt() public view returns(DebtBase memory debtBaseResult){
+ DebtModuleStorage storage $ = _getDebtModuleStorage();
+ if(address($._debtEngine) != address(0)){
+ debtBaseResult = $._debtEngine.debt();
+ }
+ }
+
+ function creditEvents() public view returns(CreditEvents memory creditEventsResult){
+ DebtModuleStorage storage $ = _getDebtModuleStorage();
+ if(address($._debtEngine) != address(0)){
+ creditEventsResult = $._debtEngine.creditEvents();
+ }
+ }
+
+
+ /*//////////////////////////////////////////////////////////////
+ INTERNAL/PRIVATE FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+
+ /* ============ ERC-7201 ============ */
+ function _getDebtModuleStorage() private pure returns (DebtModuleStorage storage $) {
+ assembly {
+ $.slot := DebtModuleStorageLocation
+ }
+ }
+
+}
diff --git a/contracts/modules/wrapper/extensions/DebtModule/CreditEventsModule.sol b/contracts/modules/wrapper/extensions/DebtModule/CreditEventsModule.sol
deleted file mode 100644
index 1c878936..00000000
--- a/contracts/modules/wrapper/extensions/DebtModule/CreditEventsModule.sol
+++ /dev/null
@@ -1,84 +0,0 @@
-//SPDX-License-Identifier: MPL-2.0
-
-pragma solidity ^0.8.20;
-
-import "../../../../../openzeppelin-contracts-upgradeable/contracts/access/AccessControlUpgradeable.sol";
-import "../../../../../openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol";
-import "../../../../interfaces/IDebtGlobal.sol";
-import "../../../security/AuthorizationModule.sol";
-
-import "../../../../libraries/Errors.sol";
-
-abstract contract CreditEventsModule is
- IDebtGlobal,
- Initializable,
- ContextUpgradeable,
- AuthorizationModule
-{
- // CreditEvents
- bytes32 public constant DEBT_CREDIT_EVENT_ROLE =
- keccak256("DEBT_CREDIT_EVENT_ROLE");
- CreditEvents public creditEvents;
-
- /* Events */
- event FlagDefault(bool indexed newFlagDefault);
- event FlagRedeemed(bool indexed newFlagRedeemed);
- event Rating(string indexed newRatingIndexed, string newRating);
-
- function __CreditEvents_init_unchained() internal onlyInitializing {
- // no variable to initialize
- }
-
- /**
- * @notice Set all attributes of creditEvents
- * The values of all attributes will be changed even if the new values are the same as the current ones
- */
- function setCreditEvents(
- bool flagDefault_,
- bool flagRedeemed_,
- string calldata rating_
- ) public onlyRole(DEBT_CREDIT_EVENT_ROLE) {
- creditEvents = (CreditEvents(flagDefault_, flagRedeemed_, rating_));
- emit FlagDefault(flagDefault_);
- emit FlagRedeemed(flagRedeemed_);
- emit Rating(rating_, rating_);
- }
-
- /**
- * @notice The call will be reverted if the new value of flagDefault is the same as the current one
- */
- function setFlagDefault(
- bool flagDefault_
- ) public onlyRole(DEBT_CREDIT_EVENT_ROLE) {
- if (flagDefault_ == creditEvents.flagDefault) {
- revert Errors.CMTAT_DebtModule_SameValue();
- }
- creditEvents.flagDefault = flagDefault_;
- emit FlagDefault(flagDefault_);
- }
-
- /**
- * @notice The call will be reverted if the new value of flagRedeemed is the same as the current one
- */
- function setFlagRedeemed(
- bool flagRedeemed_
- ) public onlyRole(DEBT_CREDIT_EVENT_ROLE) {
- if (flagRedeemed_ == creditEvents.flagRedeemed) {
- revert Errors.CMTAT_DebtModule_SameValue();
- }
- creditEvents.flagRedeemed = flagRedeemed_;
- emit FlagRedeemed(flagRedeemed_);
- }
-
- /**
- * @notice The rating will be changed even if the new value is the same as the current one
- */
- function setRating(
- string calldata rating_
- ) public onlyRole(DEBT_CREDIT_EVENT_ROLE) {
- creditEvents.rating = rating_;
- emit Rating(rating_, rating_);
- }
-
- uint256[50] private __gap;
-}
diff --git a/contracts/modules/wrapper/extensions/DebtModule/DebtBaseModule.sol b/contracts/modules/wrapper/extensions/DebtModule/DebtBaseModule.sol
deleted file mode 100644
index 62117776..00000000
--- a/contracts/modules/wrapper/extensions/DebtModule/DebtBaseModule.sol
+++ /dev/null
@@ -1,233 +0,0 @@
-//SPDX-License-Identifier: MPL-2.0
-
-pragma solidity ^0.8.20;
-
-import "../../../../../openzeppelin-contracts-upgradeable/contracts/access/AccessControlUpgradeable.sol";
-import "../../../../../openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol";
-import "../../../../interfaces/IDebtGlobal.sol";
-import "../../../security/AuthorizationModule.sol";
-
-import "../../../../libraries/Errors.sol";
-
-abstract contract DebtBaseModule is
- IDebtGlobal,
- Initializable,
- ContextUpgradeable,
- AuthorizationModule
-{
- // DebtModule
- bytes32 public constant DEBT_ROLE = keccak256("DEBT_ROLE");
- DebtBase public debt;
-
- /* Events */
- event InterestRate(uint256 newInterestRate);
- event ParValue(uint256 newParValue);
- event Guarantor(string indexed newGuarantorIndexed, string newGuarantor);
- event BondHolder(string indexed newBondHolderIndexed, string newBondHolder);
- event MaturityDate(
- string indexed newMaturityDateIndexed,
- string newMaturityDate
- );
- event InterestScheduleFormat(
- string indexed newInterestScheduleFormatIndexed,
- string newInterestScheduleFormat
- );
- event InterestPaymentDate(
- string indexed newInterestPaymentDateIndexed,
- string newInterestPaymentDate
- );
- event DayCountConvention(
- string indexed newDayCountConventionIndexed,
- string newDayCountConvention
- );
- event BusinessDayConvention(
- string indexed newBusinessDayConventionIndexed,
- string newBusinessDayConvention
- );
- event PublicHolidaysCalendar(
- string indexed newPublicHolidaysCalendarIndexed,
- string newPublicHolidaysCalendar
- );
- event IssuanceDate(
- string indexed newIssuanceDateIndexed,
- string newIssuanceDate
- );
- event CouponFrequency(
- string indexed newCouponFrequencyIndexed,
- string newCouponFrequency
- );
-
- function __DebtBaseModule_init_unchained() internal onlyInitializing {
- // no variable to initialize
- }
-
- /**
- * @notice Set all attributes of debt
- * The values of all attributes will be changed even if the new values are the same as the current ones
- */
- function setDebt(DebtBase calldata debt_) public onlyRole(DEBT_ROLE) {
- debt = debt_;
- emit InterestRate(debt_.interestRate);
- emit ParValue(debt_.parValue);
- emit Guarantor(debt_.guarantor, debt_.guarantor);
- emit BondHolder(debt_.bondHolder, debt_.bondHolder);
- emit MaturityDate(debt_.maturityDate, debt_.maturityDate);
- emit InterestScheduleFormat(
- debt_.interestScheduleFormat,
- debt_.interestScheduleFormat
- );
- emit InterestPaymentDate(
- debt_.interestPaymentDate,
- debt_.interestPaymentDate
- );
- emit DayCountConvention(
- debt_.dayCountConvention,
- debt_.dayCountConvention
- );
- emit BusinessDayConvention(
- debt_.businessDayConvention,
- debt_.businessDayConvention
- );
- emit PublicHolidaysCalendar(
- debt_.publicHolidaysCalendar,
- debt_.publicHolidaysCalendar
- );
-
- emit IssuanceDate(debt_.issuanceDate, debt_.issuanceDate);
-
- emit CouponFrequency(debt_.couponFrequency, debt_.couponFrequency);
- }
-
- /**
- * @notice The call will be reverted if the new value of interestRate is the same as the current one
- */
- function setInterestRate(uint256 interestRate_) public onlyRole(DEBT_ROLE) {
- if (interestRate_ == debt.interestRate) {
- revert Errors.CMTAT_DebtModule_SameValue();
- }
- debt.interestRate = interestRate_;
- emit InterestRate(interestRate_);
- }
-
- /**
- * @notice The call will be reverted if the new value of parValue is the same as the current one
- */
- function setParValue(uint256 parValue_) public onlyRole(DEBT_ROLE) {
- if (parValue_ == debt.parValue) {
- revert Errors.CMTAT_DebtModule_SameValue();
- }
- debt.parValue = parValue_;
- emit ParValue(parValue_);
- }
-
- /**
- * @notice The Guarantor will be changed even if the new value is the same as the current one
- */
- function setGuarantor(
- string calldata guarantor_
- ) public onlyRole(DEBT_ROLE) {
- debt.guarantor = guarantor_;
- emit Guarantor(guarantor_, guarantor_);
- }
-
- /**
- * @notice The bonHolder will be changed even if the new value is the same as the current one
- */
- function setBondHolder(
- string calldata bondHolder_
- ) public onlyRole(DEBT_ROLE) {
- debt.bondHolder = bondHolder_;
- emit BondHolder(bondHolder_, bondHolder_);
- }
-
- /**
- * @notice The maturityDate will be changed even if the new value is the same as the current one
- */
- function setMaturityDate(
- string calldata maturityDate_
- ) public onlyRole(DEBT_ROLE) {
- debt.maturityDate = maturityDate_;
- emit MaturityDate(maturityDate_, maturityDate_);
- }
-
- /**
- * @notice The interestScheduleFormat will be changed even if the new value is the same as the current one
- */
- function setInterestScheduleFormat(
- string calldata interestScheduleFormat_
- ) public onlyRole(DEBT_ROLE) {
- debt.interestScheduleFormat = interestScheduleFormat_;
- emit InterestScheduleFormat(
- interestScheduleFormat_,
- interestScheduleFormat_
- );
- }
-
- /**
- * @notice The interestPaymentDate will be changed even if the new value is the same as the current one
- */
- function setInterestPaymentDate(
- string calldata interestPaymentDate_
- ) public onlyRole(DEBT_ROLE) {
- debt.interestPaymentDate = interestPaymentDate_;
- emit InterestPaymentDate(interestPaymentDate_, interestPaymentDate_);
- }
-
- /**
- * @notice The dayCountConvention will be changed even if the new value is the same as the current one
- */
- function setDayCountConvention(
- string calldata dayCountConvention_
- ) public onlyRole(DEBT_ROLE) {
- debt.dayCountConvention = dayCountConvention_;
- emit DayCountConvention(dayCountConvention_, dayCountConvention_);
- }
-
- /**
- * @notice The businessDayConvention will be changed even if the new value is the same as the current one
- */
- function setBusinessDayConvention(
- string calldata businessDayConvention_
- ) public onlyRole(DEBT_ROLE) {
- debt.businessDayConvention = businessDayConvention_;
- emit BusinessDayConvention(
- businessDayConvention_,
- businessDayConvention_
- );
- }
-
- /**
- * @notice The publicHolidayCalendar will be changed even if the new value is the same as the current one
- */
- function setPublicHolidaysCalendar(
- string calldata publicHolidaysCalendar_
- ) public onlyRole(DEBT_ROLE) {
- debt.publicHolidaysCalendar = publicHolidaysCalendar_;
- emit PublicHolidaysCalendar(
- publicHolidaysCalendar_,
- publicHolidaysCalendar_
- );
- }
-
- /**
- * @notice The issuanceDate will be changed even if the new value is the same as the current one
- */
- function setIssuanceDate(
- string calldata issuanceDate_
- ) public onlyRole(DEBT_ROLE) {
- debt.issuanceDate = issuanceDate_;
- emit IssuanceDate(issuanceDate_, issuanceDate_);
- }
-
- /**
- * @notice The couponFrequency will be changed even if the new value is the same as the current one
- */
- function setCouponFrequency(
- string calldata couponFrequency_
- ) public onlyRole(DEBT_ROLE) {
- debt.couponFrequency = couponFrequency_;
- emit CouponFrequency(couponFrequency_, couponFrequency_);
- }
-
- uint256[50] private __gap;
-}
diff --git a/contracts/modules/wrapper/extensions/DocumentModule.sol b/contracts/modules/wrapper/extensions/DocumentModule.sol
new file mode 100644
index 00000000..e763a12d
--- /dev/null
+++ b/contracts/modules/wrapper/extensions/DocumentModule.sol
@@ -0,0 +1,101 @@
+//SPDX-License-Identifier: MPL-2.0
+
+pragma solidity ^0.8.20;
+
+import "../../security/AuthorizationModule.sol";
+import "../../../libraries/Errors.sol";
+import "../../../interfaces/engine/draft-IERC1643.sol";
+
+
+/**
+ * @title Document module
+ * @dev
+ *
+ * Retrieve documents from a documentEngine
+ */
+
+abstract contract DocumentModule is AuthorizationModule, IERC1643 {
+ /* ============ Events ============ */
+ /**
+ * @dev Emitted when a rule engine is set.
+ */
+ event DocumentEngine(IERC1643 indexed newDocumentEngine);
+
+ /* ============ ERC-7201 ============ */
+ bytes32 public constant DOCUMENT_ROLE = keccak256("DOCUMENT_ROLE");
+ // keccak256(abi.encode(uint256(keccak256("CMTAT.storage.DocumentModule")) - 1)) & ~bytes32(uint256(0xff))
+ bytes32 private constant DocumentModuleStorageLocation = 0x5edcb2767f407e647b6a4171ef53e8015a3eff0bb2b6e7765b1a26332bc43000;
+ /* ==== ERC-7201 State Variables === */
+ struct DocumentModuleStorage {
+ IERC1643 _documentEngine;
+ }
+
+ /* ============ Initializer Function ============ */
+ /**
+ * @dev
+ *
+ * - The grant to the admin role is done by AccessControlDefaultAdminRules
+ * - The control of the zero address is done by AccessControlDefaultAdminRules
+ *
+ */
+ function __DocumentModule_init_unchained(IERC1643 documentEngine_)
+ internal onlyInitializing {
+ if (address(documentEngine_) != address (0)) {
+ DocumentModuleStorage storage $ = _getDocumentModuleStorage();
+ $._documentEngine = documentEngine_;
+ emit DocumentEngine(documentEngine_);
+ }
+ }
+
+ /*//////////////////////////////////////////////////////////////
+ PUBLIC/EXTERNAL FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+ function documentEngine() public view virtual returns (IERC1643) {
+ DocumentModuleStorage storage $ = _getDocumentModuleStorage();
+ return $._documentEngine;
+ }
+
+ /*
+ * @notice set an authorizationEngine if not already set
+ *
+ */
+ function setDocumentEngine(
+ IERC1643 documentEngine_
+ ) external onlyRole(DOCUMENT_ROLE) {
+ DocumentModuleStorage storage $ = _getDocumentModuleStorage();
+ if ($._documentEngine == documentEngine_){
+ revert Errors.CMTAT_DocumentModule_SameValue();
+ }
+ $._documentEngine = documentEngine_;
+ emit DocumentEngine(documentEngine_);
+ }
+
+
+ function getDocument(bytes32 _name) public view returns (string memory, bytes32, uint256){
+ DocumentModuleStorage storage $ = _getDocumentModuleStorage();
+ if(address($._documentEngine) != address(0)){
+ return $._documentEngine.getDocument( _name);
+ } else{
+ return ("",0x0, 0);
+ }
+ }
+
+ function getAllDocuments() public view returns (bytes32[] memory documents){
+ DocumentModuleStorage storage $ = _getDocumentModuleStorage();
+ if(address($._documentEngine) != address(0)){
+ documents = $._documentEngine.getAllDocuments();
+ }
+ }
+
+
+ /*//////////////////////////////////////////////////////////////
+ INTERNAL/PRIVATE FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+
+ /* ============ ERC-7201 ============ */
+ function _getDocumentModuleStorage() private pure returns (DocumentModuleStorage storage $) {
+ assembly {
+ $.slot := DocumentModuleStorageLocation
+ }
+ }
+}
diff --git a/contracts/modules/wrapper/extensions/ERC20SnapshotModule.sol b/contracts/modules/wrapper/extensions/ERC20SnapshotModule.sol
index b7142fb5..df1870cf 100644
--- a/contracts/modules/wrapper/extensions/ERC20SnapshotModule.sol
+++ b/contracts/modules/wrapper/extensions/ERC20SnapshotModule.sol
@@ -6,7 +6,8 @@ import "../../security/AuthorizationModule.sol";
import "../../internal/ERC20SnapshotModuleInternal.sol";
/**
- * @dev Snapshot module.
+ * @title Snapshot module
+ * @dev
*
* Useful to take a snapshot of token holder balance and total supply at a specific time
*/
@@ -15,12 +16,15 @@ abstract contract ERC20SnapshotModule is
ERC20SnapshotModuleInternal,
AuthorizationModule
{
- // SnapshotModule
+ /* ============ State Variables ============ */
bytes32 public constant SNAPSHOOTER_ROLE = keccak256("SNAPSHOOTER_ROLE");
+ /* ============ Initializer Function ============ */
function __ERC20SnasphotModule_init_unchained() internal onlyInitializing {
// no variable to initialize
}
-
+ /*//////////////////////////////////////////////////////////////
+ PUBLIC/EXTERNAL FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
/**
* @notice
* Schedule a snapshot at the given time specified as a number of seconds since epoch.
@@ -73,6 +77,4 @@ abstract contract ERC20SnapshotModule is
) public onlyRole(SNAPSHOOTER_ROLE) {
_unscheduleSnapshotNotOptimized(time);
}
-
- uint256[50] private __gap;
}
diff --git a/contracts/modules/wrapper/extensions/MetaTxModule.sol b/contracts/modules/wrapper/extensions/MetaTxModule.sol
index 3df45f74..2732069f 100644
--- a/contracts/modules/wrapper/extensions/MetaTxModule.sol
+++ b/contracts/modules/wrapper/extensions/MetaTxModule.sol
@@ -2,10 +2,11 @@
pragma solidity ^0.8.20;
-import "../../../../openzeppelin-contracts-upgradeable/contracts/metatx/ERC2771ContextUpgradeable.sol";
+import "@openzeppelin/contracts-upgradeable/metatx/ERC2771ContextUpgradeable.sol";
/**
- * @dev Meta transaction (gasless) module.
+ * @title Meta transaction (gasless) module.
+ * @dev
*
* Useful for to provide UX where the user does not pay gas for token exchange
* To follow OpenZeppelin, this contract does not implement the functions init & init_unchained.
@@ -18,6 +19,4 @@ abstract contract MetaTxModule is ERC2771ContextUpgradeable {
) ERC2771ContextUpgradeable(trustedForwarder) {
// Nothing to do
}
-
- uint256[50] private __gap;
}
diff --git a/contracts/test/proxy/CMTAT_PROXY.sol b/contracts/test/proxy/CMTAT_PROXY_TEST.sol
similarity index 94%
rename from contracts/test/proxy/CMTAT_PROXY.sol
rename to contracts/test/proxy/CMTAT_PROXY_TEST.sol
index ef35898f..fccfc680 100644
--- a/contracts/test/proxy/CMTAT_PROXY.sol
+++ b/contracts/test/proxy/CMTAT_PROXY_TEST.sol
@@ -4,6 +4,7 @@ pragma solidity ^0.8.20;
import "../../CMTAT_PROXY.sol";
+
/**
* @title a contrat used to test the proxy upgrade functionality
*/
@@ -18,6 +19,4 @@ contract CMTAT_PROXY_TEST is CMTAT_PROXY {
) CMTAT_PROXY(forwarderIrrevocable) {
// Nothing to do
}
-
- uint256[50] private __gap;
}
diff --git a/contracts/test/proxy/CMTAT_PROXY_TEST_UUPS.sol b/contracts/test/proxy/CMTAT_PROXY_TEST_UUPS.sol
new file mode 100644
index 00000000..16f7ee5e
--- /dev/null
+++ b/contracts/test/proxy/CMTAT_PROXY_TEST_UUPS.sol
@@ -0,0 +1,22 @@
+//SPDX-License-Identifier: MPL-2.0
+
+pragma solidity ^0.8.20;
+
+import "../../CMTAT_PROXY_UUPS.sol";
+
+
+/**
+ * @title a contrat used to test the proxy upgrade functionality
+ */
+contract CMTAT_PROXY_TEST_UUPS is CMTAT_PROXY_UUPS {
+ /**
+ * @notice Contract version for the deployment with a proxy
+ * @param forwarderIrrevocable address of the forwarder, required for the gasless support
+ */
+ /// @custom:oz-upgrades-unsafe-allow constructor
+ constructor(
+ address forwarderIrrevocable
+ ) CMTAT_PROXY_UUPS(forwarderIrrevocable) {
+ // Nothing to do
+ }
+}
diff --git a/doc/TOOLCHAIN.md b/doc/TOOLCHAIN.md
index 8d829fab..03b64792 100644
--- a/doc/TOOLCHAIN.md
+++ b/doc/TOOLCHAIN.md
@@ -18,18 +18,6 @@ Library used for the tests
**[Coveralls](https://coveralls.io/)**
It is used to perform a code coverage
-#### Truffle
-
-**[Truffle](https://trufflesuite.com/)**
-A development environment, testing framework and asset pipeline for blockchains using the Ethereum Virtual Machine (EVM).
-
-**[Truffle Flattener](https://www.npmjs.com/package/truffle-flattener)**
-Concats solidity files from Truffle projects with all of their dependencies.
-
-**[truffle-contract-size](https://www.npmjs.com/package/truffle-contract-size)**
-
-This [Truffle](https://www.trufflesuite.com/docs/truffle/overview) plugin displays the contract size of all or a selection of your smart contracts in kilobytes.
-
#### Nomiclabs - Hardhat
**[hardhat-truffle5](https://hardhat.org/hardhat-runner/plugins/nomiclabs-hardhat-truffle5)**
@@ -113,9 +101,6 @@ Use by `openzeppelin-contracts-upgradeable/test/helpers/eip712`imported in `Meta
**[solc](https://github.com/ethereum/solc-js)**
JavaScript bindings for the Solidity compiler.
-**[Web3](https://github.com/web3/web3.js)**
-Ethereum JavaScript API.
-
#### Documentation
**[sol2uml](https://github.com/naddison36/sol2uml)**
@@ -145,8 +130,7 @@ Loads environment variables from a .env file
This section concerns the packages installed in the section `dependencies` of package.json
-**[ethereumjs-wallet](https://www.npmjs.com/package/ethereumjs-wallet)**
-A wallet implementation
+
## Submodule
diff --git a/doc/USAGE.md b/doc/USAGE.md
index b0404e66..13999bdf 100644
--- a/doc/USAGE.md
+++ b/doc/USAGE.md
@@ -8,16 +8,12 @@ The toolchain includes the following components, where the versions
are the latest ones that we tested:
- npm 10.2.5
-- Hardhat-web3 2.0.0
-- *Truffle 5.9.3 [depreciated]*
-- Solidity 0.8.22 (via solc-js)
+- Hardhat ^2.22.7
+- Solidity 0.8.27 (via solc-js)
- Node 20.5.0
-- Web3.js 1.9.0
-- OpenZeppelin
- - OpenZeppelin Contracts Upgradeable (submodule) [v5.0.2](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/releases/tag/v5.0.2)
- - OpenZeppelin Contracts (Node.js module) [v5.0.2](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v5.0.2)
- - Reason n°1: libraries and interfaces are no longer available inside the upgradeable version since the version v5.0.0.
- - Reason n°2: It is not installed as a github submodule because it will create conflicts with the imports inside OpenZeppelin which use the Node.js version.
+- OpenZeppelin Contracts (Node.js module) [v5.0.2](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v5.0.2)
+- OpenZeppelin Contracts Upgradeable (Node.js module) [v5.0.2](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/releases/tag/v5.0.2)
+- Test: OpenZeppelin Contracts Upgradeable (submodule) [v5.0.2](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/releases/tag/v5.0.2)
## Installation
@@ -44,35 +40,22 @@ To install the node modules required by CMTAT, run the following command at the
### Hardhat
-> Since the version v2.3.1, Hardhat is our main development tool and replace Truffle. The reason behind this change is the fact that Truffle does not support custom errors for testing.
+> Since the [sunset of Truffle](https://consensys.io/blog/consensys-announces-the-sunset-of-truffle-and-ganache-and-new-hardhat) by Consensys ,Hardhat is our main development tool and replace Truffle.
To use Hardhat, the recommended way is to use the version installed as
part of the node modules, via the `npx` command:
`npx hardhat`
-Alternatively, you can install Truffle [globally](https://trufflesuite.com/docs/truffle/getting-started/installation/):
+Alternatively, you can install Hardhat [globally](https://hardhat.org/hardhat-runner/docs/getting-started):
`npm install -g hardhat`
See Hardhat's official [documentation](https://hardhat.org) for more information.
-### Truffle [partially depreciated]
-
-> Truffle can still be used to compile the contracts but you can no longer use it to run the tests.
-
-To use Truffle, the recommended way is to use the version installed as
-part of the node modules, via the `npx` command:
-
-`npx truffle`
-
-Alternatively, you can install Truffle [globally](https://trufflesuite.com/docs/truffle/getting-started/installation/):
-
-`npm install -g truffle`
-
-See Truffle's official [documentation](https://trufflesuite.com/docs/truffle/getting-started/installation/) for more information.
-
+### Truffle [depreciated]
+Truffle is no longer supported since it has been sunset by Consensys, see [Consensys Announces the Sunset of Truffle and Ganache and New Hardhat Partnership](https://consensys.io/blog/consensys-announces-the-sunset-of-truffle-and-ganache-and-new-hardhat)
## Contract size
@@ -81,7 +64,6 @@ You can get the size of the contract by running the following commands.
- Compile the contracts:
```bash
-npx truffle compile
npx hardhat compile
```
@@ -89,10 +71,9 @@ npx hardhat compile
```bash
npm run-script size
-npm run-script hardhat:size
```
-The script calls the plugin `truffle-contract-size` for Truffle or [hardhat-contract-sizer](https://www.npmjs.com/package/hardhat-contract-sizer) with Hardhat.
+The script calls the plugin [hardhat-contract-sizer](https://www.npmjs.com/package/hardhat-contract-sizer) with Hardhat.
## Testing
@@ -102,23 +83,7 @@ Tests are written in JavaScript by using [web3js](https://web3js.readthedocs.io/
To use the global hardhat install, use instead `hardhat test`.
-Please see the Truffle [JavaScript tests documentation](https://www.trufflesuite.com/docs/truffle/testing/writing-tests-in-javascript) for more information about the writing and running of Truffle tests since the tests were originally written for Truffle.
-
-
-
-[**Depreciated** since the version v2.3.21]
-
-> Since the version v2.3.1, it is no longer possible to run tests with Truffle.
->
-> Truffle does not support custom errors for testing.
-
-Tests are written in JavaScript and run with Truffle as follows:
-
-`npx truffle test`
-
-To use the global Truffle install, use instead `truffle test`.
-
-Please see the Truffle [JavaScript tests documentation](https://www.trufflesuite.com/docs/truffle/testing/writing-tests-in-javascript) for more information about the writing and running of Truffle tests.
+Please see the Hardhat [documentation](https://hardhat.org/tutorial/testing-contracts) for more information about the writing and running of Hardhat.
## Code style guidelines
diff --git a/doc/audits/tools/slither-report-v2.4.0.md b/doc/audits/tools/slither-report-v2.4.0.md
new file mode 100644
index 00000000..414e0e42
--- /dev/null
+++ b/doc/audits/tools/slither-report-v2.4.0.md
@@ -0,0 +1,710 @@
+**THIS CHECKLIST IS NOT COMPLETE**. Use `--show-ignored-findings` to show all the results.
+Summary
+ - [shadowing-state](#shadowing-state) (1 results) (High)
+ - [reentrancy-no-eth](#reentrancy-no-eth) (1 results) (Medium)
+ - [uninitialized-local](#uninitialized-local) (1 results) (Medium)
+ - [missing-zero-check](#missing-zero-check) (2 results) (Low)
+ - [calls-loop](#calls-loop) (4 results) (Low)
+ - [reentrancy-benign](#reentrancy-benign) (3 results) (Low)
+ - [reentrancy-events](#reentrancy-events) (2 results) (Low)
+ - [timestamp](#timestamp) (6 results) (Low)
+ - [costly-loop](#costly-loop) (2 results) (Informational)
+ - [dead-code](#dead-code) (1 results) (Informational)
+ - [solc-version](#solc-version) (1 results) (Informational)
+ - [naming-convention](#naming-convention) (57 results) (Informational)
+## shadowing-state
+
+> Forgot to set this but only one module modifies the variable
+
+Impact: High
+Confidence: High
+ - [ ] ID-0
+ [ERC20SnapshotModuleInternal._scheduledSnapshots](contracts/modules/internal/ERC20SnapshotModuleInternal.sol#L25) shadows:
+ - [SnapshotModuleBase._scheduledSnapshots](contracts/modules/internal/base/SnapshotModuleBase.sol#L62)
+
+contracts/modules/internal/ERC20SnapshotModuleInternal.sol#L25
+
+
+## reentrancy-no-eth
+Impact: Medium
+Confidence: Medium
+ - [ ] ID-1
+ Reentrancy in [CMTAT_BASE.burnAndMint(address,address,uint256,uint256,string)](contracts/modules/CMTAT_BASE.sol#L189-L192):
+ External calls:
+ - [burn(from,amountToBurn,reason)](contracts/modules/CMTAT_BASE.sol#L190)
+ - [ruleEngine.operateOnTransfer(from,to,amount)](contracts/modules/internal/ValidationModuleInternal.sol#L65)
+ - [mint(to,amountToMint)](contracts/modules/CMTAT_BASE.sol#L191)
+ - [ruleEngine.operateOnTransfer(from,to,amount)](contracts/modules/internal/ValidationModuleInternal.sol#L65)
+ State variables written after the call(s):
+ - [mint(to,amountToMint)](contracts/modules/CMTAT_BASE.sol#L191)
+ - [_currentSnapshotIndex = scheduleSnapshotIndex](contracts/modules/internal/base/SnapshotModuleBase.sol#L328)
+ [SnapshotModuleBase._currentSnapshotIndex](contracts/modules/internal/base/SnapshotModuleBase.sol#L55) can be used in cross function reentrancies:
+ - [SnapshotModuleBase._findScheduledMostRecentPastSnapshot()](contracts/modules/internal/base/SnapshotModuleBase.sol#L375-L402)
+ - [SnapshotModuleBase._setCurrentSnapshot()](contracts/modules/internal/base/SnapshotModuleBase.sol#L321-L330)
+ - [mint(to,amountToMint)](contracts/modules/CMTAT_BASE.sol#L191)
+ - [_currentSnapshotTime = scheduleSnapshotTime](contracts/modules/internal/base/SnapshotModuleBase.sol#L327)
+ [SnapshotModuleBase._currentSnapshotTime](contracts/modules/internal/base/SnapshotModuleBase.sol#L53) can be used in cross function reentrancies:
+ - [SnapshotModuleBase._setCurrentSnapshot()](contracts/modules/internal/base/SnapshotModuleBase.sol#L321-L330)
+ - [SnapshotModuleBase._updateSnapshot(SnapshotModuleBase.Snapshots,uint256)](contracts/modules/internal/base/SnapshotModuleBase.sol#L305-L314)
+ - [SnapshotModuleBase.getNextSnapshots()](contracts/modules/internal/base/SnapshotModuleBase.sol#L82-L111)
+
+contracts/modules/CMTAT_BASE.sol#L189-L192
+
+## uninitialized-local
+
+> The concerned variable local `mostRecent` is initialized in the loop
+
+Impact: Medium
+Confidence: Medium
+
+ - [ ] ID-2
+[SnapshotModuleBase._findScheduledMostRecentPastSnapshot().mostRecent](contracts/modules/internal/base/SnapshotModuleBase.sol#L389) is a local variable never initialized
+
+contracts/modules/internal/base/SnapshotModuleBase.sol#L389
+
+## missing-zero-check
+
+> Mock: not intended to be used in production
+
+Impact: Low
+Confidence: Medium
+
+
+ - [ ] ID-4
+ [AuthorizationEngineMock.authorizeAdminChange(address).newAdmin](contracts/mocks/AuthorizationEngineMock.sol#L21) lacks a zero-check on :
+ - [nextAdmin = newAdmin](contracts/mocks/AuthorizationEngineMock.sol#L22)
+
+contracts/mocks/AuthorizationEngineMock.sol#L21
+
+## calls-loop
+
+>Mock: not intended to be used in production
+>ValidationModuleInternal: the loop happens only for batch function. A relevant alternative could be the creation of a batch function for the RuleEngine, but for the moment we don't have an implemented solution.
+
+Impact: Low
+Confidence: Medium
+
+ - [ ] ID-5
+[RuleEngineMock.messageForTransferRestriction(uint8)](contracts/mocks/RuleEngine/RuleEngineMock.sol#L83-L97) has external calls inside a loop: [_rules[i].canReturnTransferRestrictionCode(_restrictionCode)](contracts/mocks/RuleEngine/RuleEngineMock.sol#L88)
+
+contracts/mocks/RuleEngine/RuleEngineMock.sol#L83-L97
+
+
+ - [ ] ID-6
+[RuleEngineMock.messageForTransferRestriction(uint8)](contracts/mocks/RuleEngine/RuleEngineMock.sol#L83-L97) has external calls inside a loop: [_rules[i].messageForTransferRestriction(_restrictionCode)](contracts/mocks/RuleEngine/RuleEngineMock.sol#L89-L90)
+
+contracts/mocks/RuleEngine/RuleEngineMock.sol#L83-L97
+
+
+ - [ ] ID-7
+[ValidationModuleInternal._operateOnTransfer(address,address,uint256)](contracts/modules/internal/ValidationModuleInternal.sol#L64-L66) has external calls inside a loop: [ruleEngine.operateOnTransfer(from,to,amount)](contracts/modules/internal/ValidationModuleInternal.sol#L65)
+
+contracts/modules/internal/ValidationModuleInternal.sol#L64-L66
+
+
+ - [ ] ID-8
+[RuleEngineMock.detectTransferRestriction(address,address,uint256)](contracts/mocks/RuleEngine/RuleEngineMock.sol#L39-L59) has external calls inside a loop: [restriction = _rules[i].detectTransferRestriction(_from,_to,_amount)](contracts/mocks/RuleEngine/RuleEngineMock.sol#L46-L50)
+
+contracts/mocks/RuleEngine/RuleEngineMock.sol#L39-L59
+
+## reentrancy-benign
+
+> Factory contract : It is not a security issue since only authorized user can call the function
+> CMTAT_BASE._update: the contract called is a trusted contract (RuleEngine)
+
+Impact: Low
+Confidence: Medium
+ - [ ] ID-9
+ Reentrancy in [CMTAT_BEACON_FACTORY.deployCMTAT(address,IAuthorizationEngine,string,string,uint8,string,string,IRuleEngine,string,uint256)](contracts/deployment/CMTAT_BEACON_FACTORY.sol#L41-L75):
+ External calls:
+ - [cmtat = new BeaconProxy(address(beacon),abi.encodeWithSelector(CMTAT_PROXY(address(0)).initialize.selector,admin,authorizationEngineIrrevocable,nameIrrevocable,symbolIrrevocable,decimalsIrrevocable,tokenId_,terms_,ruleEngine_,information_,flag_))](contracts/deployment/CMTAT_BEACON_FACTORY.sol#L54-L69)
+ State variables written after the call(s):
+ - [cmtatCounterId ++](contracts/deployment/CMTAT_BEACON_FACTORY.sol#L72)
+ - [cmtats[cmtatCounterId] = address(cmtat)](contracts/deployment/CMTAT_BEACON_FACTORY.sol#L70)
+ - [cmtatsList.push(address(cmtat))](contracts/deployment/CMTAT_BEACON_FACTORY.sol#L73)
+
+contracts/deployment/CMTAT_BEACON_FACTORY.sol#L41-L75
+
+
+ - [ ] ID-10
+ Reentrancy in [CMTAT_TP_FACTORY.deployCMTAT(address,address,IAuthorizationEngine,string,string,uint8,string,string,IRuleEngine,string,uint256)](contracts/deployment/CMTAT_TP_FACTORY.sol#L32-L68):
+ External calls:
+ - [cmtat = new TransparentUpgradeableProxy(logic,proxyAdminOwner,abi.encodeWithSelector(CMTAT_PROXY(address(0)).initialize.selector,admin,authorizationEngineIrrevocable,nameIrrevocable,symbolIrrevocable,decimalsIrrevocable,tokenId_,terms_,ruleEngine_,information_,flag_))](contracts/deployment/CMTAT_TP_FACTORY.sol#L46-L62)
+ State variables written after the call(s):
+ - [cmtatID ++](contracts/deployment/CMTAT_TP_FACTORY.sol#L65)
+ - [cmtats[cmtatID] = address(cmtat)](contracts/deployment/CMTAT_TP_FACTORY.sol#L63)
+ - [cmtatsList.push(address(cmtat))](contracts/deployment/CMTAT_TP_FACTORY.sol#L66)
+
+contracts/deployment/CMTAT_TP_FACTORY.sol#L32-L68
+
+
+ - [ ] ID-11
+ Reentrancy in [CMTAT_BASE._update(address,address,uint256)](contracts/modules/CMTAT_BASE.sol#L198-L213):
+ External calls:
+ - [! ValidationModule._operateOnTransfer(from,to,amount)](contracts/modules/CMTAT_BASE.sol#L203)
+ - [ruleEngine.operateOnTransfer(from,to,amount)](contracts/modules/internal/ValidationModuleInternal.sol#L65)
+ State variables written after the call(s):
+ - [ERC20SnapshotModuleInternal._snapshotUpdate(from,to)](contracts/modules/CMTAT_BASE.sol#L211)
+ - [_currentSnapshotIndex = scheduleSnapshotIndex](contracts/modules/internal/base/SnapshotModuleBase.sol#L328)
+ - [ERC20SnapshotModuleInternal._snapshotUpdate(from,to)](contracts/modules/CMTAT_BASE.sol#L211)
+ - [_currentSnapshotTime = scheduleSnapshotTime](contracts/modules/internal/base/SnapshotModuleBase.sol#L327)
+
+contracts/modules/CMTAT_BASE.sol#L198-L213
+
+## reentrancy-events
+
+> It is not a security issue since only authorized user can call the function
+
+Impact: Low
+Confidence: Medium
+ - [ ] ID-12
+ Reentrancy in [CMTAT_TP_FACTORY.deployCMTAT(address,address,IAuthorizationEngine,string,string,uint8,string,string,IRuleEngine,string,uint256)](contracts/deployment/CMTAT_TP_FACTORY.sol#L32-L68):
+ External calls:
+ - [cmtat = new TransparentUpgradeableProxy(logic,proxyAdminOwner,abi.encodeWithSelector(CMTAT_PROXY(address(0)).initialize.selector,admin,authorizationEngineIrrevocable,nameIrrevocable,symbolIrrevocable,decimalsIrrevocable,tokenId_,terms_,ruleEngine_,information_,flag_))](contracts/deployment/CMTAT_TP_FACTORY.sol#L46-L62)
+ Event emitted after the call(s):
+ - [CMTAT(address(cmtat),cmtatID)](contracts/deployment/CMTAT_TP_FACTORY.sol#L64)
+
+contracts/deployment/CMTAT_TP_FACTORY.sol#L32-L68
+
+
+ - [ ] ID-13
+ Reentrancy in [CMTAT_BEACON_FACTORY.deployCMTAT(address,IAuthorizationEngine,string,string,uint8,string,string,IRuleEngine,string,uint256)](contracts/deployment/CMTAT_BEACON_FACTORY.sol#L41-L75):
+ External calls:
+ - [cmtat = new BeaconProxy(address(beacon),abi.encodeWithSelector(CMTAT_PROXY(address(0)).initialize.selector,admin,authorizationEngineIrrevocable,nameIrrevocable,symbolIrrevocable,decimalsIrrevocable,tokenId_,terms_,ruleEngine_,information_,flag_))](contracts/deployment/CMTAT_BEACON_FACTORY.sol#L54-L69)
+ Event emitted after the call(s):
+ - [CMTAT(address(cmtat),cmtatCounterId)](contracts/deployment/CMTAT_BEACON_FACTORY.sol#L71)
+
+contracts/deployment/CMTAT_BEACON_FACTORY.sol#L41-L75
+
+## timestamp
+
+> With the Proof of Work, it was possible for a miner to modify the timestamp in a range of about 15 seconds
+>
+> With the Proof Of Stake, a new block is created every 12 seconds
+>
+> In all cases, we are not looking for such precision
+
+Impact: Low
+Confidence: Medium
+ - [ ] ID-14
+ [SnapshotModuleBase._scheduleSnapshotNotOptimized(uint256)](contracts/modules/internal/base/SnapshotModuleBase.sol#L149-L177) uses timestamp for comparisons
+ Dangerous comparisons:
+ - [time <= block.timestamp](contracts/modules/internal/base/SnapshotModuleBase.sol#L150)
+
+contracts/modules/internal/base/SnapshotModuleBase.sol#L149-L177
+
+
+ - [ ] ID-15
+ [SnapshotModuleBase._rescheduleSnapshot(uint256,uint256)](contracts/modules/internal/base/SnapshotModuleBase.sol#L182-L223) uses timestamp for comparisons
+ Dangerous comparisons:
+ - [oldTime <= block.timestamp](contracts/modules/internal/base/SnapshotModuleBase.sol#L184)
+ - [newTime <= block.timestamp](contracts/modules/internal/base/SnapshotModuleBase.sol#L187)
+
+contracts/modules/internal/base/SnapshotModuleBase.sol#L182-L223
+
+
+ - [ ] ID-16
+ [SnapshotModuleBase._unscheduleSnapshotNotOptimized(uint256)](contracts/modules/internal/base/SnapshotModuleBase.sol#L250-L263) uses timestamp for comparisons
+ Dangerous comparisons:
+ - [time <= block.timestamp](contracts/modules/internal/base/SnapshotModuleBase.sol#L251)
+
+contracts/modules/internal/base/SnapshotModuleBase.sol#L250-L263
+
+
+ - [ ] ID-17
+ [SnapshotModuleBase._scheduleSnapshot(uint256)](contracts/modules/internal/base/SnapshotModuleBase.sol#L118-L144) uses timestamp for comparisons
+ Dangerous comparisons:
+ - [time <= block.timestamp](contracts/modules/internal/base/SnapshotModuleBase.sol#L120)
+
+contracts/modules/internal/base/SnapshotModuleBase.sol#L118-L144
+
+
+ - [ ] ID-18
+ [SnapshotModuleBase._unscheduleLastSnapshot(uint256)](contracts/modules/internal/base/SnapshotModuleBase.sol#L228-L242) uses timestamp for comparisons
+ Dangerous comparisons:
+ - [time <= block.timestamp](contracts/modules/internal/base/SnapshotModuleBase.sol#L230)
+
+contracts/modules/internal/base/SnapshotModuleBase.sol#L228-L242
+
+
+ - [ ] ID-19
+ [SnapshotModuleBase._findScheduledMostRecentPastSnapshot()](contracts/modules/internal/base/SnapshotModuleBase.sol#L375-L402) uses timestamp for comparisons
+ Dangerous comparisons:
+ - [_scheduledSnapshots[i] <= block.timestamp](contracts/modules/internal/base/SnapshotModuleBase.sol#L393)
+
+contracts/modules/internal/base/SnapshotModuleBase.sol#L375-L402
+
+## costly-loop
+
+> Inside the function, these two operations are not performed inside a loop.
+>
+> It seems that the only loops which calls`setCurrentSnapshot`are inside the batch functions(mintBatch, burnBatch, ...) through a call to the function update.
+> At the moment, there is no trivial solution to resolve this.
+
+Impact: Informational
+Confidence: Medium
+ - [ ] ID-20
+ [SnapshotModuleBase._setCurrentSnapshot()](contracts/modules/internal/base/SnapshotModuleBase.sol#L321-L330) has costly operations inside a loop:
+ - [_currentSnapshotTime = scheduleSnapshotTime](contracts/modules/internal/base/SnapshotModuleBase.sol#L327)
+
+contracts/modules/internal/base/SnapshotModuleBase.sol#L321-L330
+
+
+ - [ ] ID-21
+ [SnapshotModuleBase._setCurrentSnapshot()](contracts/modules/internal/base/SnapshotModuleBase.sol#L321-L330) has costly operations inside a loop:
+ - [_currentSnapshotIndex = scheduleSnapshotIndex](contracts/modules/internal/base/SnapshotModuleBase.sol#L328)
+
+contracts/modules/internal/base/SnapshotModuleBase.sol#L321-L330
+
+## dead-code
+
+> - Implemented to be gasless compatible (see MetaTxModule)
+>
+> - If we remove this function, we will have the following error:
+>
+> "Derived contract must override function "_msgData". Two or more base classes define function with same name and parameter types."
+
+Impact: Informational
+Confidence: Medium
+
+ - [ ] ID-22
+[CMTAT_BASE._msgData()](contracts/modules/CMTAT_BASE.sol#L240-L247) is never used and should be removed
+
+contracts/modules/CMTAT_BASE.sol#L240-L247
+
+## solc-version
+
+> The version set in the config file is 0.8.22
+
+Impact: Informational
+Confidence: High
+ - [ ] ID-23
+ Version constraint ^0.8.20 contains known severe issues (https://solidity.readthedocs.io/en/latest/bugs.html)
+ - VerbatimInvalidDeduplication
+ - FullInlinerNonExpressionSplitArgumentEvaluationOrder
+ - MissingSideEffectsOnSelectorAccess.
+ It is used by:
+ - node_modules/@openzeppelin/contracts/access/AccessControl.sol#4
+ - node_modules/@openzeppelin/contracts/access/IAccessControl.sol#4
+ - node_modules/@openzeppelin/contracts/access/Ownable.sol#4
+ - node_modules/@openzeppelin/contracts/interfaces/IERC1967.sol#4
+ - node_modules/@openzeppelin/contracts/interfaces/IERC5267.sol#4
+ - node_modules/@openzeppelin/contracts/interfaces/draft-IERC6093.sol#3
+ - node_modules/@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol#4
+ - node_modules/@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol#4
+ - node_modules/@openzeppelin/contracts/proxy/Proxy.sol#4
+ - node_modules/@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol#4
+ - node_modules/@openzeppelin/contracts/proxy/beacon/IBeacon.sol#4
+ - node_modules/@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol#4
+ - node_modules/@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol#4
+ - node_modules/@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol#4
+ - node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol#4
+ - node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol#4
+ - node_modules/@openzeppelin/contracts/utils/Address.sol#4
+ - node_modules/@openzeppelin/contracts/utils/Arrays.sol#4
+ - node_modules/@openzeppelin/contracts/utils/Context.sol#4
+ - node_modules/@openzeppelin/contracts/utils/StorageSlot.sol#5
+ - node_modules/@openzeppelin/contracts/utils/Strings.sol#4
+ - node_modules/@openzeppelin/contracts/utils/cryptography/ECDSA.sol#4
+ - node_modules/@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol#4
+ - node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol#4
+ - node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol#4
+ - node_modules/@openzeppelin/contracts/utils/math/Math.sol#4
+ - node_modules/@openzeppelin/contracts/utils/math/SignedMath.sol#4
+ - contracts/CMTAT_PROXY.sol#3
+ - contracts/CMTAT_STANDALONE.sol#3
+ - contracts/deployment/CMTAT_BEACON_FACTORY.sol#2
+ - contracts/deployment/CMTAT_TP_FACTORY.sol#2
+ - contracts/interfaces/ICCIPToken.sol#3
+ - contracts/interfaces/ICMTATSnapshot.sol#3
+ - contracts/interfaces/IDebtGlobal.sol#3
+ - contracts/interfaces/draft-IERC1404/draft-IERC1404.sol#3
+ - contracts/interfaces/draft-IERC1404/draft-IERC1404EnumCode.sol#3
+ - contracts/interfaces/draft-IERC1404/draft-IERC1404Wrapper.sol#3
+ - contracts/interfaces/engine/IAuthorizationEngine.sol#3
+ - contracts/interfaces/engine/IRuleEngine.sol#3
+ - contracts/libraries/Errors.sol#3
+ - contracts/mocks/AuthorizationEngineMock.sol#3
+ - contracts/mocks/MinimalForwarderMock.sol#3
+ - contracts/mocks/RuleEngine/CodeList.sol#3
+ - contracts/mocks/RuleEngine/RuleEngineMock.sol#3
+ - contracts/mocks/RuleEngine/RuleMock.sol#3
+ - contracts/mocks/RuleEngine/interfaces/IRule.sol#3
+ - contracts/mocks/RuleEngine/interfaces/IRuleEngineMock.sol#3
+ - contracts/modules/CMTAT_BASE.sol#3
+ - contracts/modules/internal/ERC20SnapshotModuleInternal.sol#3
+ - contracts/modules/internal/EnforcementModuleInternal.sol#3
+ - contracts/modules/internal/ValidationModuleInternal.sol#3
+ - contracts/modules/internal/base/SnapshotModuleBase.sol#3
+ - contracts/modules/security/AuthorizationModule.sol#3
+ - contracts/modules/wrapper/controllers/ValidationModule.sol#3
+ - contracts/modules/wrapper/core/BaseModule.sol#3
+ - contracts/modules/wrapper/core/ERC20BaseModule.sol#3
+ - contracts/modules/wrapper/core/ERC20BurnModule.sol#3
+ - contracts/modules/wrapper/core/ERC20MintModule.sol#3
+ - contracts/modules/wrapper/core/EnforcementModule.sol#3
+ - contracts/modules/wrapper/core/PauseModule.sol#3
+ - contracts/modules/wrapper/extensions/DebtModule/CreditEventsModule.sol#3
+ - contracts/modules/wrapper/extensions/DebtModule/DebtBaseModule.sol#3
+ - contracts/modules/wrapper/extensions/ERC20SnapshotModule.sol#3
+ - contracts/modules/wrapper/extensions/MetaTxModule.sol#3
+ - contracts/test/proxy/CMTAT_PROXY.sol#3
+ - openzeppelin-contracts-upgradeable/contracts/access/AccessControlUpgradeable.sol#4
+ - openzeppelin-contracts-upgradeable/contracts/metatx/ERC2771ContextUpgradeable.sol#4
+ - openzeppelin-contracts-upgradeable/contracts/metatx/ERC2771ForwarderUpgradeable.sol#4
+ - openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol#4
+ - openzeppelin-contracts-upgradeable/contracts/token/ERC20/ERC20Upgradeable.sol#4
+ - openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol#4
+ - openzeppelin-contracts-upgradeable/contracts/utils/NoncesUpgradeable.sol#3
+ - openzeppelin-contracts-upgradeable/contracts/utils/PausableUpgradeable.sol#4
+ - openzeppelin-contracts-upgradeable/contracts/utils/cryptography/EIP712Upgradeable.sol#4
+ - openzeppelin-contracts-upgradeable/contracts/utils/introspection/ERC165Upgradeable.sol#4
+
+## naming-convention
+
+> It is not really necessary to rename all the variables. It will generate a lot of work for a minor improvement.
+
+Impact: Informational
+Confidence: High
+
+ - [ ] ID-24
+Enum [IERC1404EnumCode.REJECTED_CODE_BASE](contracts/interfaces/draft-IERC1404/draft-IERC1404EnumCode.sol#L9-L14) is not in CapWords
+
+contracts/interfaces/draft-IERC1404/draft-IERC1404EnumCode.sol#L9-L14
+
+
+ - [ ] ID-25
+Variable [CreditEventsModule.__gap](contracts/modules/wrapper/extensions/DebtModule/CreditEventsModule.sol#L83) is not in mixedCase
+
+contracts/modules/wrapper/extensions/DebtModule/CreditEventsModule.sol#L83
+
+
+ - [ ] ID-26
+Parameter [RuleEngineMock.detectTransferRestriction(address,address,uint256)._amount](contracts/mocks/RuleEngine/RuleEngineMock.sol#L42) is not in mixedCase
+
+contracts/mocks/RuleEngine/RuleEngineMock.sol#L42
+
+
+ - [ ] ID-27
+Contract [CMTAT_PROXY](contracts/CMTAT_PROXY.sol#L7-L21) is not in CapWords
+
+contracts/CMTAT_PROXY.sol#L7-L21
+
+
+ - [ ] ID-28
+Function [PauseModule.__PauseModule_init_unchained()](contracts/modules/wrapper/core/PauseModule.sol#L26-L28) is not in mixedCase
+
+contracts/modules/wrapper/core/PauseModule.sol#L26-L28
+
+
+ - [ ] ID-29
+Function [CreditEventsModule.__CreditEvents_init_unchained()](contracts/modules/wrapper/extensions/DebtModule/CreditEventsModule.sol#L28-L30) is not in mixedCase
+
+contracts/modules/wrapper/extensions/DebtModule/CreditEventsModule.sol#L28-L30
+
+
+ - [ ] ID-30
+Variable [CMTAT_BASE.__gap](contracts/modules/CMTAT_BASE.sol#L249) is not in mixedCase
+
+contracts/modules/CMTAT_BASE.sol#L249
+
+
+ - [ ] ID-31
+Function [EnforcementModuleInternal.__Enforcement_init_unchained()](contracts/modules/internal/EnforcementModuleInternal.sol#L40-L42) is not in mixedCase
+
+contracts/modules/internal/EnforcementModuleInternal.sol#L40-L42
+
+
+ - [ ] ID-32
+Variable [ValidationModuleInternal.__gap](contracts/modules/internal/ValidationModuleInternal.sol#L68) is not in mixedCase
+
+contracts/modules/internal/ValidationModuleInternal.sol#L68
+
+
+ - [ ] ID-33
+Function [ERC20BurnModule.__ERC20BurnModule_init_unchained()](contracts/modules/wrapper/core/ERC20BurnModule.sol#L19-L21) is not in mixedCase
+
+contracts/modules/wrapper/core/ERC20BurnModule.sol#L19-L21
+
+
+ - [ ] ID-34
+Function [ValidationModuleInternal.__Validation_init_unchained(IRuleEngine)](contracts/modules/internal/ValidationModuleInternal.sol#L24-L31) is not in mixedCase
+
+contracts/modules/internal/ValidationModuleInternal.sol#L24-L31
+
+
+ - [ ] ID-35
+Variable [BaseModule.__gap](contracts/modules/wrapper/core/BaseModule.sol#L94) is not in mixedCase
+
+contracts/modules/wrapper/core/BaseModule.sol#L94
+
+
+ - [ ] ID-36
+Variable [ValidationModule.__gap](contracts/modules/wrapper/controllers/ValidationModule.sol#L136) is not in mixedCase
+
+contracts/modules/wrapper/controllers/ValidationModule.sol#L136
+
+
+ - [ ] ID-37
+Variable [EnforcementModule.__gap](contracts/modules/wrapper/core/EnforcementModule.sol#L55) is not in mixedCase
+
+contracts/modules/wrapper/core/EnforcementModule.sol#L55
+
+
+ - [ ] ID-38
+Contract [CMTAT_STANDALONE](contracts/CMTAT_STANDALONE.sol#L7-L53) is not in CapWords
+
+contracts/CMTAT_STANDALONE.sol#L7-L53
+
+
+ - [ ] ID-39
+Variable [DebtBaseModule.__gap](contracts/modules/wrapper/extensions/DebtModule/DebtBaseModule.sol#L232) is not in mixedCase
+
+contracts/modules/wrapper/extensions/DebtModule/DebtBaseModule.sol#L232
+
+
+ - [ ] ID-40
+Variable [AuthorizationModule.__gap](contracts/modules/security/AuthorizationModule.sol#L85) is not in mixedCase
+
+contracts/modules/security/AuthorizationModule.sol#L85
+
+
+ - [ ] ID-41
+Parameter [RuleEngineMock.operateOnTransfer(address,address,uint256)._to](contracts/mocks/RuleEngine/RuleEngineMock.sol#L74) is not in mixedCase
+
+contracts/mocks/RuleEngine/RuleEngineMock.sol#L74
+
+
+ - [ ] ID-42
+Parameter [RuleEngineMock.validateTransfer(address,address,uint256)._amount](contracts/mocks/RuleEngine/RuleEngineMock.sol#L64) is not in mixedCase
+
+contracts/mocks/RuleEngine/RuleEngineMock.sol#L64
+
+
+ - [ ] ID-43
+Parameter [RuleEngineMock.operateOnTransfer(address,address,uint256)._from](contracts/mocks/RuleEngine/RuleEngineMock.sol#L73) is not in mixedCase
+
+contracts/mocks/RuleEngine/RuleEngineMock.sol#L73
+
+
+ - [ ] ID-44
+Parameter [RuleMock.validateTransfer(address,address,uint256)._to](contracts/mocks/RuleEngine/RuleMock.sol#L14) is not in mixedCase
+
+contracts/mocks/RuleEngine/RuleMock.sol#L14
+
+
+ - [ ] ID-45
+Parameter [RuleEngineMock.operateOnTransfer(address,address,uint256)._amount](contracts/mocks/RuleEngine/RuleEngineMock.sol#L75) is not in mixedCase
+
+contracts/mocks/RuleEngine/RuleEngineMock.sol#L75
+
+
+ - [ ] ID-46
+Variable [EnforcementModuleInternal.__gap](contracts/modules/internal/EnforcementModuleInternal.sol#L87) is not in mixedCase
+
+contracts/modules/internal/EnforcementModuleInternal.sol#L87
+
+
+ - [ ] ID-47
+Parameter [RuleMock.canReturnTransferRestrictionCode(uint8)._restrictionCode](contracts/mocks/RuleEngine/RuleMock.sol#L35) is not in mixedCase
+
+contracts/mocks/RuleEngine/RuleMock.sol#L35
+
+
+ - [ ] ID-48
+Variable [SnapshotModuleBase.__gap](contracts/modules/internal/base/SnapshotModuleBase.sol#L404) is not in mixedCase
+
+contracts/modules/internal/base/SnapshotModuleBase.sol#L404
+
+
+ - [ ] ID-49
+Parameter [RuleEngineMock.validateTransfer(address,address,uint256)._to](contracts/mocks/RuleEngine/RuleEngineMock.sol#L63) is not in mixedCase
+
+contracts/mocks/RuleEngine/RuleEngineMock.sol#L63
+
+
+ - [ ] ID-50
+Function [BaseModule.__Base_init_unchained(string,string,string,uint256)](contracts/modules/wrapper/core/BaseModule.sol#L40-L50) is not in mixedCase
+
+contracts/modules/wrapper/core/BaseModule.sol#L40-L50
+
+
+ - [ ] ID-51
+Function [AuthorizationModule.__AuthorizationModule_init_unchained(address,IAuthorizationEngine)](contracts/modules/security/AuthorizationModule.sol#L22-L33) is not in mixedCase
+
+contracts/modules/security/AuthorizationModule.sol#L22-L33
+
+
+ - [ ] ID-52
+Parameter [RuleEngineMock.validateTransfer(address,address,uint256)._from](contracts/mocks/RuleEngine/RuleEngineMock.sol#L62) is not in mixedCase
+
+contracts/mocks/RuleEngine/RuleEngineMock.sol#L62
+
+
+ - [ ] ID-53
+Parameter [RuleMock.validateTransfer(address,address,uint256)._amount](contracts/mocks/RuleEngine/RuleMock.sol#L15) is not in mixedCase
+
+contracts/mocks/RuleEngine/RuleMock.sol#L15
+
+
+ - [ ] ID-54
+Variable [PauseModule.__gap](contracts/modules/wrapper/core/PauseModule.sol#L83) is not in mixedCase
+
+contracts/modules/wrapper/core/PauseModule.sol#L83
+
+
+ - [ ] ID-55
+Function [CMTAT_BASE.__CMTAT_init_unchained()](contracts/modules/CMTAT_BASE.sol#L148-L150) is not in mixedCase
+
+contracts/modules/CMTAT_BASE.sol#L148-L150
+
+
+ - [ ] ID-56
+Variable [ERC20SnapshotModule.__gap](contracts/modules/wrapper/extensions/ERC20SnapshotModule.sol#L77) is not in mixedCase
+
+contracts/modules/wrapper/extensions/ERC20SnapshotModule.sol#L77
+
+
+ - [ ] ID-57
+Parameter [RuleMock.detectTransferRestriction(address,address,uint256)._amount](contracts/mocks/RuleEngine/RuleMock.sol#L26) is not in mixedCase
+
+contracts/mocks/RuleEngine/RuleMock.sol#L26
+
+
+ - [ ] ID-58
+Function [ERC20BaseModule.__ERC20BaseModule_init_unchained(uint8)](contracts/modules/wrapper/core/ERC20BaseModule.sol#L28-L32) is not in mixedCase
+
+contracts/modules/wrapper/core/ERC20BaseModule.sol#L28-L32
+
+
+ - [ ] ID-59
+Parameter [RuleMock.messageForTransferRestriction(uint8)._restrictionCode](contracts/mocks/RuleEngine/RuleMock.sol#L41) is not in mixedCase
+
+contracts/mocks/RuleEngine/RuleMock.sol#L41
+
+
+ - [ ] ID-60
+Function [CMTAT_BASE.__CMTAT_init(address,IAuthorizationEngine,string,string,uint8,string,string,IRuleEngine,string,uint256)](contracts/modules/CMTAT_BASE.sol#L87-L146) is not in mixedCase
+
+contracts/modules/CMTAT_BASE.sol#L87-L146
+
+
+ - [ ] ID-61
+Function [ERC20MintModule.__ERC20MintModule_init_unchained()](contracts/modules/wrapper/core/ERC20MintModule.sol#L17-L19) is not in mixedCase
+
+contracts/modules/wrapper/core/ERC20MintModule.sol#L17-L19
+
+
+ - [ ] ID-62
+Parameter [RuleEngineMock.detectTransferRestriction(address,address,uint256)._to](contracts/mocks/RuleEngine/RuleEngineMock.sol#L41) is not in mixedCase
+
+contracts/mocks/RuleEngine/RuleEngineMock.sol#L41
+
+
+ - [ ] ID-63
+Variable [MetaTxModule.__gap](contracts/modules/wrapper/extensions/MetaTxModule.sol#L22) is not in mixedCase
+
+contracts/modules/wrapper/extensions/MetaTxModule.sol#L22
+
+
+ - [ ] ID-64
+Function [SnapshotModuleBase.__SnapshotModuleBase_init_unchained()](contracts/modules/internal/base/SnapshotModuleBase.sol#L64-L67) is not in mixedCase
+
+contracts/modules/internal/base/SnapshotModuleBase.sol#L64-L67
+
+
+ - [ ] ID-65
+Variable [ERC20BurnModule.__gap](contracts/modules/wrapper/core/ERC20BurnModule.sol#L113) is not in mixedCase
+
+contracts/modules/wrapper/core/ERC20BurnModule.sol#L113
+
+
+ - [ ] ID-66
+Variable [ERC20BaseModule.__gap](contracts/modules/wrapper/core/ERC20BaseModule.sol#L113) is not in mixedCase
+
+contracts/modules/wrapper/core/ERC20BaseModule.sol#L113
+
+
+ - [ ] ID-67
+Contract [CMTAT_BEACON_FACTORY](contracts/deployment/CMTAT_BEACON_FACTORY.sol#L15-L93) is not in CapWords
+
+contracts/deployment/CMTAT_BEACON_FACTORY.sol#L15-L93
+
+
+ - [ ] ID-68
+Contract [CMTAT_BASE](contracts/modules/CMTAT_BASE.sol#L29-L250) is not in CapWords
+
+contracts/modules/CMTAT_BASE.sol#L29-L250
+
+
+ - [ ] ID-69
+Parameter [RuleEngineMock.messageForTransferRestriction(uint8)._restrictionCode](contracts/mocks/RuleEngine/RuleEngineMock.sol#L84) is not in mixedCase
+
+contracts/mocks/RuleEngine/RuleEngineMock.sol#L84
+
+
+ - [ ] ID-70
+Variable [ERC20MintModule.__gap](contracts/modules/wrapper/core/ERC20MintModule.sol#L73) is not in mixedCase
+
+contracts/modules/wrapper/core/ERC20MintModule.sol#L73
+
+
+ - [ ] ID-71
+Function [ValidationModule.__ValidationModule_init_unchained()](contracts/modules/wrapper/controllers/ValidationModule.sol#L26-L28) is not in mixedCase
+
+contracts/modules/wrapper/controllers/ValidationModule.sol#L26-L28
+
+
+ - [ ] ID-72
+Function [DebtBaseModule.__DebtBaseModule_init_unchained()](contracts/modules/wrapper/extensions/DebtModule/DebtBaseModule.sol#L60-L62) is not in mixedCase
+
+contracts/modules/wrapper/extensions/DebtModule/DebtBaseModule.sol#L60-L62
+
+
+ - [ ] ID-73
+Parameter [RuleEngineMock.detectTransferRestriction(address,address,uint256)._from](contracts/mocks/RuleEngine/RuleEngineMock.sol#L40) is not in mixedCase
+
+contracts/mocks/RuleEngine/RuleEngineMock.sol#L40
+
+
+ - [ ] ID-74
+Function [ERC20SnapshotModule.__ERC20SnasphotModule_init_unchained()](contracts/modules/wrapper/extensions/ERC20SnapshotModule.sol#L20-L22) is not in mixedCase
+
+contracts/modules/wrapper/extensions/ERC20SnapshotModule.sol#L20-L22
+
+
+ - [ ] ID-75
+Variable [ERC20SnapshotModuleInternal.__gap](contracts/modules/internal/ERC20SnapshotModuleInternal.sol#L140) is not in mixedCase
+
+contracts/modules/internal/ERC20SnapshotModuleInternal.sol#L140
+
+
+ - [ ] ID-76
+Function [EnforcementModule.__EnforcementModule_init_unchained()](contracts/modules/wrapper/core/EnforcementModule.sol#L25-L27) is not in mixedCase
+
+contracts/modules/wrapper/core/EnforcementModule.sol#L25-L27
+
+
+ - [ ] ID-77
+Function [ERC20SnapshotModuleInternal.__ERC20Snapshot_init_unchained()](contracts/modules/internal/ERC20SnapshotModuleInternal.sol#L27-L30) is not in mixedCase
+
+contracts/modules/internal/ERC20SnapshotModuleInternal.sol#L27-L30
+
+
+ - [ ] ID-78
+Contract [CMTAT_TP_FACTORY](contracts/deployment/CMTAT_TP_FACTORY.sol#L11-L78) is not in CapWords
+
+contracts/deployment/CMTAT_TP_FACTORY.sol#L11-L78
+
+
+ - [ ] ID-79
+Parameter [RuleMock.validateTransfer(address,address,uint256)._from](contracts/mocks/RuleEngine/RuleMock.sol#L13) is not in mixedCase
+
+contracts/mocks/RuleEngine/RuleMock.sol#L13
+
+
+ - [ ] ID-80
+Variable [CMTAT_PROXY.__gap](contracts/CMTAT_PROXY.sol#L20) is not in mixedCase
+
+contracts/CMTAT_PROXY.sol#L20
+
diff --git a/doc/audits/tools/slither-report.md b/doc/audits/tools/slither-report.md
index ffa903c3..7443f783 100644
--- a/doc/audits/tools/slither-report.md
+++ b/doc/audits/tools/slither-report.md
@@ -1,51 +1,36 @@
**THIS CHECKLIST IS NOT COMPLETE**. Use `--show-ignored-findings` to show all the results.
Summary
- - [shadowing-state](#shadowing-state) (1 results) (High)
- - [reentrancy-no-eth](#reentrancy-no-eth) (1 results) (Medium)
+ - [incorrect-equality](#incorrect-equality) (2 results) (Medium)
- [uninitialized-local](#uninitialized-local) (1 results) (Medium)
- - [missing-zero-check](#missing-zero-check) (2 results) (Low)
+ - [unused-return](#unused-return) (1 results) (Medium)
+ - [shadowing-local](#shadowing-local) (1 results) (Low)
+ - [missing-zero-check](#missing-zero-check) (1 results) (Low)
- [calls-loop](#calls-loop) (4 results) (Low)
- - [reentrancy-benign](#reentrancy-benign) (3 results) (Low)
- - [reentrancy-events](#reentrancy-events) (2 results) (Low)
- - [timestamp](#timestamp) (6 results) (Low)
- - [costly-loop](#costly-loop) (2 results) (Informational)
+ - [timestamp](#timestamp) (5 results) (Low)
+ - [assembly](#assembly) (9 results) (Informational)
+ - [costly-loop](#costly-loop) (1 results) (Informational)
- [dead-code](#dead-code) (1 results) (Informational)
- [solc-version](#solc-version) (1 results) (Informational)
- - [naming-convention](#naming-convention) (57 results) (Informational)
-## shadowing-state
-Impact: High
+ - [naming-convention](#naming-convention) (56 results) (Informational)
+ - [similar-names](#similar-names) (3 results) (Informational)
+ - [too-many-digits](#too-many-digits) (2 results) (Informational)
+ - [unused-import](#unused-import) (6 results) (Informational)
+ - [immutable-states](#immutable-states) (1 results) (Optimization)
+## incorrect-equality
+Impact: Medium
Confidence: High
- [ ] ID-0
- [ERC20SnapshotModuleInternal._scheduledSnapshots](contracts/modules/internal/ERC20SnapshotModuleInternal.sol#L25) shadows:
- - [SnapshotModuleBase._scheduledSnapshots](contracts/modules/internal/base/SnapshotModuleBase.sol#L62)
+ [DocumentEngineMock.removeDocument(bytes32)](contracts/mocks/DocumentEngineMock.sol#L72-L89) uses a dangerous strict equality:
+ - [bytes(documents[name_].uri).length == 0](contracts/mocks/DocumentEngineMock.sol#L73)
-contracts/modules/internal/ERC20SnapshotModuleInternal.sol#L25
+contracts/mocks/DocumentEngineMock.sol#L72-L89
-## reentrancy-no-eth
-Impact: Medium
-Confidence: Medium
- [ ] ID-1
- Reentrancy in [CMTAT_BASE.burnAndMint(address,address,uint256,uint256,string)](contracts/modules/CMTAT_BASE.sol#L189-L192):
- External calls:
- - [burn(from,amountToBurn,reason)](contracts/modules/CMTAT_BASE.sol#L190)
- - [ruleEngine.operateOnTransfer(from,to,amount)](contracts/modules/internal/ValidationModuleInternal.sol#L65)
- - [mint(to,amountToMint)](contracts/modules/CMTAT_BASE.sol#L191)
- - [ruleEngine.operateOnTransfer(from,to,amount)](contracts/modules/internal/ValidationModuleInternal.sol#L65)
- State variables written after the call(s):
- - [mint(to,amountToMint)](contracts/modules/CMTAT_BASE.sol#L191)
- - [_currentSnapshotIndex = scheduleSnapshotIndex](contracts/modules/internal/base/SnapshotModuleBase.sol#L328)
- [SnapshotModuleBase._currentSnapshotIndex](contracts/modules/internal/base/SnapshotModuleBase.sol#L55) can be used in cross function reentrancies:
- - [SnapshotModuleBase._findScheduledMostRecentPastSnapshot()](contracts/modules/internal/base/SnapshotModuleBase.sol#L375-L402)
- - [SnapshotModuleBase._setCurrentSnapshot()](contracts/modules/internal/base/SnapshotModuleBase.sol#L321-L330)
- - [mint(to,amountToMint)](contracts/modules/CMTAT_BASE.sol#L191)
- - [_currentSnapshotTime = scheduleSnapshotTime](contracts/modules/internal/base/SnapshotModuleBase.sol#L327)
- [SnapshotModuleBase._currentSnapshotTime](contracts/modules/internal/base/SnapshotModuleBase.sol#L53) can be used in cross function reentrancies:
- - [SnapshotModuleBase._setCurrentSnapshot()](contracts/modules/internal/base/SnapshotModuleBase.sol#L321-L330)
- - [SnapshotModuleBase._updateSnapshot(SnapshotModuleBase.Snapshots,uint256)](contracts/modules/internal/base/SnapshotModuleBase.sol#L305-L314)
- - [SnapshotModuleBase.getNextSnapshots()](contracts/modules/internal/base/SnapshotModuleBase.sol#L82-L111)
-
-contracts/modules/CMTAT_BASE.sol#L189-L192
+ [DocumentEngineMock.getDocument(bytes32)](contracts/mocks/DocumentEngineMock.sol#L37-L49) uses a dangerous strict equality:
+ - [bytes(documents[name_].uri).length == 0](contracts/mocks/DocumentEngineMock.sol#L43)
+
+contracts/mocks/DocumentEngineMock.sol#L37-L49
## uninitialized-local
@@ -55,19 +40,41 @@ Impact: Medium
Confidence: Medium
- [ ] ID-2
-[SnapshotModuleBase._findScheduledMostRecentPastSnapshot().mostRecent](contracts/modules/internal/base/SnapshotModuleBase.sol#L389) is a local variable never initialized
+[SnapshotModuleBase._findScheduledMostRecentPastSnapshot().mostRecent](contracts/modules/internal/base/SnapshotModuleBase.sol#L385) is a local variable never initialized
-contracts/modules/internal/base/SnapshotModuleBase.sol#L389
+contracts/modules/internal/base/SnapshotModuleBase.sol#L385
-## missing-zero-check
+## unused-return
-> Mock: not intended to be used in production
+> Not the case
-Impact: Low
+Impact: Medium
Confidence: Medium
+ - [ ] ID-3
+[DocumentModule.getDocument(bytes32)](contracts/modules/wrapper/extensions/DocumentModule.sol#L74-L81) ignores return value by [$._documentEngine.getDocument(_name)](contracts/modules/wrapper/extensions/DocumentModule.sol#L77)
+
+contracts/modules/wrapper/extensions/DocumentModule.sol#L74-L81
+
+## shadowing-local
+> Mock: not intended to be used in production
+
+Impact: Low
+Confidence: High
- [ ] ID-4
+ [IDebtEngineMock.setCreditEvents(IDebtGlobal.CreditEvents).creditEvents](contracts/mocks/DebtEngineMock.sol#L7) shadows:
+ - [IDebtEngine.creditEvents()](contracts/interfaces/engine/IDebtEngine.sol#L17) (function)
+
+contracts/mocks/DebtEngineMock.sol#L7
+
+## missing-zero-check
+
+> Mock: not intended to be used in production
+
+Impact: Low
+Confidence: Medium
+ - [ ] ID-5
[AuthorizationEngineMock.authorizeAdminChange(address).newAdmin](contracts/mocks/AuthorizationEngineMock.sol#L21) lacks a zero-check on :
- [nextAdmin = newAdmin](contracts/mocks/AuthorizationEngineMock.sol#L22)
@@ -75,185 +82,166 @@ contracts/mocks/AuthorizationEngineMock.sol#L21
## calls-loop
->Mock: not intended to be used in production
->ValidationModuleInternal: the loop happens only for batch function. A relevant alternative could be the creation of a batch function for the RuleEngine, but for the moment we don't have an implemented solution.
+> ValidationModuleInternal: Acknowledge
+>
+> Mock: not intended to be used in production
+> ValidationModuleInternal: the loop happens only for batch function. A relevant alternative could be the creation of a batch function for the RuleEngine, but for the moment we don't have an implemented solution.
Impact: Low
Confidence: Medium
-
- - [ ] ID-5
+ - [ ] ID-6
[RuleEngineMock.messageForTransferRestriction(uint8)](contracts/mocks/RuleEngine/RuleEngineMock.sol#L83-L97) has external calls inside a loop: [_rules[i].canReturnTransferRestrictionCode(_restrictionCode)](contracts/mocks/RuleEngine/RuleEngineMock.sol#L88)
contracts/mocks/RuleEngine/RuleEngineMock.sol#L83-L97
- - [ ] ID-6
+ - [ ] ID-7
[RuleEngineMock.messageForTransferRestriction(uint8)](contracts/mocks/RuleEngine/RuleEngineMock.sol#L83-L97) has external calls inside a loop: [_rules[i].messageForTransferRestriction(_restrictionCode)](contracts/mocks/RuleEngine/RuleEngineMock.sol#L89-L90)
contracts/mocks/RuleEngine/RuleEngineMock.sol#L83-L97
- - [ ] ID-7
-[ValidationModuleInternal._operateOnTransfer(address,address,uint256)](contracts/modules/internal/ValidationModuleInternal.sol#L64-L66) has external calls inside a loop: [ruleEngine.operateOnTransfer(from,to,amount)](contracts/modules/internal/ValidationModuleInternal.sol#L65)
+ - [ ] ID-8
+[ValidationModuleInternal._operateOnTransfer(address,address,uint256)](contracts/modules/internal/ValidationModuleInternal.sol#L89-L92) has external calls inside a loop: [$._ruleEngine.operateOnTransfer(from,to,amount)](contracts/modules/internal/ValidationModuleInternal.sol#L91)
-contracts/modules/internal/ValidationModuleInternal.sol#L64-L66
+contracts/modules/internal/ValidationModuleInternal.sol#L89-L92
- - [ ] ID-8
+ - [ ] ID-9
[RuleEngineMock.detectTransferRestriction(address,address,uint256)](contracts/mocks/RuleEngine/RuleEngineMock.sol#L39-L59) has external calls inside a loop: [restriction = _rules[i].detectTransferRestriction(_from,_to,_amount)](contracts/mocks/RuleEngine/RuleEngineMock.sol#L46-L50)
contracts/mocks/RuleEngine/RuleEngineMock.sol#L39-L59
-## reentrancy-benign
-
-> Factory contract : It is not a security issue since only authorized user can call the function
-> CMTAT_BASE._update: the contract called is a trusted contract (RuleEngine)
-
+## timestamp
+> With the Proof of Work, it was possible for a miner to modify the timestamp in a range of about 15 seconds
+>
+> With the Proof Of Stake, a new block is created every 12 seconds
+>
+> In all cases, we are not looking for such precision
Impact: Low
Confidence: Medium
- - [ ] ID-9
- Reentrancy in [CMTAT_BEACON_FACTORY.deployCMTAT(address,IAuthorizationEngine,string,string,uint8,string,string,IRuleEngine,string,uint256)](contracts/deployment/CMTAT_BEACON_FACTORY.sol#L41-L75):
- External calls:
- - [cmtat = new BeaconProxy(address(beacon),abi.encodeWithSelector(CMTAT_PROXY(address(0)).initialize.selector,admin,authorizationEngineIrrevocable,nameIrrevocable,symbolIrrevocable,decimalsIrrevocable,tokenId_,terms_,ruleEngine_,information_,flag_))](contracts/deployment/CMTAT_BEACON_FACTORY.sol#L54-L69)
- State variables written after the call(s):
- - [cmtatCounterId ++](contracts/deployment/CMTAT_BEACON_FACTORY.sol#L72)
- - [cmtats[cmtatCounterId] = address(cmtat)](contracts/deployment/CMTAT_BEACON_FACTORY.sol#L70)
- - [cmtatsList.push(address(cmtat))](contracts/deployment/CMTAT_BEACON_FACTORY.sol#L73)
-
-contracts/deployment/CMTAT_BEACON_FACTORY.sol#L41-L75
-
-
- [ ] ID-10
- Reentrancy in [CMTAT_TP_FACTORY.deployCMTAT(address,address,IAuthorizationEngine,string,string,uint8,string,string,IRuleEngine,string,uint256)](contracts/deployment/CMTAT_TP_FACTORY.sol#L32-L68):
- External calls:
- - [cmtat = new TransparentUpgradeableProxy(logic,proxyAdminOwner,abi.encodeWithSelector(CMTAT_PROXY(address(0)).initialize.selector,admin,authorizationEngineIrrevocable,nameIrrevocable,symbolIrrevocable,decimalsIrrevocable,tokenId_,terms_,ruleEngine_,information_,flag_))](contracts/deployment/CMTAT_TP_FACTORY.sol#L46-L62)
- State variables written after the call(s):
- - [cmtatID ++](contracts/deployment/CMTAT_TP_FACTORY.sol#L65)
- - [cmtats[cmtatID] = address(cmtat)](contracts/deployment/CMTAT_TP_FACTORY.sol#L63)
- - [cmtatsList.push(address(cmtat))](contracts/deployment/CMTAT_TP_FACTORY.sol#L66)
+ [SnapshotModuleBase._findScheduledMostRecentPastSnapshot()](contracts/modules/internal/base/SnapshotModuleBase.sol#L370-L398) uses timestamp for comparisons
+ Dangerous comparisons:
+ - [$._scheduledSnapshots[i] <= block.timestamp](contracts/modules/internal/base/SnapshotModuleBase.sol#L389)
-contracts/deployment/CMTAT_TP_FACTORY.sol#L32-L68
+contracts/modules/internal/base/SnapshotModuleBase.sol#L370-L398
- [ ] ID-11
- Reentrancy in [CMTAT_BASE._update(address,address,uint256)](contracts/modules/CMTAT_BASE.sol#L198-L213):
- External calls:
- - [! ValidationModule._operateOnTransfer(from,to,amount)](contracts/modules/CMTAT_BASE.sol#L203)
- - [ruleEngine.operateOnTransfer(from,to,amount)](contracts/modules/internal/ValidationModuleInternal.sol#L65)
- State variables written after the call(s):
- - [ERC20SnapshotModuleInternal._snapshotUpdate(from,to)](contracts/modules/CMTAT_BASE.sol#L211)
- - [_currentSnapshotIndex = scheduleSnapshotIndex](contracts/modules/internal/base/SnapshotModuleBase.sol#L328)
- - [ERC20SnapshotModuleInternal._snapshotUpdate(from,to)](contracts/modules/CMTAT_BASE.sol#L211)
- - [_currentSnapshotTime = scheduleSnapshotTime](contracts/modules/internal/base/SnapshotModuleBase.sol#L327)
-
-contracts/modules/CMTAT_BASE.sol#L198-L213
+ [DocumentEngineMock.getDocument(bytes32)](contracts/mocks/DocumentEngineMock.sol#L37-L49) uses timestamp for comparisons
+ Dangerous comparisons:
+ - [bytes(documents[name_].uri).length == 0](contracts/mocks/DocumentEngineMock.sol#L43)
-## reentrancy-events
+contracts/mocks/DocumentEngineMock.sol#L37-L49
-> It is not a security issue since only authorized user can call the function
-Impact: Low
-Confidence: Medium
- [ ] ID-12
- Reentrancy in [CMTAT_TP_FACTORY.deployCMTAT(address,address,IAuthorizationEngine,string,string,uint8,string,string,IRuleEngine,string,uint256)](contracts/deployment/CMTAT_TP_FACTORY.sol#L32-L68):
- External calls:
- - [cmtat = new TransparentUpgradeableProxy(logic,proxyAdminOwner,abi.encodeWithSelector(CMTAT_PROXY(address(0)).initialize.selector,admin,authorizationEngineIrrevocable,nameIrrevocable,symbolIrrevocable,decimalsIrrevocable,tokenId_,terms_,ruleEngine_,information_,flag_))](contracts/deployment/CMTAT_TP_FACTORY.sol#L46-L62)
- Event emitted after the call(s):
- - [CMTAT(address(cmtat),cmtatID)](contracts/deployment/CMTAT_TP_FACTORY.sol#L64)
+ [SnapshotModuleBase._checkTimeSnapshotAlreadyDone(uint256)](contracts/modules/internal/base/SnapshotModuleBase.sol#L420-L424) uses timestamp for comparisons
+ Dangerous comparisons:
+ - [time <= block.timestamp](contracts/modules/internal/base/SnapshotModuleBase.sol#L421)
-contracts/deployment/CMTAT_TP_FACTORY.sol#L32-L68
+contracts/modules/internal/base/SnapshotModuleBase.sol#L420-L424
- [ ] ID-13
- Reentrancy in [CMTAT_BEACON_FACTORY.deployCMTAT(address,IAuthorizationEngine,string,string,uint8,string,string,IRuleEngine,string,uint256)](contracts/deployment/CMTAT_BEACON_FACTORY.sol#L41-L75):
- External calls:
- - [cmtat = new BeaconProxy(address(beacon),abi.encodeWithSelector(CMTAT_PROXY(address(0)).initialize.selector,admin,authorizationEngineIrrevocable,nameIrrevocable,symbolIrrevocable,decimalsIrrevocable,tokenId_,terms_,ruleEngine_,information_,flag_))](contracts/deployment/CMTAT_BEACON_FACTORY.sol#L54-L69)
- Event emitted after the call(s):
- - [CMTAT(address(cmtat),cmtatCounterId)](contracts/deployment/CMTAT_BEACON_FACTORY.sol#L71)
+ [SnapshotModuleBase._checkTimeInThePast(uint256)](contracts/modules/internal/base/SnapshotModuleBase.sol#L412-L419) uses timestamp for comparisons
+ Dangerous comparisons:
+ - [time <= block.timestamp](contracts/modules/internal/base/SnapshotModuleBase.sol#L413)
-contracts/deployment/CMTAT_BEACON_FACTORY.sol#L41-L75
+contracts/modules/internal/base/SnapshotModuleBase.sol#L412-L419
-## timestamp
-> With the Proof of Work, it was possible for a miner to modify the timestamp in a range of about 15 seconds
->
-> With the Proof Of Stake, a new block is created every 12 seconds
->
-> In all cases, we are not looking for such precision
-
-Impact: Low
-Confidence: Medium
- [ ] ID-14
- [SnapshotModuleBase._scheduleSnapshotNotOptimized(uint256)](contracts/modules/internal/base/SnapshotModuleBase.sol#L149-L177) uses timestamp for comparisons
+ [DocumentEngineMock.removeDocument(bytes32)](contracts/mocks/DocumentEngineMock.sol#L72-L89) uses timestamp for comparisons
Dangerous comparisons:
- - [time <= block.timestamp](contracts/modules/internal/base/SnapshotModuleBase.sol#L150)
+ - [bytes(documents[name_].uri).length == 0](contracts/mocks/DocumentEngineMock.sol#L73)
+
+contracts/mocks/DocumentEngineMock.sol#L72-L89
-contracts/modules/internal/base/SnapshotModuleBase.sol#L149-L177
+## assembly
+> use to implement ERC-7201
+Impact: Informational
+Confidence: High
- [ ] ID-15
- [SnapshotModuleBase._rescheduleSnapshot(uint256,uint256)](contracts/modules/internal/base/SnapshotModuleBase.sol#L182-L223) uses timestamp for comparisons
- Dangerous comparisons:
- - [oldTime <= block.timestamp](contracts/modules/internal/base/SnapshotModuleBase.sol#L184)
- - [newTime <= block.timestamp](contracts/modules/internal/base/SnapshotModuleBase.sol#L187)
+ [AuthorizationModule._getAuthorizationModuleStorage()](contracts/modules/security/AuthorizationModule.sol#L114-L118) uses assembly
+ - [INLINE ASM](contracts/modules/security/AuthorizationModule.sol#L115-L117)
-contracts/modules/internal/base/SnapshotModuleBase.sol#L182-L223
+contracts/modules/security/AuthorizationModule.sol#L114-L118
- [ ] ID-16
- [SnapshotModuleBase._unscheduleSnapshotNotOptimized(uint256)](contracts/modules/internal/base/SnapshotModuleBase.sol#L250-L263) uses timestamp for comparisons
- Dangerous comparisons:
- - [time <= block.timestamp](contracts/modules/internal/base/SnapshotModuleBase.sol#L251)
+ [EnforcementModuleInternal._getEnforcementModuleInternalStorage()](contracts/modules/internal/EnforcementModuleInternal.sol#L112-L116) uses assembly
+ - [INLINE ASM](contracts/modules/internal/EnforcementModuleInternal.sol#L113-L115)
-contracts/modules/internal/base/SnapshotModuleBase.sol#L250-L263
+contracts/modules/internal/EnforcementModuleInternal.sol#L112-L116
- [ ] ID-17
- [SnapshotModuleBase._scheduleSnapshot(uint256)](contracts/modules/internal/base/SnapshotModuleBase.sol#L118-L144) uses timestamp for comparisons
- Dangerous comparisons:
- - [time <= block.timestamp](contracts/modules/internal/base/SnapshotModuleBase.sol#L120)
+ [BaseModule._getBaseModuleStorage()](contracts/modules/wrapper/core/BaseModule.sol#L110-L114) uses assembly
+ - [INLINE ASM](contracts/modules/wrapper/core/BaseModule.sol#L111-L113)
-contracts/modules/internal/base/SnapshotModuleBase.sol#L118-L144
+contracts/modules/wrapper/core/BaseModule.sol#L110-L114
- [ ] ID-18
- [SnapshotModuleBase._unscheduleLastSnapshot(uint256)](contracts/modules/internal/base/SnapshotModuleBase.sol#L228-L242) uses timestamp for comparisons
- Dangerous comparisons:
- - [time <= block.timestamp](contracts/modules/internal/base/SnapshotModuleBase.sol#L230)
+ [ValidationModuleInternal._getValidationModuleInternalStorage()](contracts/modules/internal/ValidationModuleInternal.sol#L96-L100) uses assembly
+ - [INLINE ASM](contracts/modules/internal/ValidationModuleInternal.sol#L97-L99)
-contracts/modules/internal/base/SnapshotModuleBase.sol#L228-L242
+contracts/modules/internal/ValidationModuleInternal.sol#L96-L100
- [ ] ID-19
- [SnapshotModuleBase._findScheduledMostRecentPastSnapshot()](contracts/modules/internal/base/SnapshotModuleBase.sol#L375-L402) uses timestamp for comparisons
- Dangerous comparisons:
- - [_scheduledSnapshots[i] <= block.timestamp](contracts/modules/internal/base/SnapshotModuleBase.sol#L393)
-
-contracts/modules/internal/base/SnapshotModuleBase.sol#L375-L402
+ [SnapshotModuleBase._getSnapshotModuleBaseStorage()](contracts/modules/internal/base/SnapshotModuleBase.sol#L427-L431) uses assembly
+ - [INLINE ASM](contracts/modules/internal/base/SnapshotModuleBase.sol#L428-L430)
-## costly-loop
+contracts/modules/internal/base/SnapshotModuleBase.sol#L427-L431
-> Inside the function, these two operations are not performed inside a loop.
->
-> It seems that the only loops which calls`setCurrentSnapshot`are inside the batch functions(mintBatch, burnBatch, ...) through a call to the function update.
-> At the moment, there is no trivial solution to resolve this.
-Impact: Informational
-Confidence: Medium
- [ ] ID-20
- [SnapshotModuleBase._setCurrentSnapshot()](contracts/modules/internal/base/SnapshotModuleBase.sol#L321-L330) has costly operations inside a loop:
- - [_currentSnapshotTime = scheduleSnapshotTime](contracts/modules/internal/base/SnapshotModuleBase.sol#L327)
+ [DocumentModule._getDocumentModuleStorage()](contracts/modules/wrapper/extensions/DocumentModule.sol#L96-L100) uses assembly
+ - [INLINE ASM](contracts/modules/wrapper/extensions/DocumentModule.sol#L97-L99)
-contracts/modules/internal/base/SnapshotModuleBase.sol#L321-L330
+contracts/modules/wrapper/extensions/DocumentModule.sol#L96-L100
- [ ] ID-21
- [SnapshotModuleBase._setCurrentSnapshot()](contracts/modules/internal/base/SnapshotModuleBase.sol#L321-L330) has costly operations inside a loop:
- - [_currentSnapshotIndex = scheduleSnapshotIndex](contracts/modules/internal/base/SnapshotModuleBase.sol#L328)
+ [PauseModule._getPauseModuleStorage()](contracts/modules/wrapper/core/PauseModule.sol#L104-L108) uses assembly
+ - [INLINE ASM](contracts/modules/wrapper/core/PauseModule.sol#L105-L107)
-contracts/modules/internal/base/SnapshotModuleBase.sol#L321-L330
+contracts/modules/wrapper/core/PauseModule.sol#L104-L108
+
+
+ - [ ] ID-22
+ [DebtModule._getDebtModuleStorage()](contracts/modules/wrapper/extensions/DebtModule.sol#L94-L98) uses assembly
+ - [INLINE ASM](contracts/modules/wrapper/extensions/DebtModule.sol#L95-L97)
+
+contracts/modules/wrapper/extensions/DebtModule.sol#L94-L98
+
+
+ - [ ] ID-23
+ [ERC20BaseModule._getERC20BaseModuleStorage()](contracts/modules/wrapper/core/ERC20BaseModule.sol#L134-L138) uses assembly
+ - [INLINE ASM](contracts/modules/wrapper/core/ERC20BaseModule.sol#L135-L137)
+
+contracts/modules/wrapper/core/ERC20BaseModule.sol#L134-L138
+
+## costly-loop
+
+> Acknowledge
+>
+> Mocks are not destined to be used in production
+
+Impact: Informational
+Confidence: Medium
+ - [ ] ID-24
+ [DocumentEngineMock.removeDocument(bytes32)](contracts/mocks/DocumentEngineMock.sol#L72-L89) has costly operations inside a loop:
+ - [documentNames.pop()](contracts/mocks/DocumentEngineMock.sol#L83)
+
+contracts/mocks/DocumentEngineMock.sol#L72-L89
## dead-code
@@ -265,29 +253,40 @@ contracts/modules/internal/base/SnapshotModuleBase.sol#L321-L330
Impact: Informational
Confidence: Medium
+ - [ ] ID-25
+[CMTAT_BASE._msgData()](contracts/modules/CMTAT_BASE.sol#L232-L239) is never used and should be removed
- - [ ] ID-22
-[CMTAT_BASE._msgData()](contracts/modules/CMTAT_BASE.sol#L240-L247) is never used and should be removed
-
-contracts/modules/CMTAT_BASE.sol#L240-L247
+contracts/modules/CMTAT_BASE.sol#L232-L239
## solc-version
-> The version set in the config file is 0.8.22
+> The version set in the config file is 0.8.27
Impact: Informational
Confidence: High
- - [ ] ID-23
+ - [ ] ID-26
Version constraint ^0.8.20 contains known severe issues (https://solidity.readthedocs.io/en/latest/bugs.html)
- VerbatimInvalidDeduplication
- FullInlinerNonExpressionSplitArgumentEvaluationOrder
- MissingSideEffectsOnSelectorAccess.
It is used by:
+ - node_modules/@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol#4
+ - node_modules/@openzeppelin/contracts-upgradeable/metatx/ERC2771ContextUpgradeable.sol#4
+ - node_modules/@openzeppelin/contracts-upgradeable/metatx/ERC2771ForwarderUpgradeable.sol#4
+ - node_modules/@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol#4
+ - node_modules/@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol#4
+ - node_modules/@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol#4
+ - node_modules/@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol#4
+ - node_modules/@openzeppelin/contracts-upgradeable/utils/NoncesUpgradeable.sol#3
+ - node_modules/@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol#4
+ - node_modules/@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol#4
+ - node_modules/@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol#4
- node_modules/@openzeppelin/contracts/access/AccessControl.sol#4
- node_modules/@openzeppelin/contracts/access/IAccessControl.sol#4
- node_modules/@openzeppelin/contracts/access/Ownable.sol#4
- node_modules/@openzeppelin/contracts/interfaces/IERC1967.sol#4
- node_modules/@openzeppelin/contracts/interfaces/IERC5267.sol#4
+ - node_modules/@openzeppelin/contracts/interfaces/draft-IERC1822.sol#4
- node_modules/@openzeppelin/contracts/interfaces/draft-IERC6093.sol#3
- node_modules/@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol#4
- node_modules/@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol#4
@@ -302,6 +301,7 @@ Confidence: High
- node_modules/@openzeppelin/contracts/utils/Address.sol#4
- node_modules/@openzeppelin/contracts/utils/Arrays.sol#4
- node_modules/@openzeppelin/contracts/utils/Context.sol#4
+ - node_modules/@openzeppelin/contracts/utils/Create2.sol#4
- node_modules/@openzeppelin/contracts/utils/StorageSlot.sol#5
- node_modules/@openzeppelin/contracts/utils/Strings.sol#4
- node_modules/@openzeppelin/contracts/utils/cryptography/ECDSA.sol#4
@@ -311,19 +311,30 @@ Confidence: High
- node_modules/@openzeppelin/contracts/utils/math/Math.sol#4
- node_modules/@openzeppelin/contracts/utils/math/SignedMath.sol#4
- contracts/CMTAT_PROXY.sol#3
+ - contracts/CMTAT_PROXY_UUPS.sol#3
- contracts/CMTAT_STANDALONE.sol#3
- contracts/deployment/CMTAT_BEACON_FACTORY.sol#2
- contracts/deployment/CMTAT_TP_FACTORY.sol#2
+ - contracts/deployment/CMTAT_UUPS_FACTORY.sol#2
+ - contracts/deployment/libraries/CMTATFactoryBase.sol#2
+ - contracts/deployment/libraries/CMTATFactoryInvariant.sol#2
+ - contracts/deployment/libraries/CMTATFactoryRoot.sol#2
- contracts/interfaces/ICCIPToken.sol#3
+ - contracts/interfaces/ICMTATConstructor.sol#7
- contracts/interfaces/ICMTATSnapshot.sol#3
- - contracts/interfaces/IDebtGlobal.sol#3
- contracts/interfaces/draft-IERC1404/draft-IERC1404.sol#3
- contracts/interfaces/draft-IERC1404/draft-IERC1404EnumCode.sol#3
- contracts/interfaces/draft-IERC1404/draft-IERC1404Wrapper.sol#3
- contracts/interfaces/engine/IAuthorizationEngine.sol#3
+ - contracts/interfaces/engine/IDebtEngine.sol#3
+ - contracts/interfaces/engine/IDebtGlobal.sol#3
- contracts/interfaces/engine/IRuleEngine.sol#3
+ - contracts/interfaces/engine/draft-IERC1643.sol#3
- contracts/libraries/Errors.sol#3
+ - contracts/libraries/FactoryErrors.sol#3
- contracts/mocks/AuthorizationEngineMock.sol#3
+ - contracts/mocks/DebtEngineMock.sol#3
+ - contracts/mocks/DocumentEngineMock.sol#3
- contracts/mocks/MinimalForwarderMock.sol#3
- contracts/mocks/RuleEngine/CodeList.sol#3
- contracts/mocks/RuleEngine/RuleEngineMock.sol#3
@@ -343,21 +354,12 @@ Confidence: High
- contracts/modules/wrapper/core/ERC20MintModule.sol#3
- contracts/modules/wrapper/core/EnforcementModule.sol#3
- contracts/modules/wrapper/core/PauseModule.sol#3
- - contracts/modules/wrapper/extensions/DebtModule/CreditEventsModule.sol#3
- - contracts/modules/wrapper/extensions/DebtModule/DebtBaseModule.sol#3
+ - contracts/modules/wrapper/extensions/DebtModule.sol#3
+ - contracts/modules/wrapper/extensions/DocumentModule.sol#3
- contracts/modules/wrapper/extensions/ERC20SnapshotModule.sol#3
- contracts/modules/wrapper/extensions/MetaTxModule.sol#3
- - contracts/test/proxy/CMTAT_PROXY.sol#3
- - openzeppelin-contracts-upgradeable/contracts/access/AccessControlUpgradeable.sol#4
- - openzeppelin-contracts-upgradeable/contracts/metatx/ERC2771ContextUpgradeable.sol#4
- - openzeppelin-contracts-upgradeable/contracts/metatx/ERC2771ForwarderUpgradeable.sol#4
- - openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol#4
- - openzeppelin-contracts-upgradeable/contracts/token/ERC20/ERC20Upgradeable.sol#4
- - openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol#4
- - openzeppelin-contracts-upgradeable/contracts/utils/NoncesUpgradeable.sol#3
- - openzeppelin-contracts-upgradeable/contracts/utils/PausableUpgradeable.sol#4
- - openzeppelin-contracts-upgradeable/contracts/utils/cryptography/EIP712Upgradeable.sol#4
- - openzeppelin-contracts-upgradeable/contracts/utils/introspection/ERC165Upgradeable.sol#4
+ - contracts/test/proxy/CMTAT_PROXY_TEST.sol#3
+ - contracts/test/proxy/CMTAT_PROXY_TEST_UUPS.sol#3
## naming-convention
@@ -366,344 +368,375 @@ Confidence: High
Impact: Informational
Confidence: High
- - [ ] ID-24
-Enum [IERC1404EnumCode.REJECTED_CODE_BASE](contracts/interfaces/draft-IERC1404/draft-IERC1404EnumCode.sol#L9-L14) is not in CapWords
-
-contracts/interfaces/draft-IERC1404/draft-IERC1404EnumCode.sol#L9-L14
-
-
- - [ ] ID-25
-Variable [CreditEventsModule.__gap](contracts/modules/wrapper/extensions/DebtModule/CreditEventsModule.sol#L83) is not in mixedCase
-
-contracts/modules/wrapper/extensions/DebtModule/CreditEventsModule.sol#L83
-
-
- - [ ] ID-26
-Parameter [RuleEngineMock.detectTransferRestriction(address,address,uint256)._amount](contracts/mocks/RuleEngine/RuleEngineMock.sol#L42) is not in mixedCase
-
-contracts/mocks/RuleEngine/RuleEngineMock.sol#L42
-
-
- [ ] ID-27
-Contract [CMTAT_PROXY](contracts/CMTAT_PROXY.sol#L7-L21) is not in CapWords
+Contract [CMTAT_PROXY_UUPS](contracts/CMTAT_PROXY_UUPS.sol#L10-L53) is not in CapWords
-contracts/CMTAT_PROXY.sol#L7-L21
+contracts/CMTAT_PROXY_UUPS.sol#L10-L53
- [ ] ID-28
-Function [PauseModule.__PauseModule_init_unchained()](contracts/modules/wrapper/core/PauseModule.sol#L26-L28) is not in mixedCase
+Enum [IERC1404EnumCode.REJECTED_CODE_BASE](contracts/interfaces/draft-IERC1404/draft-IERC1404EnumCode.sol#L9-L14) is not in CapWords
-contracts/modules/wrapper/core/PauseModule.sol#L26-L28
+contracts/interfaces/draft-IERC1404/draft-IERC1404EnumCode.sol#L9-L14
- [ ] ID-29
-Function [CreditEventsModule.__CreditEvents_init_unchained()](contracts/modules/wrapper/extensions/DebtModule/CreditEventsModule.sol#L28-L30) is not in mixedCase
+Constant [EnforcementModuleInternal.EnforcementModuleInternalStorageLocation](contracts/modules/internal/EnforcementModuleInternal.sol#L41) is not in UPPER_CASE_WITH_UNDERSCORES
-contracts/modules/wrapper/extensions/DebtModule/CreditEventsModule.sol#L28-L30
+contracts/modules/internal/EnforcementModuleInternal.sol#L41
- [ ] ID-30
-Variable [CMTAT_BASE.__gap](contracts/modules/CMTAT_BASE.sol#L249) is not in mixedCase
+Function [CMTATFactoryRoot.CMTATProxyAddress(uint256)](contracts/deployment/libraries/CMTATFactoryRoot.sol#L48-L50) is not in mixedCase
-contracts/modules/CMTAT_BASE.sol#L249
+contracts/deployment/libraries/CMTATFactoryRoot.sol#L48-L50
- [ ] ID-31
-Function [EnforcementModuleInternal.__Enforcement_init_unchained()](contracts/modules/internal/EnforcementModuleInternal.sol#L40-L42) is not in mixedCase
+Parameter [RuleEngineMock.detectTransferRestriction(address,address,uint256)._amount](contracts/mocks/RuleEngine/RuleEngineMock.sol#L42) is not in mixedCase
-contracts/modules/internal/EnforcementModuleInternal.sol#L40-L42
+contracts/mocks/RuleEngine/RuleEngineMock.sol#L42
- [ ] ID-32
-Variable [ValidationModuleInternal.__gap](contracts/modules/internal/ValidationModuleInternal.sol#L68) is not in mixedCase
+Constant [PauseModule.PauseModuleStorageLocation](contracts/modules/wrapper/core/PauseModule.sol#L28) is not in UPPER_CASE_WITH_UNDERSCORES
-contracts/modules/internal/ValidationModuleInternal.sol#L68
+contracts/modules/wrapper/core/PauseModule.sol#L28
- [ ] ID-33
-Function [ERC20BurnModule.__ERC20BurnModule_init_unchained()](contracts/modules/wrapper/core/ERC20BurnModule.sol#L19-L21) is not in mixedCase
+Contract [CMTAT_UUPS_FACTORY](contracts/deployment/CMTAT_UUPS_FACTORY.sol#L15-L92) is not in CapWords
-contracts/modules/wrapper/core/ERC20BurnModule.sol#L19-L21
+contracts/deployment/CMTAT_UUPS_FACTORY.sol#L15-L92
- [ ] ID-34
-Function [ValidationModuleInternal.__Validation_init_unchained(IRuleEngine)](contracts/modules/internal/ValidationModuleInternal.sol#L24-L31) is not in mixedCase
+Contract [CMTAT_PROXY](contracts/CMTAT_PROXY.sol#L10-L22) is not in CapWords
-contracts/modules/internal/ValidationModuleInternal.sol#L24-L31
+contracts/CMTAT_PROXY.sol#L10-L22
- [ ] ID-35
-Variable [BaseModule.__gap](contracts/modules/wrapper/core/BaseModule.sol#L94) is not in mixedCase
+Function [PauseModule.__PauseModule_init_unchained()](contracts/modules/wrapper/core/PauseModule.sol#L34-L36) is not in mixedCase
-contracts/modules/wrapper/core/BaseModule.sol#L94
+contracts/modules/wrapper/core/PauseModule.sol#L34-L36
- [ ] ID-36
-Variable [ValidationModule.__gap](contracts/modules/wrapper/controllers/ValidationModule.sol#L136) is not in mixedCase
+Function [BaseModule.__Base_init_unchained(string,string,string)](contracts/modules/wrapper/core/BaseModule.sol#L42-L51) is not in mixedCase
-contracts/modules/wrapper/controllers/ValidationModule.sol#L136
+contracts/modules/wrapper/core/BaseModule.sol#L42-L51
- [ ] ID-37
-Variable [EnforcementModule.__gap](contracts/modules/wrapper/core/EnforcementModule.sol#L55) is not in mixedCase
+Function [EnforcementModuleInternal.__Enforcement_init_unchained()](contracts/modules/internal/EnforcementModuleInternal.sol#L53-L55) is not in mixedCase
-contracts/modules/wrapper/core/EnforcementModule.sol#L55
+contracts/modules/internal/EnforcementModuleInternal.sol#L53-L55
- [ ] ID-38
-Contract [CMTAT_STANDALONE](contracts/CMTAT_STANDALONE.sol#L7-L53) is not in CapWords
+Struct [CMTATFactoryInvariant.CMTAT_ARGUMENT](contracts/deployment/libraries/CMTATFactoryInvariant.sol#L13-L18) is not in CapWords
-contracts/CMTAT_STANDALONE.sol#L7-L53
+contracts/deployment/libraries/CMTATFactoryInvariant.sol#L13-L18
- [ ] ID-39
-Variable [DebtBaseModule.__gap](contracts/modules/wrapper/extensions/DebtModule/DebtBaseModule.sol#L232) is not in mixedCase
+Function [ERC20BurnModule.__ERC20BurnModule_init_unchained()](contracts/modules/wrapper/core/ERC20BurnModule.sol#L32-L34) is not in mixedCase
-contracts/modules/wrapper/extensions/DebtModule/DebtBaseModule.sol#L232
+contracts/modules/wrapper/core/ERC20BurnModule.sol#L32-L34
- [ ] ID-40
-Variable [AuthorizationModule.__gap](contracts/modules/security/AuthorizationModule.sol#L85) is not in mixedCase
+Function [ValidationModuleInternal.__Validation_init_unchained(IRuleEngine)](contracts/modules/internal/ValidationModuleInternal.sol#L30-L38) is not in mixedCase
-contracts/modules/security/AuthorizationModule.sol#L85
+contracts/modules/internal/ValidationModuleInternal.sol#L30-L38
- [ ] ID-41
-Parameter [RuleEngineMock.operateOnTransfer(address,address,uint256)._to](contracts/mocks/RuleEngine/RuleEngineMock.sol#L74) is not in mixedCase
+Constant [ValidationModuleInternal.ValidationModuleInternalStorageLocation](contracts/modules/internal/ValidationModuleInternal.sol#L24) is not in UPPER_CASE_WITH_UNDERSCORES
-contracts/mocks/RuleEngine/RuleEngineMock.sol#L74
+contracts/modules/internal/ValidationModuleInternal.sol#L24
- [ ] ID-42
-Parameter [RuleEngineMock.validateTransfer(address,address,uint256)._amount](contracts/mocks/RuleEngine/RuleEngineMock.sol#L64) is not in mixedCase
+Contract [CMTAT_STANDALONE](contracts/CMTAT_STANDALONE.sol#L10-L36) is not in CapWords
-contracts/mocks/RuleEngine/RuleEngineMock.sol#L64
+contracts/CMTAT_STANDALONE.sol#L10-L36
- [ ] ID-43
-Parameter [RuleEngineMock.operateOnTransfer(address,address,uint256)._from](contracts/mocks/RuleEngine/RuleEngineMock.sol#L73) is not in mixedCase
+Parameter [RuleEngineMock.operateOnTransfer(address,address,uint256)._to](contracts/mocks/RuleEngine/RuleEngineMock.sol#L74) is not in mixedCase
-contracts/mocks/RuleEngine/RuleEngineMock.sol#L73
+contracts/mocks/RuleEngine/RuleEngineMock.sol#L74
- [ ] ID-44
-Parameter [RuleMock.validateTransfer(address,address,uint256)._to](contracts/mocks/RuleEngine/RuleMock.sol#L14) is not in mixedCase
+Parameter [RuleEngineMock.validateTransfer(address,address,uint256)._amount](contracts/mocks/RuleEngine/RuleEngineMock.sol#L64) is not in mixedCase
-contracts/mocks/RuleEngine/RuleMock.sol#L14
+contracts/mocks/RuleEngine/RuleEngineMock.sol#L64
- [ ] ID-45
-Parameter [RuleEngineMock.operateOnTransfer(address,address,uint256)._amount](contracts/mocks/RuleEngine/RuleEngineMock.sol#L75) is not in mixedCase
+Parameter [RuleEngineMock.operateOnTransfer(address,address,uint256)._from](contracts/mocks/RuleEngine/RuleEngineMock.sol#L73) is not in mixedCase
-contracts/mocks/RuleEngine/RuleEngineMock.sol#L75
+contracts/mocks/RuleEngine/RuleEngineMock.sol#L73
- [ ] ID-46
-Variable [EnforcementModuleInternal.__gap](contracts/modules/internal/EnforcementModuleInternal.sol#L87) is not in mixedCase
+Parameter [RuleMock.validateTransfer(address,address,uint256)._to](contracts/mocks/RuleEngine/RuleMock.sol#L14) is not in mixedCase
-contracts/modules/internal/EnforcementModuleInternal.sol#L87
+contracts/mocks/RuleEngine/RuleMock.sol#L14
- [ ] ID-47
-Parameter [RuleMock.canReturnTransferRestrictionCode(uint8)._restrictionCode](contracts/mocks/RuleEngine/RuleMock.sol#L35) is not in mixedCase
+Parameter [RuleEngineMock.operateOnTransfer(address,address,uint256)._amount](contracts/mocks/RuleEngine/RuleEngineMock.sol#L75) is not in mixedCase
-contracts/mocks/RuleEngine/RuleMock.sol#L35
+contracts/mocks/RuleEngine/RuleEngineMock.sol#L75
- [ ] ID-48
-Variable [SnapshotModuleBase.__gap](contracts/modules/internal/base/SnapshotModuleBase.sol#L404) is not in mixedCase
+Parameter [RuleMock.canReturnTransferRestrictionCode(uint8)._restrictionCode](contracts/mocks/RuleEngine/RuleMock.sol#L35) is not in mixedCase
-contracts/modules/internal/base/SnapshotModuleBase.sol#L404
+contracts/mocks/RuleEngine/RuleMock.sol#L35
- [ ] ID-49
-Parameter [RuleEngineMock.validateTransfer(address,address,uint256)._to](contracts/mocks/RuleEngine/RuleEngineMock.sol#L63) is not in mixedCase
+Function [DebtModule.__DebtModule_init_unchained(IDebtEngine)](contracts/modules/wrapper/extensions/DebtModule.sol#L41-L50) is not in mixedCase
-contracts/mocks/RuleEngine/RuleEngineMock.sol#L63
+contracts/modules/wrapper/extensions/DebtModule.sol#L41-L50
- [ ] ID-50
-Function [BaseModule.__Base_init_unchained(string,string,string,uint256)](contracts/modules/wrapper/core/BaseModule.sol#L40-L50) is not in mixedCase
+Parameter [RuleEngineMock.validateTransfer(address,address,uint256)._to](contracts/mocks/RuleEngine/RuleEngineMock.sol#L63) is not in mixedCase
-contracts/modules/wrapper/core/BaseModule.sol#L40-L50
+contracts/mocks/RuleEngine/RuleEngineMock.sol#L63
- [ ] ID-51
-Function [AuthorizationModule.__AuthorizationModule_init_unchained(address,IAuthorizationEngine)](contracts/modules/security/AuthorizationModule.sol#L22-L33) is not in mixedCase
+Function [DocumentModule.__DocumentModule_init_unchained(IERC1643)](contracts/modules/wrapper/extensions/DocumentModule.sol#L41-L48) is not in mixedCase
-contracts/modules/security/AuthorizationModule.sol#L22-L33
+contracts/modules/wrapper/extensions/DocumentModule.sol#L41-L48
- [ ] ID-52
-Parameter [RuleEngineMock.validateTransfer(address,address,uint256)._from](contracts/mocks/RuleEngine/RuleEngineMock.sol#L62) is not in mixedCase
+Parameter [DocumentModule.getDocument(bytes32)._name](contracts/modules/wrapper/extensions/DocumentModule.sol#L74) is not in mixedCase
-contracts/mocks/RuleEngine/RuleEngineMock.sol#L62
+contracts/modules/wrapper/extensions/DocumentModule.sol#L74
- [ ] ID-53
-Parameter [RuleMock.validateTransfer(address,address,uint256)._amount](contracts/mocks/RuleEngine/RuleMock.sol#L15) is not in mixedCase
+Constant [SnapshotModuleBase.SnapshotModuleBaseStorageLocation](contracts/modules/internal/base/SnapshotModuleBase.sol#L45) is not in UPPER_CASE_WITH_UNDERSCORES
-contracts/mocks/RuleEngine/RuleMock.sol#L15
+contracts/modules/internal/base/SnapshotModuleBase.sol#L45
- [ ] ID-54
-Variable [PauseModule.__gap](contracts/modules/wrapper/core/PauseModule.sol#L83) is not in mixedCase
+Function [AuthorizationModule.__AuthorizationModule_init_unchained(address,IAuthorizationEngine)](contracts/modules/security/AuthorizationModule.sol#L30-L41) is not in mixedCase
-contracts/modules/wrapper/core/PauseModule.sol#L83
+contracts/modules/security/AuthorizationModule.sol#L30-L41
- [ ] ID-55
-Function [CMTAT_BASE.__CMTAT_init_unchained()](contracts/modules/CMTAT_BASE.sol#L148-L150) is not in mixedCase
+Function [CMTAT_BASE.__CMTAT_init(address,ICMTATConstructor.ERC20Attributes,ICMTATConstructor.BaseModuleAttributes,ICMTATConstructor.Engine)](contracts/modules/CMTAT_BASE.sol#L77-L129) is not in mixedCase
-contracts/modules/CMTAT_BASE.sol#L148-L150
+contracts/modules/CMTAT_BASE.sol#L77-L129
- [ ] ID-56
-Variable [ERC20SnapshotModule.__gap](contracts/modules/wrapper/extensions/ERC20SnapshotModule.sol#L77) is not in mixedCase
+Constant [ERC20BaseModule.ERC20BaseModuleStorageLocation](contracts/modules/wrapper/core/ERC20BaseModule.sol#L26) is not in UPPER_CASE_WITH_UNDERSCORES
-contracts/modules/wrapper/extensions/ERC20SnapshotModule.sol#L77
+contracts/modules/wrapper/core/ERC20BaseModule.sol#L26
- [ ] ID-57
-Parameter [RuleMock.detectTransferRestriction(address,address,uint256)._amount](contracts/mocks/RuleEngine/RuleMock.sol#L26) is not in mixedCase
+Parameter [RuleEngineMock.validateTransfer(address,address,uint256)._from](contracts/mocks/RuleEngine/RuleEngineMock.sol#L62) is not in mixedCase
-contracts/mocks/RuleEngine/RuleMock.sol#L26
+contracts/mocks/RuleEngine/RuleEngineMock.sol#L62
- [ ] ID-58
-Function [ERC20BaseModule.__ERC20BaseModule_init_unchained(uint8)](contracts/modules/wrapper/core/ERC20BaseModule.sol#L28-L32) is not in mixedCase
+Parameter [RuleMock.validateTransfer(address,address,uint256)._amount](contracts/mocks/RuleEngine/RuleMock.sol#L15) is not in mixedCase
-contracts/modules/wrapper/core/ERC20BaseModule.sol#L28-L32
+contracts/mocks/RuleEngine/RuleMock.sol#L15
- [ ] ID-59
-Parameter [RuleMock.messageForTransferRestriction(uint8)._restrictionCode](contracts/mocks/RuleEngine/RuleMock.sol#L41) is not in mixedCase
+Parameter [CMTAT_PROXY_UUPS.initialize(address,ICMTATConstructor.ERC20Attributes,ICMTATConstructor.BaseModuleAttributes,ICMTATConstructor.Engine).ERC20Attributes_](contracts/CMTAT_PROXY_UUPS.sol#L38) is not in mixedCase
-contracts/mocks/RuleEngine/RuleMock.sol#L41
+contracts/CMTAT_PROXY_UUPS.sol#L38
- [ ] ID-60
-Function [CMTAT_BASE.__CMTAT_init(address,IAuthorizationEngine,string,string,uint8,string,string,IRuleEngine,string,uint256)](contracts/modules/CMTAT_BASE.sol#L87-L146) is not in mixedCase
+Parameter [CMTAT_BASE.initialize(address,ICMTATConstructor.ERC20Attributes,ICMTATConstructor.BaseModuleAttributes,ICMTATConstructor.Engine).ERC20Attributes_](contracts/modules/CMTAT_BASE.sol#L61) is not in mixedCase
-contracts/modules/CMTAT_BASE.sol#L87-L146
+contracts/modules/CMTAT_BASE.sol#L61
- [ ] ID-61
-Function [ERC20MintModule.__ERC20MintModule_init_unchained()](contracts/modules/wrapper/core/ERC20MintModule.sol#L17-L19) is not in mixedCase
+Function [CMTAT_BASE.__CMTAT_init_unchained()](contracts/modules/CMTAT_BASE.sol#L131-L133) is not in mixedCase
-contracts/modules/wrapper/core/ERC20MintModule.sol#L17-L19
+contracts/modules/CMTAT_BASE.sol#L131-L133
- [ ] ID-62
-Parameter [RuleEngineMock.detectTransferRestriction(address,address,uint256)._to](contracts/mocks/RuleEngine/RuleEngineMock.sol#L41) is not in mixedCase
+Constant [DocumentModule.DocumentModuleStorageLocation](contracts/modules/wrapper/extensions/DocumentModule.sol#L27) is not in UPPER_CASE_WITH_UNDERSCORES
-contracts/mocks/RuleEngine/RuleEngineMock.sol#L41
+contracts/modules/wrapper/extensions/DocumentModule.sol#L27
- [ ] ID-63
-Variable [MetaTxModule.__gap](contracts/modules/wrapper/extensions/MetaTxModule.sol#L22) is not in mixedCase
+Parameter [RuleMock.detectTransferRestriction(address,address,uint256)._amount](contracts/mocks/RuleEngine/RuleMock.sol#L26) is not in mixedCase
-contracts/modules/wrapper/extensions/MetaTxModule.sol#L22
+contracts/mocks/RuleEngine/RuleMock.sol#L26
- [ ] ID-64
-Function [SnapshotModuleBase.__SnapshotModuleBase_init_unchained()](contracts/modules/internal/base/SnapshotModuleBase.sol#L64-L67) is not in mixedCase
+Function [ERC20BaseModule.__ERC20BaseModule_init_unchained(uint8)](contracts/modules/wrapper/core/ERC20BaseModule.sol#L39-L44) is not in mixedCase
-contracts/modules/internal/base/SnapshotModuleBase.sol#L64-L67
+contracts/modules/wrapper/core/ERC20BaseModule.sol#L39-L44
- [ ] ID-65
-Variable [ERC20BurnModule.__gap](contracts/modules/wrapper/core/ERC20BurnModule.sol#L113) is not in mixedCase
+Parameter [RuleMock.messageForTransferRestriction(uint8)._restrictionCode](contracts/mocks/RuleEngine/RuleMock.sol#L41) is not in mixedCase
-contracts/modules/wrapper/core/ERC20BurnModule.sol#L113
+contracts/mocks/RuleEngine/RuleMock.sol#L41
- [ ] ID-66
-Variable [ERC20BaseModule.__gap](contracts/modules/wrapper/core/ERC20BaseModule.sol#L113) is not in mixedCase
+Constant [AuthorizationModule.AuthorizationModuleStorageLocation](contracts/modules/security/AuthorizationModule.sol#L17) is not in UPPER_CASE_WITH_UNDERSCORES
-contracts/modules/wrapper/core/ERC20BaseModule.sol#L113
+contracts/modules/security/AuthorizationModule.sol#L17
- [ ] ID-67
-Contract [CMTAT_BEACON_FACTORY](contracts/deployment/CMTAT_BEACON_FACTORY.sol#L15-L93) is not in CapWords
+Function [ERC20MintModule.__ERC20MintModule_init_unchained()](contracts/modules/wrapper/core/ERC20MintModule.sol#L27-L29) is not in mixedCase
-contracts/deployment/CMTAT_BEACON_FACTORY.sol#L15-L93
+contracts/modules/wrapper/core/ERC20MintModule.sol#L27-L29
- [ ] ID-68
-Contract [CMTAT_BASE](contracts/modules/CMTAT_BASE.sol#L29-L250) is not in CapWords
+Parameter [RuleEngineMock.detectTransferRestriction(address,address,uint256)._to](contracts/mocks/RuleEngine/RuleEngineMock.sol#L41) is not in mixedCase
-contracts/modules/CMTAT_BASE.sol#L29-L250
+contracts/mocks/RuleEngine/RuleEngineMock.sol#L41
- [ ] ID-69
-Parameter [RuleEngineMock.messageForTransferRestriction(uint8)._restrictionCode](contracts/mocks/RuleEngine/RuleEngineMock.sol#L84) is not in mixedCase
+Constant [BaseModule.BaseModuleStorageLocation](contracts/modules/wrapper/core/BaseModule.sol#L27) is not in UPPER_CASE_WITH_UNDERSCORES
-contracts/mocks/RuleEngine/RuleEngineMock.sol#L84
+contracts/modules/wrapper/core/BaseModule.sol#L27
- [ ] ID-70
-Variable [ERC20MintModule.__gap](contracts/modules/wrapper/core/ERC20MintModule.sol#L73) is not in mixedCase
+Function [SnapshotModuleBase.__SnapshotModuleBase_init_unchained()](contracts/modules/internal/base/SnapshotModuleBase.sol#L70-L73) is not in mixedCase
-contracts/modules/wrapper/core/ERC20MintModule.sol#L73
+contracts/modules/internal/base/SnapshotModuleBase.sol#L70-L73
- [ ] ID-71
-Function [ValidationModule.__ValidationModule_init_unchained()](contracts/modules/wrapper/controllers/ValidationModule.sol#L26-L28) is not in mixedCase
+Contract [CMTAT_BEACON_FACTORY](contracts/deployment/CMTAT_BEACON_FACTORY.sol#L16-L111) is not in CapWords
-contracts/modules/wrapper/controllers/ValidationModule.sol#L26-L28
+contracts/deployment/CMTAT_BEACON_FACTORY.sol#L16-L111
- [ ] ID-72
-Function [DebtBaseModule.__DebtBaseModule_init_unchained()](contracts/modules/wrapper/extensions/DebtModule/DebtBaseModule.sol#L60-L62) is not in mixedCase
+Parameter [CMTAT_BASE.__CMTAT_init(address,ICMTATConstructor.ERC20Attributes,ICMTATConstructor.BaseModuleAttributes,ICMTATConstructor.Engine).ERC20Attributes_](contracts/modules/CMTAT_BASE.sol#L79) is not in mixedCase
-contracts/modules/wrapper/extensions/DebtModule/DebtBaseModule.sol#L60-L62
+contracts/modules/CMTAT_BASE.sol#L79
- [ ] ID-73
-Parameter [RuleEngineMock.detectTransferRestriction(address,address,uint256)._from](contracts/mocks/RuleEngine/RuleEngineMock.sol#L40) is not in mixedCase
+Contract [CMTAT_BASE](contracts/modules/CMTAT_BASE.sol#L29-L240) is not in CapWords
-contracts/mocks/RuleEngine/RuleEngineMock.sol#L40
+contracts/modules/CMTAT_BASE.sol#L29-L240
- [ ] ID-74
-Function [ERC20SnapshotModule.__ERC20SnasphotModule_init_unchained()](contracts/modules/wrapper/extensions/ERC20SnapshotModule.sol#L20-L22) is not in mixedCase
+Parameter [RuleEngineMock.messageForTransferRestriction(uint8)._restrictionCode](contracts/mocks/RuleEngine/RuleEngineMock.sol#L84) is not in mixedCase
-contracts/modules/wrapper/extensions/ERC20SnapshotModule.sol#L20-L22
+contracts/mocks/RuleEngine/RuleEngineMock.sol#L84
- [ ] ID-75
-Variable [ERC20SnapshotModuleInternal.__gap](contracts/modules/internal/ERC20SnapshotModuleInternal.sol#L140) is not in mixedCase
+Function [ValidationModule.__ValidationModule_init_unchained()](contracts/modules/wrapper/controllers/ValidationModule.sol#L28-L30) is not in mixedCase
-contracts/modules/internal/ERC20SnapshotModuleInternal.sol#L140
+contracts/modules/wrapper/controllers/ValidationModule.sol#L28-L30
- [ ] ID-76
-Function [EnforcementModule.__EnforcementModule_init_unchained()](contracts/modules/wrapper/core/EnforcementModule.sol#L25-L27) is not in mixedCase
+Parameter [RuleEngineMock.detectTransferRestriction(address,address,uint256)._from](contracts/mocks/RuleEngine/RuleEngineMock.sol#L40) is not in mixedCase
-contracts/modules/wrapper/core/EnforcementModule.sol#L25-L27
+contracts/mocks/RuleEngine/RuleEngineMock.sol#L40
- [ ] ID-77
-Function [ERC20SnapshotModuleInternal.__ERC20Snapshot_init_unchained()](contracts/modules/internal/ERC20SnapshotModuleInternal.sol#L27-L30) is not in mixedCase
+Constant [DebtModule.DebtModuleStorageLocation](contracts/modules/wrapper/extensions/DebtModule.sol#L20) is not in UPPER_CASE_WITH_UNDERSCORES
-contracts/modules/internal/ERC20SnapshotModuleInternal.sol#L27-L30
+contracts/modules/wrapper/extensions/DebtModule.sol#L20
- [ ] ID-78
-Contract [CMTAT_TP_FACTORY](contracts/deployment/CMTAT_TP_FACTORY.sol#L11-L78) is not in CapWords
+Function [ERC20SnapshotModule.__ERC20SnasphotModule_init_unchained()](contracts/modules/wrapper/extensions/ERC20SnapshotModule.sol#L22-L24) is not in mixedCase
-contracts/deployment/CMTAT_TP_FACTORY.sol#L11-L78
+contracts/modules/wrapper/extensions/ERC20SnapshotModule.sol#L22-L24
- [ ] ID-79
+Function [EnforcementModule.__EnforcementModule_init_unchained()](contracts/modules/wrapper/core/EnforcementModule.sol#L27-L29) is not in mixedCase
+
+contracts/modules/wrapper/core/EnforcementModule.sol#L27-L29
+
+
+ - [ ] ID-80
+Function [ERC20SnapshotModuleInternal.__ERC20Snapshot_init_unchained()](contracts/modules/internal/ERC20SnapshotModuleInternal.sol#L21-L24) is not in mixedCase
+
+contracts/modules/internal/ERC20SnapshotModuleInternal.sol#L21-L24
+
+
+ - [ ] ID-81
+Contract [CMTAT_TP_FACTORY](contracts/deployment/CMTAT_TP_FACTORY.sol#L14-L92) is not in CapWords
+
+contracts/deployment/CMTAT_TP_FACTORY.sol#L14-L92
+
+
+ - [ ] ID-82
Parameter [RuleMock.validateTransfer(address,address,uint256)._from](contracts/mocks/RuleEngine/RuleMock.sol#L13) is not in mixedCase
contracts/mocks/RuleEngine/RuleMock.sol#L13
- - [ ] ID-80
-Variable [CMTAT_PROXY.__gap](contracts/CMTAT_PROXY.sol#L20) is not in mixedCase
+## similar-names
+Impact: Informational
+Confidence: Medium
+ - [ ] ID-83
+Variable [IERC1643Whole.setDocument(bytes32,string,bytes32)._documentHash](contracts/mocks/DocumentEngineMock.sol#L8) is too similar to [DocumentEngineMock.setDocument(bytes32,string,bytes32).documentHash_](contracts/mocks/DocumentEngineMock.sol#L55)
+
+contracts/mocks/DocumentEngineMock.sol#L8
+
+
+ - [ ] ID-84
+Variable [CMTAT_BEACON_FACTORY._getBytecode(CMTATFactoryInvariant.CMTAT_ARGUMENT)._implementation](contracts/deployment/CMTAT_BEACON_FACTORY.sol#L101-L107) is too similar to [CMTAT_BEACON_FACTORY.constructor(address,address,address,bool).implementation_](contracts/deployment/CMTAT_BEACON_FACTORY.sol#L24)
+
+contracts/deployment/CMTAT_BEACON_FACTORY.sol#L101-L107
+
+
+ - [ ] ID-85
+Variable [DebtEngineMock._creditEvents](contracts/mocks/DebtEngineMock.sol#L15) is too similar to [DebtEngineMock.setCreditEvents(IDebtGlobal.CreditEvents).creditEvents_](contracts/mocks/DebtEngineMock.sol#L29)
+
+contracts/mocks/DebtEngineMock.sol#L15
+
+
+## too-many-digits
+Impact: Informational
+Confidence: Medium
+ - [ ] ID-86
+ [CMTAT_BEACON_FACTORY._getBytecode(CMTATFactoryInvariant.CMTAT_ARGUMENT)](contracts/deployment/CMTAT_BEACON_FACTORY.sol#L98-L109) uses literals with too many digits:
+ - [bytecode = abi.encodePacked(type()(BeaconProxy).creationCode,abi.encode(address(beacon),_implementation))](contracts/deployment/CMTAT_BEACON_FACTORY.sol#L108)
+
+contracts/deployment/CMTAT_BEACON_FACTORY.sol#L98-L109
+
-contracts/CMTAT_PROXY.sol#L20
+ - [ ] ID-87
+ [CMTAT_TP_FACTORY._getBytecode(address,CMTATFactoryInvariant.CMTAT_ARGUMENT)](contracts/deployment/CMTAT_TP_FACTORY.sol#L79-L90) uses literals with too many digits:
+ - [bytecode = abi.encodePacked(type()(TransparentUpgradeableProxy).creationCode,abi.encode(logic,proxyAdminOwner,implementation))](contracts/deployment/CMTAT_TP_FACTORY.sol#L89)
+contracts/deployment/CMTAT_TP_FACTORY.sol#L79-L90
diff --git a/doc/general/ARCHITECTURE.md b/doc/general/ARCHITECTURE.md
index 9dbb66de..ede6ba12 100644
--- a/doc/general/ARCHITECTURE.md
+++ b/doc/general/ARCHITECTURE.md
@@ -5,18 +5,17 @@ This documents presents an overview of the CMTAT architecture.
## Introduction
-There are two mains contracts for deployment:
-[CMTAT_PROXY.sol](../../contracts/CMTAT_PROXY.sol) and
-[CMTAT_STANDALONE.sol](../../contracts/CMTAT_STANDALONE.sol), to deploy
-the CMTAT either with proxy or without, respectively.
+There are three mains contracts for deployment:
-These contracts inherit from the same base contract
-[CMTAT_BASE.sol](../contracts/modules/CMTAT_BASE.sol), which inherits of
-the different modules.
+| Model | Contract |
+| --------------------------- | -------------------------------------------------------- |
+| Standalone | [CMTAT_STANDALONE](../../contracts/CMTAT_STANDALONE.sol) |
+| Transparent or Beacon Proxy | [CMTAT_PROXY](../../contracts/CMTAT_PROXY.sol) |
+| UUPS Proxy | [CMTAT_PROXY_UUPS](../../contracts/CMTAT_PROXY_UUPS.sol) |
-The main schema describing the architecture can be found here: [architecture.pdf](../schema/drawio/architecture.pdf)
+These contracts inherit from the same base contract [CMTAT_BASE.sol](../contracts/modules/CMTAT_BASE.sol), which inherits of the different modules.
-Small change with the PDF: the snapshotModule is now included by default.
+The main schema describing the architecture can be found here: [architecture.pdf](../schema/drawio/architecture.pdf)
## Schema
@@ -37,6 +36,16 @@ This section presents the different schema:
![surya_inheritance_CMTAT_STANDALONE.sol](../schema/surya_inheritance/surya_inheritance_CMTAT_STANDALONE.sol.png)
+
+
+#### UUPS Proxy
+
+![surya_inheritance_CMTAT_PROXY_UUPS.sol](../schema/surya_inheritance/surya_inheritance_CMTAT_PROXY_UUPS.sol.png)
+
+
+
+
+
### UML
See [CMTAT_BASE.svg](../schema/sol2uml/CMTAT_BASE.svg).
diff --git a/doc/general/Engine.md b/doc/general/Engine.md
index 2f1ef62f..eb7134e2 100644
--- a/doc/general/Engine.md
+++ b/doc/general/Engine.md
@@ -1,6 +1,11 @@
# Engine
-It is possible to add supplementary controls on the CMTAT through two Engines: the `RuleEngine`and the `AuthorizationEngine`
+It is possible to add supplementary controls on the CMTAT through four Engines:
+
+- The `RuleEngine`
+- The `AuthorizationEngine`
+- The DocumentEngine
+- The DebtEngine
## RuleEngine
@@ -18,10 +23,6 @@ In this example, the token holder calls the function `transfer` which triggers a
-
-
-
-
### Implementation
A **ruleEngine** contract has to implement the interface `IRuleEngine`, which inherits from the `IERC1404Wrapper`. These two interfaces defines mainly two functions.
diff --git a/doc/general/Proxy.md b/doc/general/Proxy.md
index 68e720aa..2a1ed347 100644
--- a/doc/general/Proxy.md
+++ b/doc/general/Proxy.md
@@ -15,6 +15,12 @@ As indicated in the [OpenZeppelin documentation](https://docs.openzeppelin.com/c
>
> The function `__{ContractName}_init_unchained` found in every contract is the initializer function minus the calls to parent initializers, and can be used to avoid the double initialization problem, but doing this manually is not recommended. We hope to be able to implement safety checks for this in future versions of the Upgrades Plugins.
+## ERC-7201
+
+To manage memory and avoid storage collisions, CMTAT implements, like OpenZeppelin, the [ERC-7201](https://eips.ethereum.org/EIPS/eip-7201)
+
+More information on a [RareSkills article](https://www.rareskills.io/post/erc-7201)
+
## Deployment with a proxy
The CMTAT supports deployment via a proxy contract. Furthermore, using a proxy permits to upgrade the contract, using a standard proxy upgrade pattern.
@@ -26,6 +32,3 @@ Please see the OpenZeppelin [upgradeable contracts documentation](https://docs.o
Please see the OpenZeppelin [Upgrades plugins](https://docs.openzeppelin.com/upgrades-plugins/1.x/) for more information about plugin upgrades in general.
Note that deployment via a proxy is not mandatory, but is recommended by CMTA.
-
-
-###
diff --git a/doc/general/contract-size.png b/doc/general/contract-size.png
index 7f1d997a..80fd05d3 100644
Binary files a/doc/general/contract-size.png and b/doc/general/contract-size.png differ
diff --git a/doc/general/test/archive/test.odt b/doc/general/test/archive/test.odt
deleted file mode 100644
index 8a51c6a0..00000000
Binary files a/doc/general/test/archive/test.odt and /dev/null differ
diff --git a/doc/general/test/archive/test.pdf b/doc/general/test/archive/test.pdf
deleted file mode 100644
index 2c854383..00000000
Binary files a/doc/general/test/archive/test.pdf and /dev/null differ
diff --git a/doc/general/test/coverage/contracts/CMTAT_PROXY.sol.html b/doc/general/test/coverage/contracts/CMTAT_PROXY.sol.html
index 1f6a919f..c1f44cd5 100644
--- a/doc/general/test/coverage/contracts/CMTAT_PROXY.sol.html
+++ b/doc/general/test/coverage/contracts/CMTAT_PROXY.sol.html
@@ -64,7 +64,8 @@
//SPDX-License-Identifier: MPL-2.0 @@ -91,6 +93,9 @@import "./modules/CMTAT_BASE.sol"; +/** +* @title CMTAT version for a proxy deployment (Transparent or Beacon proxy) +*/ contract CMTAT_PROXY is CMTAT_BASE { /** * @notice Contract version for the deployment with a proxy @@ -103,8 +108,6 @@
// Disable the possibility to initialize the implementation _disableInitializers(); } - - uint256[50] private __gap; }
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 | + + + + + + + + + + + + + + + + + + + +9× + + + + + + + + + + + + + + + + + + + +5× + + + +5× + + + + + + + + + | //SPDX-License-Identifier: MPL-2.0
+
+pragma solidity ^0.8.20;
+import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
+import "./modules/CMTAT_BASE.sol";
+
+/**
+* @title CMTAT version for a proxy deployment with UUPS proxy
+*/
+contract CMTAT_PROXY_UUPS is CMTAT_BASE, UUPSUpgradeable {
+ bytes32 public constant PROXY_UPGRADE_ROLE = keccak256("PROXY_UPGRADE_ROLE");
+ /**
+ * @notice Contract version for the deployment with a proxy
+ * @param forwarderIrrevocable address of the forwarder, required for the gasless support
+ */
+ /// @custom:oz-upgrades-unsafe-allow constructor
+ constructor(
+ address forwarderIrrevocable
+ ) MetaTxModule(forwarderIrrevocable) {
+ // Disable the possibility to initialize the implementation
+ _disableInitializers();
+ }
+
+ /*//////////////////////////////////////////////////////////////
+ PUBLIC/EXTERNAL FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+
+ /**
+ * @notice
+ * initialize the proxy contract
+ * The calls to this function will revert if the contract was deployed without a proxy
+ * @param admin address of the admin of contract (Access Control)
+ * @param ERC20Attributes_ ERC20 name, symbol and decimals
+ * @param baseModuleAttributes_ tokenId, terms, information
+ * @param engines_ external contract
+ */
+ function initialize( address admin,
+ ICMTATConstructor.ERC20Attributes memory ERC20Attributes_,
+ ICMTATConstructor.BaseModuleAttributes memory baseModuleAttributes_,
+ ICMTATConstructor.Engine memory engines_ ) public override Einitializer {
+ CMTAT_BASE.initialize( admin,
+ ERC20Attributes_,
+ baseModuleAttributes_,
+ engines_);
+ __UUPSUpgradeable_init_unchained();
+ }
+
+
+ /*//////////////////////////////////////////////////////////////
+ INTERNAL/PRIVATE FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+ function _authorizeUpgrade(address) internal override onlyRole(PROXY_UPGRADE_ROLE) {}
+}
+ |
//SPDX-License-Identifier: MPL-2.0 pragma solidity ^0.8.20; import "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol"; - +import '@openzeppelin/contracts/utils/Create2.sol'; import '@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol'; import "../CMTAT_PROXY.sol"; -import "../modules/CMTAT_BASE.sol"; -import "../libraries/FactoryErrors.sol"; -import '@openzeppelin/contracts/access/AccessControl.sol'; +import "./libraries/CMTATFactoryRoot.sol"; + /** * @notice Factory to deploy beacon proxy * */ -contract CMTAT_BEACON_FACTORY is AccessControl { - // Private - mapping(uint256 => address) private cmtats; - uint256 private cmtatCounterId; +contract CMTAT_BEACON_FACTORY is AccessControl, CMTATFactoryRoot { // public - /// @dev Role to deploy CMTAT - bytes32 public constant CMTAT_DEPLOYER_ROLE = keccak256("CMTAT_DEPLOYER_ROLE"); UpgradeableBeacon public immutable beacon; - address[] public cmtatsList; - event CMTAT(address indexed CMTAT, uint256 id); - /** * @param implementation_ contract implementation * @param factoryAdmin admin * @param beaconOwner owner */ - constructor(address implementation_, address factoryAdmin, address beaconOwner) { - if(factoryAdmin == address(0)){ - revert FactoryErrors.CMTAT_Factory_AddressZeroNotAllowedForFactoryAdmin(); - } + constructor(address implementation_, address factoryAdmin, address beaconOwner, bool useCustomSalt_)CMTATFactoryRoot(factoryAdmin, useCustomSalt_) { if(beaconOwner == address(0)){ revert FactoryErrors.CMTAT_Factory_AddressZeroNotAllowedForBeaconOwner(); } @@ -287,56 +289,41 @@revert FactoryErrors.CMTAT_Factory_AddressZeroNotAllowedForLogicContract(); } beacon = new UpgradeableBeacon(implementation_, beaconOwner); - _grantRole(DEFAULT_ADMIN_ROLE, factoryAdmin); - _grantRole(CMTAT_DEPLOYER_ROLE, factoryAdmin); } + /*////////////////////////////////////////////////////////////// + PUBLIC/EXTERNAL FUNCTIONS + //////////////////////////////////////////////////////////////*/ /** * @notice deploy CMTAT with a beacon proxy * */ function deployCMTAT( + bytes32 deploymentSaltInput, // CMTAT function initialize - address admin, - IAuthorizationEngine authorizationEngineIrrevocable, - string memory nameIrrevocable, - string memory symbolIrrevocable, - uint8 decimalsIrrevocable, - string memory tokenId_, - string memory terms_, - IRuleEngine ruleEngine_, - string memory information_, - uint256 flag_ + CMTAT_ARGUMENT calldata cmtatArgument ) public onlyRole(CMTAT_DEPLOYER_ROLE) returns(BeaconProxy cmtat) { - cmtat = new BeaconProxy( - address(beacon), - abi.encodeWithSelector( - CMTAT_PROXY(address(0)).initialize.selector, - admin, - authorizationEngineIrrevocable, - nameIrrevocable, - symbolIrrevocable, - decimalsIrrevocable, - tokenId_, - terms_, - ruleEngine_, - information_, - flag_ - ) - ); - cmtats[cmtatCounterId] = address(cmtat); - emit CMTAT(address(cmtat), cmtatCounterId); - cmtatCounterId++; - cmtatsList.push(address(cmtat)); + bytes32 deploymentSalt = _checkAndDetermineDeploymentSalt(deploymentSaltInput); + bytes memory bytecode = _getBytecode( + // CMTAT function initialize + cmtatArgument); + cmtat = _deployBytecode(bytecode, deploymentSalt); return cmtat; } /** - * @notice get CMTAT proxy address - * + * @param deploymentSalt salt for the deployment + * @param cmtatArgument argument for the function initialize + * @notice get the proxy address depending on a particular salt */ - function getAddress(uint256 cmtatID_) external view returns (address) { - return cmtats[cmtatID_]; + function computedProxyAddress( + bytes32 deploymentSalt, + // CMTAT function initialize + CMTAT_ARGUMENT calldata cmtatArgument) public view returns (address) { + bytes memory bytecode = _getBytecode( + // CMTAT function initialize + cmtatArgument); + return Create2.computeAddress(deploymentSalt, keccak256(bytecode), address(this) ); } /** @@ -346,13 +333,47 @@
function implementation() public view returns (address) { return beacon.implementation(); } + + /*////////////////////////////////////////////////////////////// + INTERNAL FUNCTIONS + //////////////////////////////////////////////////////////////*/ + + /** + * @notice Deploy CMTAT and push the created CMTAT in the list + */ + function _deployBytecode(bytes memory bytecode, bytes32 deploymentSalt) internal returns (BeaconProxy cmtat) { + address cmtatAddress = Create2.deploy(0, deploymentSalt, bytecode); + cmtat = BeaconProxy(payable(cmtatAddress)); + cmtats[cmtatCounterId] = address(cmtat); + emit CMTAT(address(cmtat), cmtatCounterId); + ++cmtatCounterId; + cmtatsList.push(address(cmtat)); + return cmtat; + } + + + /** + * @notice return the smart contract bytecode + */ + function _getBytecode( + // CMTAT function initialize + CMTAT_ARGUMENT calldata cmtatArgument) internal view returns(bytes memory bytecode) { + bytes memory _implementation = abi.encodeWithSelector( + CMTAT_PROXY(address(0)).initialize.selector, + cmtatArgument.CMTATAdmin, + cmtatArgument.ERC20Attributes, + cmtatArgument.baseModuleAttributes, + cmtatArgument.engines + ); + bytecode = abi.encodePacked(type(BeaconProxy).creationCode, abi.encode(address(beacon), _implementation)); + } }
//SPDX-License-Identifier: MPL-2.0 pragma solidity ^0.8.20; import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import "../CMTAT_PROXY.sol"; -import "../libraries/FactoryErrors.sol"; -import '@openzeppelin/contracts/access/AccessControl.sol'; +import '@openzeppelin/contracts/utils/Create2.sol'; +import "./libraries/CMTATFactoryInvariant.sol"; +import "./libraries/CMTATFactoryBase.sol"; /** -* @notice Factory to deploy transparent proxy +* @notice Factory to deploy CMTAT with a transparent proxy * */ -contract CMTAT_TP_FACTORY is AccessControl { - // Private - mapping(uint256 => address) private cmtats; - uint256 private cmtatID; - event CMTAT(address indexed CMTAT, uint256 id); - // Public - /// @dev Role to deploy CMTAT - bytes32 public constant CMTAT_DEPLOYER_ROLE = keccak256("CMTAT_DEPLOYER_ROLE"); - address public immutable logic; - address[] public cmtatsList; +contract CMTAT_TP_FACTORY is CMTATFactoryBase { - + constructor(address logic_, address factoryAdmin, bool useCustomSalt_) CMTATFactoryBase(logic_, factoryAdmin,useCustomSalt_){} - /** - * @param logic_ contract implementation - * @param factoryAdmin admin + /*////////////////////////////////////////////////////////////// + PUBLIC/EXTERNAL FUNCTIONS + //////////////////////////////////////////////////////////////*/ + /** + * @notice deploy a transparent proxy with a proxy admin contract */ - constructor(address logic_, address factoryAdmin) { - if(logic_ == address(0)){ - revert FactoryErrors.CMTAT_Factory_AddressZeroNotAllowedForLogicContract(); - } - if(factoryAdmin == address(0)){ - revert FactoryErrors.CMTAT_Factory_AddressZeroNotAllowedForFactoryAdmin(); - } - logic = logic_; - _grantRole(DEFAULT_ADMIN_ROLE, factoryAdmin); - _grantRole(CMTAT_DEPLOYER_ROLE, factoryAdmin); - } - function deployCMTAT( + bytes32 deploymentSaltInput, address proxyAdminOwner, // CMTAT function initialize - address admin, - IAuthorizationEngine authorizationEngineIrrevocable, - string memory nameIrrevocable, - string memory symbolIrrevocable, - uint8 decimalsIrrevocable, - string memory tokenId_, - string memory terms_, - IRuleEngine ruleEngine_, - string memory information_, - uint256 flag_ + CMTAT_ARGUMENT calldata cmtatArgument ) public onlyRole(CMTAT_DEPLOYER_ROLE) returns(TransparentUpgradeableProxy cmtat) { - cmtat = new TransparentUpgradeableProxy( - logic, - proxyAdminOwner, - abi.encodeWithSelector( - CMTAT_PROXY(address(0)).initialize.selector, - admin, - authorizationEngineIrrevocable, - nameIrrevocable, - symbolIrrevocable, - decimalsIrrevocable, - tokenId_, - terms_, - ruleEngine_, - information_, - flag_ - ) - ); - cmtats[cmtatID] = address(cmtat); - emit CMTAT(address(cmtat), cmtatID); - cmtatID++; - cmtatsList.push(address(cmtat)); + bytes32 deploymentSalt = _checkAndDetermineDeploymentSalt(deploymentSaltInput); + bytes memory bytecode = _getBytecode(proxyAdminOwner, + // CMTAT function initialize + cmtatArgument); + cmtat = _deployBytecode(bytecode, deploymentSalt); + return cmtat; } /** - * @notice get CMTAT proxy address - * + * @param deploymentSalt salt for the deployment + * @param proxyAdminOwner admin of the proxy + * @param cmtatArgument argument for the function initialize + * @notice get the proxy address depending on a particular salt */ - function getAddress(uint256 cmtatID_) external view returns (address) { - return cmtats[cmtatID_]; + function computedProxyAddress( + bytes32 deploymentSalt, + address proxyAdminOwner, + // CMTAT function initialize + CMTAT_ARGUMENT calldata cmtatArgument) public view returns (address) { + bytes memory bytecode = _getBytecode(proxyAdminOwner, + // CMTAT function initialize + cmtatArgument); + return Create2.computeAddress(deploymentSalt, keccak256(bytecode), address(this) ); } + + + /*////////////////////////////////////////////////////////////// + INTERNAL FUNCTIONS + //////////////////////////////////////////////////////////////*/ + + + /** + * @notice Deploy CMTAT and push the created CMTAT in the list + */ + function _deployBytecode(bytes memory bytecode, bytes32 deploymentSalt) internal returns (TransparentUpgradeableProxy cmtat) { + address cmtatAddress = Create2.deploy(0, deploymentSalt, bytecode); + cmtat = TransparentUpgradeableProxy(payable(cmtatAddress)); + cmtats[cmtatCounterId] = address(cmtat); + emit CMTAT(address(cmtat), cmtatCounterId); + ++cmtatCounterId; + cmtatsList.push(address(cmtat)); + return cmtat; + } + + + /** + * @notice return the smart contract bytecode + */ + function _getBytecode( address proxyAdminOwner, + // CMTAT function initialize + CMTAT_ARGUMENT calldata cmtatArgument) internal view returns(bytes memory bytecode) { + bytes memory implementation = abi.encodeWithSelector( + CMTAT_PROXY(address(0)).initialize.selector, + cmtatArgument.CMTATAdmin, + cmtatArgument.ERC20Attributes, + cmtatArgument.baseModuleAttributes, + cmtatArgument.engines + ); + bytecode = abi.encodePacked(type(TransparentUpgradeableProxy).creationCode, abi.encode(logic, proxyAdminOwner, implementation)); + } }
//SPDX-License-Identifier: MPL-2.0
-
pragma solidity ^0.8.20;
-import "../../../../../openzeppelin-contracts-upgradeable/contracts/access/AccessControlUpgradeable.sol";
-import "../../../../../openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol";
-import "../../../../interfaces/IDebtGlobal.sol";
-import "../../../security/AuthorizationModule.sol";
-
-import "../../../../libraries/Errors.sol";
-
-abstract contract CreditEventsModule is
- IDebtGlobal,
- Initializable,
- ContextUpgradeable,
- AuthorizationModule
-{
- // CreditEvents
- bytes32 public constant DEBT_CREDIT_EVENT_ROLE =
- keccak256("DEBT_CREDIT_EVENT_ROLE");
- CreditEvents public creditEvents;
-
- /* Events */
- event FlagDefault(bool indexed newFlagDefault);
- event FlagRedeemed(bool indexed newFlagRedeemed);
- event Rating(string indexed newRatingIndexed, string newRating);
-
- function __CreditEvents_init_unchained() internal EonlyInitializing {
- // no variable to initialize
- }
-
- /**
- * @notice Set all attributes of creditEvents
- * The values of all attributes will be changed even if the new values are the same as the current ones
+import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
+import "../CMTAT_PROXY_UUPS.sol";
+import '@openzeppelin/contracts/utils/Create2.sol';
+import "./libraries/CMTATFactoryInvariant.sol";
+import "./libraries/CMTATFactoryBase.sol";
+/**
+* @notice Factory to deploy CMTAT with a UUPS proxy
+*
+*/
+contract CMTAT_UUPS_FACTORY is CMTATFactoryBase {
+ /**
+ * @param logic_ contract implementation
+ * @param factoryAdmin admin
*/
- function setCreditEvents(
- bool flagDefault_,
- bool flagRedeemed_,
- string calldata rating_
- ) public onlyRole(DEBT_CREDIT_EVENT_ROLE) {
- creditEvents = (CreditEvents(flagDefault_, flagRedeemed_, rating_));
- emit FlagDefault(flagDefault_);
- emit FlagRedeemed(flagRedeemed_);
- emit Rating(rating_, rating_);
- }
-
- /**
- * @notice The call will be reverted if the new value of flagDefault is the same as the current one
+ constructor(address logic_, address factoryAdmin, bool useCustomSalt_) CMTATFactoryBase(logic_, factoryAdmin,useCustomSalt_){}
+
+
+ /*//////////////////////////////////////////////////////////////
+ PUBLIC/EXTERNAL FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+ /**
+ * @notice deploy a transparent proxy with a proxy admin contract
*/
- function setFlagDefault(
- bool flagDefault_
- ) public onlyRole(DEBT_CREDIT_EVENT_ROLE) {
- if (flagDefault_ == creditEvents.flagDefault) {
- revert Errors.CMTAT_DebtModule_SameValue();
- }
- creditEvents.flagDefault = flagDefault_;
- emit FlagDefault(flagDefault_);
+ function deployCMTAT(
+ bytes32 deploymentSaltInput,
+ // CMTAT function initialize
+ CMTAT_ARGUMENT calldata cmtatArgument
+ ) public onlyRole(CMTAT_DEPLOYER_ROLE) returns(ERC1967Proxy cmtat) {
+ bytes32 deploymentSalt = _checkAndDetermineDeploymentSalt(deploymentSaltInput);
+ bytes memory bytecode = _getBytecode(
+ // CMTAT function initialize
+ cmtatArgument);
+ cmtat = _deployBytecode(bytecode, deploymentSalt);
+
+ return cmtat;
}
- /**
- * @notice The call will be reverted if the new value of flagRedeemed is the same as the current one
+ /**
+ * @param deploymentSalt salt for the deployment
+ * @param cmtatArgument argument for the function initialize
+ * @notice get the proxy address depending on a particular salt
*/
- function setFlagRedeemed(
- bool flagRedeemed_
- ) public onlyRole(DEBT_CREDIT_EVENT_ROLE) {
- if (flagRedeemed_ == creditEvents.flagRedeemed) {
- revert Errors.CMTAT_DebtModule_SameValue();
- }
- creditEvents.flagRedeemed = flagRedeemed_;
- emit FlagRedeemed(flagRedeemed_);
+ function computedProxyAddress(
+ bytes32 deploymentSalt,
+ // CMTAT function initialize
+ CMTAT_ARGUMENT calldata cmtatArgument) public view returns (address) {
+ bytes memory bytecode = _getBytecode(
+ // CMTAT function initialize
+ cmtatArgument);
+ return Create2.computeAddress(deploymentSalt, keccak256(bytecode), address(this) );
}
- /**
- * @notice The rating will be changed even if the new value is the same as the current one
+ /*//////////////////////////////////////////////////////////////
+ INTERNAL FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+
+ /**
+ * @notice Deploy CMTAT and push the created CMTAT in the list
*/
- function setRating(
- string calldata rating_
- ) public onlyRole(DEBT_CREDIT_EVENT_ROLE) {
- creditEvents.rating = rating_;
- emit Rating(rating_, rating_);
- }
+ function _deployBytecode(bytes memory bytecode, bytes32 deploymentSalt) internal returns (ERC1967Proxy cmtat) {
+ address cmtatAddress = Create2.deploy(0, deploymentSalt, bytecode);
+ cmtat = ERC1967Proxy(payable(cmtatAddress));
+ cmtats[cmtatCounterId] = address(cmtat);
+ emit CMTAT(address(cmtat), cmtatCounterId);
+ ++cmtatCounterId;
+ cmtatsList.push(address(cmtat));
+ return cmtat;
+ }
- uint256[50] private __gap;
-}
-