diff --git a/CHANGELOG.md b/CHANGELOG.md
index 55abf03d..dd0ee63e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,26 @@
Please follow conventions.
+
+
+## 2.5.0-rc.0 - 20240809
+
+**Features**
+
+- Add ERC-1643 (part of ERC-1400) for document management through an optional external contract called DocumentEngine (not yet available) [Add ERC-1643 support #267](https://github.com/CMTA/CMTAT/issues/267)
+- Externalize the Debt and CreditEvent module to an optional external contract called DebtEngine (not yet available) [Add DebtEngine #271](https://github.com/CMTA/CMTAT/issues/271)
+- CMTAT version compatible with UUPS proxy : more gas efficient than Transparent Proxy + no need of a proxy admin contract. See Upgradable Smart Contracts | What is a Smart Contract Proxy Pattern? [Add UUPS proxy support #270](https://github.com/CMTA/CMTAT/issues/270)
+- Remove [flag](https://github.com/CMTA/CMTAT/blob/master/contracts/modules/wrapper/core/BaseModule.sol#L29) attribute, present since v2.3.0, which was not really used. [ #266](https://github.com/CMTA/CMTAT/issues/266)
+
+**Technical**
+
+- Change Solidity version to 0.8.26 (latest)
+- Change EVM version to Cancun
+- Remove truffle from dependencies, replaced by Hardhat. 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)
+- Proxy Factory
+ - use create2 with the library [Create2](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Create2.sol) from OpenZeppelin:
+- Implement [ERC-7201](https://eips.ethereum.org/EIPS/eip-7201) to manage memory to reduce memory collision when upgrading a proxy to a new implementation. [Use erc-7201 for namespace #272](https://github.com/CMTA/CMTAT/issues/272)
+
## 2.4.0
The modifications between the version v2.3.0 and this version are not audited !!!
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 00000000..a037f332
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,23 @@
+# Contributing Guidelines
+
+There are many ways to contribute to CMTAT Contracts.
+
+## Opening an issue
+
+You can [open an issue] to suggest a feature, a difficulty you have or report a minor bug. For serious bugs in an audited version please do not open an issue, instead refer to our [security policy] for appropriate steps. See [SECURITY.md](./SECURITY.MD).
+
+Before opening an issue, be sure to search through the existing open and closed issues, and consider posting a comment in one of those instead.
+
+When requesting a new feature, include as many details as you can, especially around the use cases that motivate it.
+
+## Submitting a pull request
+
+If you would like to contribute code or documentation you may do so by forking the repository and submitting a pull request.
+
+Run linter and tests to make sure your pull request is good before submitting it.
+
+
+
+## Reference
+
+Based on the version made by [OpenZeppelin](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/CONTRIBUTING.md)
diff --git a/FAQ.md b/FAQ.md
index 0bc33b66..c93cef1b 100644
--- a/FAQ.md
+++ b/FAQ.md
@@ -7,32 +7,22 @@ development.
> Which is the main development tool you use ?
-Until the version v.2.3.1, we used `Truffle` with `web3js` as our main development tool and testing library. Since this version, we use *custom errors* to generate errors inside our smart contracts and this type of errors are not supported by `Truffle` for testing.
-
-Therefore, we use `Hardhat` with `web3js` to run our tests, but you can compile the contracts with Truffle or Hardhat.
+Since the sunset of Truffle by Consensys, we use Hardhat
Regarding [Foundry](https://book.getfoundry.sh/):
-- The plugin "upgrades plugin" by OpenZeppelin is not available with Foundry and it is a very good tool to check the proxy implementation and perform automatic tests. See [https://docs.openzeppelin.com/upgrades-plugins/1.x/](https://docs.openzeppelin.com/upgrades-plugins/1.x/)
-- The tests for the gasless module (MetaTx) would be difficult to write
- in Solidity, as Foundry requires, see [https://github.com/CMTA/CMTAT/blob/master/test/common/MetaTxModuleCommon.js](https://github.com/CMTA/CMTAT/blob/master/test/common/MetaTxModuleCommon.js)
-- The OpenZeppelin libraries that we use have their tests mainly written in JavaScript, which provides a good basis for our tests
-- We have a repository [CMTA/CMTAT-Foundry](https://github.com/CMTA/CMTAT-foundry) that provides experimental support for Foundry, but it does not provide complete support and testing for the latest CMTAT version.
+- All our tests are written in Javascript and migrating them to Foundry will require a lot of work
+- The tests for the gasless module (MetaTx) would be difficult to write
+ in Solidity, as Foundry requires, see [https://github.com/CMTA/CMTAT/blob/master/test/common/MetaTxModuleCommon.js](https://github.com/CMTA/CMTAT/blob/master/test/common/MetaTxModuleCommon.js)
+
+- The OpenZeppelin libraries that we use have their tests mainly written in JavaScript, which provides a good basis for our tests
> Do you plan to fully support Foundry in the near future?
-For the foreseeable future, we plan to keep Hardhat/Truffle as the main
+For the foreseeable future, we plan to keep Hardhat as the main
development and testing suite.
-We have not planned to export all the tests from the Truffle/Hardhat suite to
-their Solidity version equivalent suitable to Foundry, though some tests
-are already available.
-
-The CMTAT-Foundry repository uses CMTAT as a submodule, whose version is
-documented in its
-[README](https://github.com/CMTA/CMTAT-Foundry/blob/main/README.md#cmtat---using-the-foundry-suite).
-
> Can Truffle be used to run tests?
@@ -45,29 +35,18 @@ You can only run the tests with `Hardhat`.
> What is the reason the Snapshot module wasn't audited in version v2.3.0?
-This module was left out of scope because it is not used yet (and not
-included in a default deployment) and will be
-subject to changes soon.
+This module was left out of scope because it is not used yet (and not included in a default deployment) and will be subject to changes soon.
> What is the status of [ERC1404](https://erc1404) compatibility?
-We have not planned to be fully compatible with ERC1404 (which, in fact,
-is only an EIP at the time of writing).
-CMTAT includes the two functions defind by ERC1404, namely
-`detectTransferRestriction` and `messageForTransferRestriction`.
+We have not planned to be fully compatible with ERC1404 (which, in fact, is only an EIP at the time of writing).
+CMTAT includes the two functions defind by ERC1404, namely `detectTransferRestriction` and `messageForTransferRestriction`.
Thus CMTAT can provide the same functionality as ERC1404.
However, from a pure technical perspective, CMTAT is not fully compliant
with the ERC1404 specification, due the way it inherits the ERC20
interface.
-> What is the purpose of the flag parameter in the Base module?
-
-It is just a variable to include some additional information under the form of bit fields.
-It is not used inside the code because it is destined to provide more
-information on the tokens to the "outside", for example for the token
-owners.
-
> Is the Validation module optional?
@@ -75,30 +54,20 @@ Generally, for a CMTAT token, the Validation functionality is optional
from the legal perspective (please contact admin@cmta.ch for detailed
information).
-However, in order to use the functions from the Pause and Enforcement
-modules, our CMTAT implementation requires the Validation module
-Therefore, the Validation module is effectively required *in this
-implementation*.
+However, in order to use the functions from the Pause and Enforcement modules, our CMTAT implementation requires the Validation module. Therefore, the Validation module is effectively required *in this implementation*.
If you remove the Validation module and want to use the Pause or the
-Enforcement module, you have to call the functions of modules inside the
-main contracts. It was initially the case but we have changed this
-behavior when addressing an issue reported by a security audit.
+Enforcement module, you have to call the functions of modules inside the main contracts. It was initially the case but we have changed this behavior when addressing an issue reported by a security audit.
Here is an old version:
-[https://github.com/CMTA/CMTAT/blob/ed23bfc69cfacc932945da751485c6472705c975/contracts/CMTAT.sol#L205](https://github.com/CMTA/CMTAT/blob/ed23bfc69cfacc932945da751485c6472705c975/contracts/CMTAT.sol#L205),
-and the relevant Pull [Request](https://github.com/CMTA/CMTAT/pull/153).
+[https://github.com/CMTA/CMTAT/blob/ed23bfc69cfacc932945da751485c6472705c975/contracts/CMTAT.sol#L205](https://github.com/CMTA/CMTAT/blob/ed23bfc69cfacc932945da751485c6472705c975/contracts/CMTAT.sol#L205), and the relevant Pull [Request](https://github.com/CMTA/CMTAT/pull/153).
## Documentation
> What is the code coverage of the test suite?
-A [code coverage report](https://github.com/CMTA/CMTAT/blob/master/doc/general/test/coverage/index.html)
-is available.
+A [code coverage report](https://github.com/CMTA/CMTAT/blob/master/doc/general/test/coverage/index.html) is available.
Normally, you can run the test suite and generate a code coverage report with `npx hardhat coverage`.
Please clone the repository and open the file inside your browser.
-
-You will find a list of automatic tests in
-[test.pdf](https://github.com/CMTA/CMTAT/blob/master/doc/general/test/test.pdf).
diff --git a/README.md b/README.md
index 4b43fe90..f08fd925 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,7 @@
+
+
# CMTA Token
+
> To use the CMTAT, we recommend the latest audited version, from the [Releases](https://github.com/CMTA/CMTAT/releases) page. Currently, it is the version [v2.3.0](https://github.com/CMTA/CMTAT/releases/tag/v2.3.0)
## Introduction
@@ -33,42 +36,21 @@ It can however also be used for other forms of financial instruments such as deb
You may modify the token code by adding, removing, or modifying features. However, the core modules must remain in place for compliance with Swiss law.
-### Deployment model
-
-#### 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 contract version to use as an implementation is the `CMTAT_PROXY`.
-
-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 or a transparent proxy.
-
-[CMTAT_BEACON_FACTORY.sol](./contracts/deployment/CMTAT_BEACON_FACTORY.sol)
-
-[CMTAT_TRANSPARENT_FACTORY.sol](./contracts/deployment/CMTAT_TRANSPARENT_FACTORY.sol)
+### Kill switch
-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.
+CMTAT initially supported a `kill()` function relying on the SELFDESTRUCT opcode (which effectively destroyed the contract's storage and code).
+However, Ethereum's [Cancun upgrate](https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/cancun.md) (rolled out in Q1 of 2024) has removed support for SELFDESTRUCT (see [EIP-6780](https://eips.ethereum.org/EIPS/eip-6780)).
-![factory-Beacon Factory.drawio](./doc/schema/drawio/factory-BeaconFactory.drawio.png)
+The `kill()` function will therefore not behave as it was used
-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.
+We have replaced this function by a new function `deactivateContract`, introduced in the version v2.3.1 inside the PauseModule, to deactivate the contract.
+This function set a boolean state variable `isDeactivated` to true and puts the contract in the pause state.
+The function `unpause`is updated to revert if the previous variable is set to true, thus the contract is in the pause state "forever".
-![factory-Transparent Factory.drawio](./doc/schema/drawio/factory-TransparentFactory.drawio.png)
+The consequences are the following:
+- In standalone mode, this operation is irreversible, it is not possible to rollback.
+- With a proxy, it is still possible to rollback by deploying a new implementation.
### Gasless support
@@ -78,36 +60,40 @@ At deployment, the parameter `forwarder` inside the CMTAT contract constructor
Please see the OpenGSN [documentation](https://docs.opengsn.org/contracts/#receiving-a-relayed-call) for more details on what is done to support GSN in the contract.
-### Kill switch
+## Architecture
-CMTAT initially supported a `kill()` function relying on the SELFDESTRUCT opcode (which effectively destroyed the contract's storage and code).
-However, Ethereum's [Cancun upgrate](https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/cancun.md) (rolled out in Q1 of 2024) will remove support for SELFDESTRUCT (see
-[EIP-6780](https://eips.ethereum.org/EIPS/eip-6780)).
+CMTAT architecture is divided in two main componentes: module and engines
-The `kill()` function will therefore not behave as it used to once Cancun is deployed.
+### Module
-The alternative function is the function `deactivateContract`, introduced in the version v2.3.1 inside the PauseModule, to deactivate the contract.
-This function set a boolean state variable `isDeactivated` to true and puts the contract in the pause state.
-The function `unpause`is updated to revert if the previous variable is set to true, thus the contract is in the pause state "forever".
+Modules describe a logical code separation inside CMTAT. They are defined as abstract contracts.
+Their code and functionalities are part of the CMTAT and therefore are also included in the calculation of the contract size and the maximum size limit of 24 kB.
-The consequences are the following:
+It is always possible to delete a module but this requires modifying the code and compiling it again, which require to perform a security audit on these modifications.
-- In standalone mode, this operation is irreversible, it is not possible to rollback.
-- With a proxy, it is still possible to rollback by deploying a new implementation.
-
+Modules are also separated in different categories.
+
+- Internal modules: implementation for a module when OpenZeppelin does not provide a library to use. For example, this is the case for the SnapshotModule.
+
+- Wrapper modules: abstract contract around OpenZeppelin contracts or internal module.
+ For example, the wrapper PauseModule provides public functions to call the internal functions from OpenZeppelin.
+ - Core (Wrapper sub-category): Contains the modules required to be CMTA compliant
+ - Extension (Wrapper sub-category): not required to be CMTA compliant, "bonus features" (snapshotModule, debtModule)
-## Modules
+
+
+#### List
-Here the list of the differents modules with the links towards the documentation and the main file.
+Here the list of the different modules with the links towards the documentation and the main file.
-### Controller
+##### Controller
| Name | Documentation | Main File |
| ---------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| ValidationModule | [validation.md](doc/modules/presentation/controllers/validation.md) | [ValidationModule.sol](./contracts/modules/wrapper/controllers/ValidationModule.sol) |
-### Core
+##### Core
Generally, these modules are required to be compliant with the CMTA specification.
@@ -120,26 +106,34 @@ Generally, these modules are required to be compliant with the CMTA specificatio
| MintModule | [ERC20Mint.md](doc/modules/presentation/core/ERC20Mint.md) | [ERC20MintModule.sol](./contracts/modules/wrapper/core/ERC20MintModule.sol) |
| PauseModule | [pause.md](doc/modules/presentation/core/pause.md) | [PauseModule.sol](./contracts/modules/wrapper/core/PauseModule.sol) |
-### Extensions
+##### Extensions
Generally, these modules are not required to be compliant with the CMTA specification.
-| Name | Documentation | Main File |
-| ----------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
-| MetaTxModule | [metatx.md](doc/modules/presentation/extensions/metatx.md) | [MetaTxModule.sol](./contracts/modules/wrapper/extensions/MetaTxModule.sol) |
-| SnapshotModule | [snapshot.md](doc/modules/presentation/extensions/snapshot.md) | [SnapshotModule.sol](./contracts/modules/wrapper/extensions/SnapshotModule.sol) |
-| creditEventModule | [creditEvents.md](doc/modules/presentation/extensions/Debt/creditEvents.md) | [CreditEventsModule.sol](./contracts/modules/wrapper/extensions/DebtModule/CreditEventsModule.sol) |
-| DebtBaseModule | [debtBase.md](doc/modules/presentation/extensions/Debt/debtBase.md) | [DebtBaseModule.sol](./contracts/modules/wrapper/extensions/DebtModule/DebtBaseModule.sol) |
+| Name | Documentation | Main File |
+| -------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
+| MetaTxModule | [metatx.md](doc/modules/presentation/extensions/metatx.md) | [MetaTxModule.sol](./contracts/modules/wrapper/extensions/MetaTxModule.sol) |
+| SnapshotModule | [snapshot.md](doc/modules/presentation/extensions/snapshot.md) | [SnapshotModule.sol](./contracts/modules/wrapper/extensions/SnapshotModule.sol) |
+| DebtModule | | [DebtModule.sol](./contracts/modules/wrapper/extensions/DebtModule.sol) |
+| DocumentModue | | [Document.sol](./contracts/modules/wrapper/extensions/DocumentModule.sol) |
-### Security
+##### Security
| Name | Documentation | Main File |
| ------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| AuthorizationModule | [authorization.md](./doc/modules/presentation/security/authorization.md) | [AuthorizationModule.sol](./contracts/modules/security/AuthorizationModule.sol) |
-## Engine
+### Engines
+
+Engines are external smart contracts called by CMTAT modules.
+
+These engines are **optional** and their addresses can be left to zero.
-### RuleEngine
+More details are available in [./doc/general/Engine.md](./doc/general/Engine.md)
+
+![Engine-Engine.drawio](./doc/schema/drawio/Engine-Engine.drawio.png)
+
+#### RuleEngine (IERC-1404)
The `RuleEngine` is an external contract used to apply transfer restriction to the CMTAT through whitelisting, blacklisting,...
@@ -162,21 +156,127 @@ 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
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.
+
+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).
+
+Currently, there is no implementation of a DebtEngine available
+
+#### 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).
+
+Currently, there is no implementation of a DocumentEngine available
+
+## Deployment model
+
+| Model | Contract |
+| --------------------------- | ---------------------------------------------------- |
+| Standalone | [CMTAT_STANDALONE](./contracts/CMTAT_STANDALONE.sol) |
+| Transparent ou 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 interface can be found in [./contracts/interfaces/engine/IAuthorizationEngine.sol](./contracts/interfaces/engine/IAuthorizationEngine.sol).
+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 +324,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,11 +353,11 @@ 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 - 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/)
## Others implementations
Two versions are available for the blockchain [Tezos](https://tezos.com)
diff --git a/contracts/CMTAT_PROXY_UUPS.sol b/contracts/CMTAT_PROXY_UUPS.sol
index f3673880..fc2d330e 100644
--- a/contracts/CMTAT_PROXY_UUPS.sol
+++ b/contracts/CMTAT_PROXY_UUPS.sol
@@ -1,9 +1,8 @@
//SPDX-License-Identifier: MPL-2.0
pragma solidity ^0.8.20;
-import "../openzeppelin-contracts-upgradeable/contracts/proxy/utils/UUPSUpgradeable.sol";
+import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "./modules/CMTAT_BASE.sol";
-import "./interfaces/engine/IEngine.sol";
contract CMTAT_PROXY_UUPS is CMTAT_BASE, UUPSUpgradeable {
bytes32 public constant PROXY_UPGRADE_ROLE = keccak256("PROXY_UPGRADE_ROLE");
/**
@@ -17,38 +16,34 @@ contract CMTAT_PROXY_UUPS is CMTAT_BASE, UUPSUpgradeable {
// 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 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 information_ additional information to describe the token
- * @param engines list of engines
+ * @param ERC20Attributes_ ERC20 name, symbol and decimals
+ * @param baseModuleAttributes_ tokenId, terms, information
+ * @param engines_ external contract
*/
function initialize( address admin,
- string memory nameIrrevocable,
- string memory symbolIrrevocable,
- uint8 decimalsIrrevocable,
- string memory tokenId_,
- string memory terms_,
- string memory information_,
- IEngine.Engine memory engines) public override initializer {
+ ICMTATConstructor.ERC20Attributes memory ERC20Attributes_,
+ ICMTATConstructor.BaseModuleAttributes memory baseModuleAttributes_,
+ ICMTATConstructor.Engine memory engines_ ) public override initializer {
CMTAT_BASE.initialize( admin,
- nameIrrevocable,
- symbolIrrevocable,
- decimalsIrrevocable,
- tokenId_,
- terms_,
- information_,
- engines);
+ 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 0e2d7e83..3f427f3f 100644
--- a/contracts/CMTAT_STANDALONE.sol
+++ b/contracts/CMTAT_STANDALONE.sol
@@ -9,37 +9,25 @@ 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 information_ additional information to describe the token
+ * @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,
- string memory nameIrrevocable,
- string memory symbolIrrevocable,
- uint8 decimalsIrrevocable,
- string memory tokenId_,
- string memory terms_,
- string memory information_,
- IEngine.Engine memory engine_
+ 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,
- nameIrrevocable,
- symbolIrrevocable,
- decimalsIrrevocable,
- tokenId_,
- terms_,
- information_,
- engine_
+ ERC20Attributes_,
+ baseModuleAttributes_,
+ engines_
);
}
}
diff --git a/contracts/deployment/CMTAT_BEACON_FACTORY.sol b/contracts/deployment/CMTAT_BEACON_FACTORY.sol
index 3f436a6f..abcb941b 100644
--- a/contracts/deployment/CMTAT_BEACON_FACTORY.sol
+++ b/contracts/deployment/CMTAT_BEACON_FACTORY.sol
@@ -6,34 +6,22 @@ import "@openzeppelin/contracts/proxy/beacon/BeaconProxy.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 "../interfaces/engine/IEngine.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();
}
@@ -41,8 +29,6 @@ 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);
}
/**
@@ -50,45 +36,63 @@ contract CMTAT_BEACON_FACTORY is AccessControl {
*
*/
function deployCMTAT(
+ bytes32 deploymentSaltInput,
// CMTAT function initialize
- address admin,
- string memory nameIrrevocable,
- string memory symbolIrrevocable,
- uint8 decimalsIrrevocable,
- string memory tokenId_,
- string memory terms_,
- string memory information_,
- IEngine.Engine memory engines
+ 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,
- nameIrrevocable,
- symbolIrrevocable,
- decimalsIrrevocable,
- tokenId_,
- terms_,
- information_,
- engines
- )
- );
- 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 getCMTATAddress(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) );
}
+ /**
+ * @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));
+ }
+
/**
* @notice get the implementation address from the beacon
* @return implementation address
diff --git a/contracts/deployment/CMTAT_TP_FACTORY.sol b/contracts/deployment/CMTAT_TP_FACTORY.sol
index c9262e61..78ab2af6 100644
--- a/contracts/deployment/CMTAT_TP_FACTORY.sol
+++ b/contracts/deployment/CMTAT_TP_FACTORY.sol
@@ -5,57 +5,15 @@ import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.so
import "../CMTAT_PROXY.sol";
import "../libraries/FactoryErrors.sol";
import '@openzeppelin/contracts/utils/Create2.sol';
-import '@openzeppelin/contracts/access/AccessControl.sol';
-import "../interfaces/engine/IEngine.sol";
-
+import "./libraries/CMTATFactoryInvariant.sol";
+import "./libraries/CMTATFactoryBase.sol";
/**
* @notice Factory to deploy CMTAT with a transparent proxy
*
*/
-contract CMTAT_TP_FACTORY is AccessControl {
- // Public
- /// @dev Role to deploy CMTAT
- bytes32 public constant CMTAT_DEPLOYER_ROLE = keccak256("CMTAT_DEPLOYER_ROLE");
- address public immutable logic;
- address[] public cmtatsList;
- bool public useCustomSalt;
- uint256 public cmtatID;
- /// mapping
- mapping(uint256 => address) private cmtats;
- mapping(bytes32 => bool) private customSaltUsed;
-
- struct CMTAT_ARGUMENT{
- address CMTATAdmin;
- string nameIrrevocable;
- string symbolIrrevocable;
- uint8 decimalsIrrevocable;
- string tokenId;
- string terms;
- string information;
- IEngine.Engine engines;
- }
- event CMTAT(address indexed CMTAT, uint256 id);
+contract CMTAT_TP_FACTORY is CMTATFactoryInvariant, CMTATFactoryBase {
-
- /**
- * @param logic_ contract implementation
- * @param factoryAdmin admin
- */
- constructor(address logic_, address factoryAdmin, bool useCustomSalt_) {
- if(logic_ == address(0)){
- revert FactoryErrors.CMTAT_Factory_AddressZeroNotAllowedForLogicContract();
- }
- if(factoryAdmin == address(0)){
- revert FactoryErrors.CMTAT_Factory_AddressZeroNotAllowedForFactoryAdmin();
- }
- if(useCustomSalt_){
- useCustomSalt = useCustomSalt_;
- }
- logic = logic_;
- _grantRole(DEFAULT_ADMIN_ROLE, factoryAdmin);
- _grantRole(CMTAT_DEPLOYER_ROLE, factoryAdmin);
- }
-
+ constructor(address logic_, address factoryAdmin, bool useCustomSalt_) CMTATFactoryBase(logic_, factoryAdmin,useCustomSalt_){}
/**
* @notice deploy a transparent proxy with a proxy admin contract
*/
@@ -90,32 +48,6 @@ contract CMTAT_TP_FACTORY is AccessControl {
cmtatArgument);
return Create2.computeAddress(deploymentSalt, keccak256(bytecode), address(this) );
}
-
- /**
- * @notice get CMTAT proxy address
- *
- */
- function CMTATProxyAddress(uint256 cmtatID_) external view returns (address) {
- return cmtats[cmtatID_];
- }
-
- /**
- * @param deploymentSalt salt for deployment
- * @dev
- * if useCustomSalt is at false, the salt used is the current value of cmtatId
- */
- 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(cmtatID)));
- }
- }
/**
* @notice Deploy CMTAT and push the created CMTAT in the list
@@ -123,9 +55,9 @@ contract CMTAT_TP_FACTORY is AccessControl {
function _deployBytecode(bytes memory bytecode, bytes32 deploymentSalt) internal returns (TransparentUpgradeableProxy cmtat) {
address cmtatAddress = Create2.deploy(0, deploymentSalt, bytecode);
cmtat = TransparentUpgradeableProxy(payable(cmtatAddress));
- cmtats[cmtatID] = address(cmtat);
- emit CMTAT(address(cmtat), cmtatID);
- ++cmtatID;
+ cmtats[cmtatCounterId] = address(cmtat);
+ emit CMTAT(address(cmtat), cmtatCounterId);
+ ++cmtatCounterId;
cmtatsList.push(address(cmtat));
return cmtat;
}
@@ -137,38 +69,13 @@ contract CMTAT_TP_FACTORY is AccessControl {
function _getBytecode( address proxyAdminOwner,
// CMTAT function initialize
CMTAT_ARGUMENT calldata cmtatArgument) internal view returns(bytes memory bytecode) {
- bytes memory implementation = _encodeImplementationArgument(
- cmtatArgument.CMTATAdmin,
- cmtatArgument.nameIrrevocable,
- cmtatArgument.symbolIrrevocable,
- cmtatArgument.decimalsIrrevocable,
- cmtatArgument.tokenId,
- cmtatArgument.terms,
- cmtatArgument.information,
- cmtatArgument.engines
- );
- bytecode = abi.encodePacked(type(TransparentUpgradeableProxy).creationCode, abi.encode(logic, proxyAdminOwner, implementation));
- }
-
-
- function _encodeImplementationArgument( address admin,
- string memory nameIrrevocable,
- string memory symbolIrrevocable,
- uint8 decimalsIrrevocable,
- string memory tokenId_,
- string memory terms_,
- string memory information_,
- IEngine.Engine memory engines) internal pure returns(bytes memory){
- return abi.encodeWithSelector(
+ bytes memory implementation = abi.encodeWithSelector(
CMTAT_PROXY(address(0)).initialize.selector,
- admin,
- nameIrrevocable,
- symbolIrrevocable,
- decimalsIrrevocable,
- tokenId_,
- terms_,
- information_,
- engines
+ 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..f5d80384
--- /dev/null
+++ b/contracts/deployment/CMTAT_UUPS_FACTORY.sol
@@ -0,0 +1,88 @@
+//SPDX-License-Identifier: MPL-2.0
+pragma solidity ^0.8.20;
+
+import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
+import "../CMTAT_PROXY_UUPS.sol";
+import "../libraries/FactoryErrors.sol";
+import '@openzeppelin/contracts/utils/Create2.sol';
+import '@openzeppelin/contracts/access/AccessControl.sol';
+import "./libraries/CMTATFactoryInvariant.sol";
+import "./libraries/CMTATFactoryBase.sol";
+/**
+* @notice Factory to deploy CMTAT with a UUPS proxy
+*
+*/
+contract CMTAT_UUPS_FACTORY is CMTATFactoryInvariant, CMTATFactoryBase {
+ /**
+ * @param logic_ contract implementation
+ * @param factoryAdmin admin
+ */
+ constructor(address logic_, address factoryAdmin, bool useCustomSalt_) CMTATFactoryBase(logic_, factoryAdmin,useCustomSalt_){}
+
+
+ /**
+ * @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..6c33a6cb
--- /dev/null
+++ b/contracts/deployment/libraries/CMTATFactoryBase.sol
@@ -0,0 +1,24 @@
+//SPDX-License-Identifier: MPL-2.0
+pragma solidity ^0.8.20;
+
+import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
+import "./CMTATFactoryRoot.sol";
+
+/**
+* @notice Code common to TP and UUPS Factory
+*
+*/
+abstract contract CMTATFactoryBase is CMTATFactoryRoot {
+ // Public
+ address public immutable logic;
+ /**
+ * @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..322d3655
--- /dev/null
+++ b/contracts/deployment/libraries/CMTATFactoryInvariant.sol
@@ -0,0 +1,22 @@
+//SPDX-License-Identifier: MPL-2.0
+pragma solidity ^0.8.20;
+
+
+import "../../interfaces/ICMTATConstructor.sol";
+
+/**
+* @notice Factory to deploy CMTAT with a transparent proxy
+*
+*/
+abstract contract CMTATFactoryInvariant {
+ /// @dev Role to deploy CMTAT
+ bytes32 public constant CMTAT_DEPLOYER_ROLE = keccak256("CMTAT_DEPLOYER_ROLE");
+ struct CMTAT_ARGUMENT{
+ address CMTATAdmin;
+ ICMTATConstructor.ERC20Attributes ERC20Attributes;
+ ICMTATConstructor.BaseModuleAttributes baseModuleAttributes;
+ ICMTATConstructor.Engine engines;
+ }
+ /* ============ 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..bc7a1481
--- /dev/null
+++ b/contracts/deployment/libraries/CMTATFactoryRoot.sol
@@ -0,0 +1,61 @@
+//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/utils/Create2.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 {
+ // Public
+ address[] public cmtatsList;
+ bool public useCustomSalt;
+ uint256 public cmtatCounterId;
+ /// mapping
+ mapping(uint256 => address) internal cmtats;
+ mapping(bytes32 => bool) internal customSaltUsed;
+ /**
+ * @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);
+ }
+
+ /**
+ * @notice get CMTAT proxy address
+ *
+ */
+ function CMTATProxyAddress(uint256 cmtatCounterId_) external view returns (address) {
+ return cmtats[cmtatCounterId_];
+ }
+
+ /**
+ * @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..919aa476
--- /dev/null
+++ b/contracts/interfaces/ICMTATConstructor.sol
@@ -0,0 +1,35 @@
+//SPDX-License-Identifier: MPL-2.0
+import "./engine/IDebtEngine.sol";
+import "./engine/IRuleEngine.sol";
+import "./engine/IAuthorizationEngine.sol";
+import "./engine/draft-IERC1643.sol";
+
+pragma solidity ^0.8.20;
+
+/**
+* @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/engine/IDebtEngine.sol b/contracts/interfaces/engine/IDebtEngine.sol
index 863ccda2..0b21894a 100644
--- a/contracts/interfaces/engine/IDebtEngine.sol
+++ b/contracts/interfaces/engine/IDebtEngine.sol
@@ -5,11 +5,11 @@ import "../IDebtGlobal.sol";
interface IDebtEngine is IDebtGlobal {
/**
- * @dev Returns true if the operation is authorized, and false otherwise.
+ * @dev Returns debt information
*/
function debt() external view returns(IDebtGlobal.DebtBase memory);
/**
- * @dev Returns true if the operation is authorized, and false otherwise.
+ * @dev Returns credit events
*/
function creditEvents() external view returns(IDebtGlobal.CreditEvents memory);
diff --git a/contracts/interfaces/engine/IEngine.sol b/contracts/interfaces/engine/IEngine.sol
deleted file mode 100644
index 251e42cb..00000000
--- a/contracts/interfaces/engine/IEngine.sol
+++ /dev/null
@@ -1,21 +0,0 @@
-//SPDX-License-Identifier: MPL-2.0
-import "./IDebtEngine.sol";
-import "./IRuleEngine.sol";
-import "./IAuthorizationEngine.sol";
-import "./draft-IERC1643.sol";
-
-pragma solidity ^0.8.20;
-
-/**
-* @notice interface to represent debt tokens
-*/
-interface IEngine {
- struct Engine {
- IRuleEngine ruleEngine;
- IDebtEngine debtEngine;
- IAuthorizationEngine authorizationEngine;
- IERC1643 documentEngine;
- }
-
-
-}
diff --git a/contracts/mocks/DebtEngineMock.sol b/contracts/mocks/DebtEngineMock.sol
index a63b69a3..4028e508 100644
--- a/contracts/mocks/DebtEngineMock.sol
+++ b/contracts/mocks/DebtEngineMock.sol
@@ -1,15 +1,13 @@
// SPDX-License-Identifier: MPL-2.0
pragma solidity ^0.8.20;
-import "../interfaces/IDebtGlobal.sol";
-interface IDebtEngine is IDebtGlobal {
- function debt() external view returns (DebtBase memory);
- function creditEvents() external view returns (CreditEvents memory);
+import "../interfaces/engine/IDebtEngine.sol";
+interface IDebtEngineMock is IDebtEngine {
function setDebt(DebtBase calldata debt_) external;
function setCreditEvents(CreditEvents calldata creditEvents) external;
}
-contract DebtEngineMock is IDebtEngine {
+contract DebtEngineMock is IDebtEngineMock {
DebtBase private _debt;
CreditEvents private _creditEvents;
diff --git a/contracts/mocks/MinimalForwarderMock.sol b/contracts/mocks/MinimalForwarderMock.sol
index 3dd609d6..74f8a6e5 100644
--- a/contracts/mocks/MinimalForwarderMock.sol
+++ b/contracts/mocks/MinimalForwarderMock.sol
@@ -2,7 +2,7 @@
pragma solidity ^0.8.20;
-import "../../openzeppelin-contracts-upgradeable/contracts/metatx/ERC2771ForwarderUpgradeable.sol";
+import "@openzeppelin/contracts-upgradeable/metatx/ERC2771ForwarderUpgradeable.sol";
contract MinimalForwarderMock is ERC2771ForwarderUpgradeable {
function initialize(string memory name) public initializer {
diff --git a/contracts/modules/CMTAT_BASE.sol b/contracts/modules/CMTAT_BASE.sol
index 6a02b9a4..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";
@@ -23,7 +23,7 @@ import "./wrapper/extensions/MetaTxModule.sol";
import "./wrapper/extensions/DebtModule.sol";
import "./wrapper/extensions/DocumentModule.sol";
import "./security/AuthorizationModule.sol";
-import "../interfaces/engine/IEngine.sol";
+import "../interfaces/ICMTATConstructor.sol";
import "../libraries/Errors.sol";
abstract contract CMTAT_BASE is
@@ -42,58 +42,48 @@ abstract contract CMTAT_BASE is
ERC20SnapshotModule,
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 information_ additional information to describe the token
+ * @param ERC20Attributes_ ERC20 name, symbol and decimals
+ * @param baseModuleAttributes_ tokenId, terms, information
+ * @param engines_ external contract
*/
function initialize(
address admin,
- string memory nameIrrevocable,
- string memory symbolIrrevocable,
- uint8 decimalsIrrevocable,
- string memory tokenId_,
- string memory terms_,
- string memory information_,
- IEngine.Engine memory engines
+ ICMTATConstructor.ERC20Attributes memory ERC20Attributes_,
+ ICMTATConstructor.BaseModuleAttributes memory baseModuleAttributes_,
+ ICMTATConstructor.Engine memory engines_
) public virtual initializer {
__CMTAT_init(
admin,
- nameIrrevocable,
- symbolIrrevocable,
- decimalsIrrevocable,
- tokenId_,
- terms_,
- information_,
- engines
+ ERC20Attributes_,
+ baseModuleAttributes_,
+ engines_
);
}
+
/**
* @dev calls the different initialize functions from the different modules
*/
function __CMTAT_init(
address admin,
- string memory nameIrrevocable,
- string memory symbolIrrevocable,
- uint8 decimalsIrrevocable,
- string memory tokenId_,
- string memory terms_,
- string memory information_,
- IEngine.Engine memory engines
+ 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
@@ -109,16 +99,16 @@ abstract contract CMTAT_BASE is
__SnapshotModuleBase_init_unchained();
__ERC20Snapshot_init_unchained();
- __Validation_init_unchained(engines.ruleEngine);
+ __Validation_init_unchained(engines_ .ruleEngine);
/* Wrapper */
// AuthorizationModule_init_unchained is called firstly due to inheritance
- __AuthorizationModule_init_unchained(admin, engines.authorizationEngine);
+ __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();
@@ -128,11 +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);
+ __DocumentModule_init_unchained(engines_ .documentEngine);
+ __DebtModule_init_unchained(engines_ .debtEngine);
/* Other modules */
- __Base_init_unchained(tokenId_, terms_, information_);
+ __Base_init_unchained(baseModuleAttributes_.tokenId, baseModuleAttributes_.terms, baseModuleAttributes_.information);
/* own function */
__CMTAT_init_unchained();
@@ -142,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.
*/
@@ -184,6 +179,9 @@ abstract contract CMTAT_BASE is
mint(to, amountToMint);
}
+ /*//////////////////////////////////////////////////////////////
+ INTERNAL/PRIVATE FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
/**
* @dev
*
@@ -204,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
*/
diff --git a/contracts/modules/internal/ERC20SnapshotModuleInternal.sol b/contracts/modules/internal/ERC20SnapshotModuleInternal.sol
index d727aa4a..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
@@ -71,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);
@@ -85,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
@@ -123,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 3f862e47..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,9 +15,7 @@ abstract contract EnforcementModuleInternal is
Initializable,
ContextUpgradeable
{
- // keccak256(abi.encode(uint256(keccak256("CMTAT.storage.EnforcementModuleInternal")) - 1)) & ~bytes32(uint256(0xff))
- bytes32 private constant EnforcementModuleInternalStorageLocation = 0x0c7bc8a17be064111d299d7669f49519cb26c58611b72d9f6ccc40a1e1184e00;
-
+ /* ============ Events ============ */
/**
* @notice Emitted when an address is frozen.
*/
@@ -38,16 +36,28 @@ abstract contract EnforcementModuleInternal is
string reason
);
- /* Variables */
+ /* ============ 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.
*/
@@ -56,6 +66,10 @@ abstract contract EnforcementModuleInternal is
return $._frozen[account];
}
+ /*//////////////////////////////////////////////////////////////
+ INTERNAL/PRIVATE FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+
/**
* @dev Freezes an address.
* @param account the account to freeze
@@ -94,6 +108,7 @@ abstract contract EnforcementModuleInternal is
return true;
}
+ /* ============ 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 7f1a29e1..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,24 +14,19 @@ abstract contract ValidationModuleInternal is
Initializable,
ContextUpgradeable
{
- // keccak256(abi.encode(uint256(keccak256("CMTAT.storage.ValidationModuleInternal")) - 1)) & ~bytes32(uint256(0xff))
- bytes32 private constant ValidationModuleInternalStorageLocation = 0xb3e8f29e401cfa802cad91001b5f9eb50decccdb111d80cb07177ab650b04700;
- /* Variables */
- struct ValidationModuleInternalStorage {
- IRuleEngine _ruleEngine;
- }
- /*
-
+ /* ============ Events ============ */
/**
* @dev Emitted when a rule engine is set.
*/
event RuleEngine(IRuleEngine indexed newRuleEngine);
-
- function ruleEngine() public view returns(IRuleEngine){
- ValidationModuleInternalStorage storage $ = _getValidationModuleInternalStorage();
- return $._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 {
@@ -42,6 +37,21 @@ abstract contract ValidationModuleInternal is
}
}
+
+ /*//////////////////////////////////////////////////////////////
+ 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.
*/
@@ -81,6 +91,8 @@ abstract contract ValidationModuleInternal is
return $._ruleEngine.operateOnTransfer(from, to, amount);
}
+
+ /* ============ 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 2862f1ac..f29f822c 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";
@@ -18,17 +18,7 @@ import "../../../libraries/Errors.sol";
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;
}
-
+ /* ============ Events ============ */
/**
- * @dev See {OpenZeppelin - ERC20Snapshot}
- */
- mapping(address => Snapshots) internal _accountBalanceSnapshots;
- Snapshots internal _totalSupplySnapshots;
-
- /**
- * @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,19 +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
_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
@@ -134,28 +148,15 @@ abstract contract SnapshotModuleBase is Initializable {
revert Errors.CMTAT_SnapshotModule_SnapshotAlreadyExists();
}
}
- _scheduledSnapshots.push(time);
+ $._scheduledSnapshots.push(time);
emit SnapshotSchedule(0, time);
}
- 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();
- }
- }
-
/**
* @dev schedule a snapshot at the specified time
*/
function _scheduleSnapshotNotOptimized(uint256 time) internal {
+ SnapshotModuleBaseStorage storage $ = _getSnapshotModuleBaseStorage();
_checkTimeInThePast(time);
(bool isFound, uint256 index) = _findScheduledSnapshotIndex(time);
// Perfect match
@@ -163,19 +164,19 @@ abstract contract SnapshotModuleBase is Initializable {
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);
}
@@ -184,18 +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
_checkTimeSnapshotAlreadyDone(oldTime);
_checkTimeInThePast(newTime);
- if (_scheduledSnapshots.length == 0) {
+ 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(
@@ -207,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);
}
@@ -223,16 +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
_checkTimeSnapshotAlreadyDone(time);
- if (_scheduledSnapshots.length == 0) {
+ 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);
}
@@ -243,16 +243,15 @@ abstract contract SnapshotModuleBase is Initializable {
* - Reduce the array size by deleting the last snapshot
*/
function _unscheduleSnapshotNotOptimized(uint256 time) internal {
+ SnapshotModuleBaseStorage storage $ = _getSnapshotModuleBaseStorage();
_checkTimeSnapshotAlreadyDone(time);
- (bool isFound, uint256 index) = _findScheduledSnapshotIndex(time);
- if (!isFound) {
- revert Errors.CMTAT_SnapshotModule_SnapshotNotFound();
- }
+
+ 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();
}
/**
@@ -299,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);
@@ -312,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;
}
}
@@ -342,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);
}
@@ -370,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);
}
@@ -382,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
@@ -394,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 7da1381a..fea79fd9 100644
--- a/contracts/modules/security/AuthorizationModule.sol
+++ b/contracts/modules/security/AuthorizationModule.sol
@@ -2,21 +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 {
+ /* ============ 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;
- /* Variables */
+ /* ==== ERC-7201 State Variables === */
struct AuthorizationModuleStorage {
IAuthorizationEngine _authorizationEngine;
}
- /**
- * @dev Emitted when a rule engine is set.
- */
- event AuthorizationEngine(IAuthorizationEngine indexed newAuthorizationEngine);
+ /* ============ Initializer Function ============ */
/**
* @dev
*
@@ -37,6 +40,11 @@ abstract contract AuthorizationModule is AccessControlUpgradeable {
}
}
+
+ /*//////////////////////////////////////////////////////////////
+ PUBLIC/EXTERNAL FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+
function authorizationEngine() public view virtual returns (IAuthorizationEngine) {
AuthorizationModuleStorage storage $ = _getAuthorizationModuleStorage();
return $._authorizationEngine;
@@ -96,6 +104,13 @@ abstract contract AuthorizationModule is AccessControlUpgradeable {
return AccessControlUpgradeable.hasRole(role, account);
}
+
+ /*//////////////////////////////////////////////////////////////
+ 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 c777c53c..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
@@ -116,6 +123,10 @@ abstract contract ValidationModule is
return true;
}
+
+ /*//////////////////////////////////////////////////////////////
+ INTERNAL/PRIVATE FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
function _validateTransferByModule(
address from,
address to,
diff --git a/contracts/modules/wrapper/core/BaseModule.sol b/contracts/modules/wrapper/core/BaseModule.sol
index 11f48590..08cc5e87 100644
--- a/contracts/modules/wrapper/core/BaseModule.sol
+++ b/contracts/modules/wrapper/core/BaseModule.sol
@@ -6,22 +6,14 @@ pragma solidity ^0.8.20;
import "../../security/AuthorizationModule.sol";
import "../../../libraries/Errors.sol";
abstract contract BaseModule is AuthorizationModule {
- // keccak256(abi.encode(uint256(keccak256("CMTAT.storage.BaseModule")) - 1)) & ~bytes32(uint256(0xff))
- bytes32 private constant BaseModuleStorageLocation = 0xa98e72f7f70574363edb12c42a03ac1feb8cc898a6e0a30f6eefbab7093e0d00;
-
- /* Variables */
- struct BaseModuleStorage {
- string _tokenId;
- string _terms;
- string _information;
- }
+ /* ============ State Variables ============ */
/**
* @notice
* Get the current version of the smart contract
*/
- string public constant VERSION = "2.4.1";
+ string public constant VERSION = "2.5.0";
- /* Events */
+ /* ============ Events ============ */
event Term(string indexed newTermIndexed, string newTerm);
event TokenId(string indexed newTokenIdIndexed, string newTokenId);
event Information(
@@ -29,10 +21,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;
-
-
- /* Initializers */
+ /* ==== ERC-7201 State Variables === */
+ struct BaseModuleStorage {
+ string _tokenId;
+ string _terms;
+ string _information;
+ }
+ /* ============ Initializer Function ============ */
/**
* @dev Sets the values for {name} and {symbol}.
*
@@ -50,7 +49,9 @@ abstract contract BaseModule is AuthorizationModule {
$._information = information_;
}
- /* Methods */
+ /*//////////////////////////////////////////////////////////////
+ PUBLIC/EXTERNAL FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
function tokenId() public view virtual returns (string memory) {
BaseModuleStorage storage $ = _getBaseModuleStorage();
@@ -100,6 +101,11 @@ abstract contract BaseModule is AuthorizationModule {
}
+ /*//////////////////////////////////////////////////////////////
+ INTERNAL/PRIVATE FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+
+ /* ============ ERC-7201 ============ */
function _getBaseModuleStorage() private pure returns (BaseModuleStorage storage $) {
assembly {
$.slot := BaseModuleStorageLocation
diff --git a/contracts/modules/wrapper/core/ERC20BaseModule.sol b/contracts/modules/wrapper/core/ERC20BaseModule.sol
index 183e7562..5eeb4e1d 100644
--- a/contracts/modules/wrapper/core/ERC20BaseModule.sol
+++ b/contracts/modules/wrapper/core/ERC20BaseModule.sol
@@ -3,28 +3,27 @@
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";
abstract contract ERC20BaseModule is ERC20Upgradeable {
- // keccak256(abi.encode(uint256(keccak256("CMTAT.storage.ERC20BaseModule")) - 1)) & ~bytes32(uint256(0xff))
- bytes32 private constant ERC20BaseModuleStorageLocation = 0x9bd8d607565c0370ae5f91651ca67fd26d4438022bf72037316600e29e6a3a00;
-
- struct ERC20BaseModuleStorage {
- uint8 _decimals;
- }
-
- /* 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;
+ }
- /* 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.
@@ -35,8 +34,9 @@ abstract contract ERC20BaseModule is ERC20Upgradeable {
ERC20BaseModuleStorage storage $ = _getERC20BaseModuleStorage();
$._decimals = decimals_;
}
-
- /* Methods */
+ /*//////////////////////////////////////////////////////////////
+ PUBLIC/EXTERNAL FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
/**
*
* @notice Returns the number of decimals used to get its user representation.
@@ -116,6 +116,13 @@ abstract contract ERC20BaseModule is ERC20Upgradeable {
totalSupply = ERC20Upgradeable.totalSupply();
}
+
+ /*//////////////////////////////////////////////////////////////
+ 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 02c951fe..f3db15d2 100644
--- a/contracts/modules/wrapper/core/ERC20BurnModule.sol
+++ b/contracts/modules/wrapper/core/ERC20BurnModule.sol
@@ -2,12 +2,15 @@
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";
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 +19,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
diff --git a/contracts/modules/wrapper/core/ERC20MintModule.sol b/contracts/modules/wrapper/core/ERC20MintModule.sol
index 3e94861c..9e872c1e 100644
--- a/contracts/modules/wrapper/core/ERC20MintModule.sol
+++ b/contracts/modules/wrapper/core/ERC20MintModule.sol
@@ -2,22 +2,28 @@
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";
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
diff --git a/contracts/modules/wrapper/core/EnforcementModule.sol b/contracts/modules/wrapper/core/EnforcementModule.sol
index aff0d705..89c446b3 100644
--- a/contracts/modules/wrapper/core/EnforcementModule.sol
+++ b/contracts/modules/wrapper/core/EnforcementModule.sol
@@ -14,7 +14,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 +22,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
diff --git a/contracts/modules/wrapper/core/PauseModule.sol b/contracts/modules/wrapper/core/PauseModule.sol
index edaa7c49..746af11a 100644
--- a/contracts/modules/wrapper/core/PauseModule.sol
+++ b/contracts/modules/wrapper/core/PauseModule.sol
@@ -2,7 +2,7 @@
pragma solidity ^0.8.20;
-import "../../../../openzeppelin-contracts-upgradeable/contracts/utils/PausableUpgradeable.sol";
+import "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
import "../../security/AuthorizationModule.sol";
/**
@@ -16,28 +16,27 @@ import "../../security/AuthorizationModule.sol";
* event of a large bug.
*/
abstract contract PauseModule is PausableUpgradeable, AuthorizationModule {
+ /* ============ State Variables ============ */
+ bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
+ string internal constant TEXT_TRANSFER_REJECTED_PAUSED =
+ "All transfers paused";
+ /* ============ 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;
}
-
- function _getPauseModuleStorage() private pure returns (PauseModuleStorage storage $) {
- assembly {
- $.slot := PauseModuleStorageLocation
- }
- }
-
- // PauseModule
- bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
- string internal constant TEXT_TRANSFER_REJECTED_PAUSED =
- "All transfers paused";
- event Deactivated(address account);
-
+ /* ============ 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}.
@@ -93,4 +92,17 @@ abstract contract PauseModule is PausableUpgradeable, AuthorizationModule {
PauseModuleStorage storage $ = _getPauseModuleStorage();
return $._isDeactivated;
}
+
+
+ /*//////////////////////////////////////////////////////////////
+ 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
index 90217304..eb67dce2 100644
--- a/contracts/modules/wrapper/extensions/DebtModule.sol
+++ b/contracts/modules/wrapper/extensions/DebtModule.sol
@@ -7,18 +7,24 @@ import "../../../libraries/Errors.sol";
import "../../../interfaces/engine/IDebtEngine.sol";
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;
- /* Variables */
+ /* ==== 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
*
@@ -36,7 +42,9 @@ abstract contract DebtModule is AuthorizationModule, IDebtEngine {
}
-
+ /*//////////////////////////////////////////////////////////////
+ PUBLIC/EXTERNAL FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
function debtEngine() public view virtual returns (IDebtEngine) {
DebtModuleStorage storage $ = _getDebtModuleStorage();
return $._debtEngine;
@@ -71,6 +79,12 @@ abstract contract DebtModule is AuthorizationModule, IDebtEngine {
}
}
+
+ /*//////////////////////////////////////////////////////////////
+ INTERNAL/PRIVATE FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+
+ /* ============ ERC-7201 ============ */
function _getDebtModuleStorage() private pure returns (DebtModuleStorage storage $) {
assembly {
$.slot := DebtModuleStorageLocation
diff --git a/contracts/modules/wrapper/extensions/DocumentModule.sol b/contracts/modules/wrapper/extensions/DocumentModule.sol
index a42eec09..a66c5b6c 100644
--- a/contracts/modules/wrapper/extensions/DocumentModule.sol
+++ b/contracts/modules/wrapper/extensions/DocumentModule.sol
@@ -6,27 +6,22 @@ import "../../security/AuthorizationModule.sol";
import "../../../libraries/Errors.sol";
import "../../../interfaces/engine/draft-IERC1643.sol";
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;
}
- function documentEngine() public view virtual returns (IERC1643) {
- DocumentModuleStorage storage $ = _getDocumentModuleStorage();
- return $._documentEngine;
- }
-
- function _getDocumentModuleStorage() private pure returns (DocumentModuleStorage storage $) {
- assembly {
- $.slot := DocumentModuleStorageLocation
- }
- }
- /**
- * @dev Emitted when a rule engine is set.
- */
- event DocumentEngine(IERC1643 indexed newDocumentEngine);
+ /* ============ Initializer Function ============ */
/**
* @dev
*
@@ -43,6 +38,14 @@ abstract contract DocumentModule is AuthorizationModule, IERC1643 {
}
}
+ /*//////////////////////////////////////////////////////////////
+ PUBLIC/EXTERNAL FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
+ function documentEngine() public view virtual returns (IERC1643) {
+ DocumentModuleStorage storage $ = _getDocumentModuleStorage();
+ return $._documentEngine;
+ }
+
/*
* @notice set an authorizationEngine if not already set
*
@@ -74,4 +77,16 @@ abstract contract DocumentModule is AuthorizationModule, IERC1643 {
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 4a079607..ae618eb5 100644
--- a/contracts/modules/wrapper/extensions/ERC20SnapshotModule.sol
+++ b/contracts/modules/wrapper/extensions/ERC20SnapshotModule.sol
@@ -15,12 +15,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.
diff --git a/contracts/modules/wrapper/extensions/MetaTxModule.sol b/contracts/modules/wrapper/extensions/MetaTxModule.sol
index 0e7e6279..1fb09868 100644
--- a/contracts/modules/wrapper/extensions/MetaTxModule.sol
+++ b/contracts/modules/wrapper/extensions/MetaTxModule.sol
@@ -2,7 +2,7 @@
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.
diff --git a/doc/TOOLCHAIN.md b/doc/TOOLCHAIN.md
index 0bc5b122..03b64792 100644
--- a/doc/TOOLCHAIN.md
+++ b/doc/TOOLCHAIN.md
@@ -101,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)**
@@ -133,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 e8383c2c..4b36c3fb 100644
--- a/doc/USAGE.md
+++ b/doc/USAGE.md
@@ -8,10 +8,9 @@ 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
-- Solidity 0.8.22 (via solc-js)
+- Hardhat ^2.22.7
+- Solidity 0.8.26 (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)
@@ -43,14 +42,14 @@ 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`
@@ -86,7 +85,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.
+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/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 3d3cdbd9..18655b87 100644
--- a/doc/general/test/coverage/contracts/CMTAT_PROXY.sol.html
+++ b/doc/general/test/coverage/contracts/CMTAT_PROXY.sol.html
@@ -78,7 +78,7 @@
// 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 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 information_ additional information to describe the token
- * @param engines list of engines
+ * @param ERC20Attributes_ ERC20 name, symbol and decimals
+ * @param baseModuleAttributes_ tokenId, terms, information
+ * @param engines_ external contract
*/
function initialize( address admin,
- string memory nameIrrevocable,
- string memory symbolIrrevocable,
- uint8 decimalsIrrevocable,
- string memory tokenId_,
- string memory terms_,
- string memory information_,
- IEngine.Engine memory engines) public override Einitializer {
+ ICMTATConstructor.ERC20Attributes memory ERC20Attributes_,
+ ICMTATConstructor.BaseModuleAttributes memory baseModuleAttributes_,
+ ICMTATConstructor.Engine memory engines_ ) public override Einitializer {
CMTAT_BASE.initialize( admin,
- nameIrrevocable,
- symbolIrrevocable,
- decimalsIrrevocable,
- tokenId_,
- terms_,
- information_,
- engines);
+ ERC20Attributes_,
+ baseModuleAttributes_,
+ engines_);
__UUPSUpgradeable_init_unchained();
}
+
+ /*//////////////////////////////////////////////////////////////
+ INTERNAL/PRIVATE FUNCTIONS
+ //////////////////////////////////////////////////////////////*/
function _authorizeUpgrade(address) internal override onlyRole(PROXY_UPGRADE_ROLE) {}
}
* @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 information_ additional information to describe the token
+ * @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,
- string memory nameIrrevocable,
- string memory symbolIrrevocable,
- uint8 decimalsIrrevocable,
- string memory tokenId_,
- string memory terms_,
- string memory information_,
- IEngine.Engine memory engine_
+ 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,
- nameIrrevocable,
- symbolIrrevocable,
- decimalsIrrevocable,
- tokenId_,
- terms_,
- information_,
- engine_
+ ERC20Attributes_,
+ baseModuleAttributes_,
+ engines_
);
}
}
@@ -184,7 +148,7 @@