Factory contracts to deploy CMTAT security tokens behind upgradeable proxies, at deterministic addresses (CREATE2) and under role-based access control.
Note: This project has not undergone an audit and is provided as-is without any warranties.
📖 Full documentation / specification: doc/README.md
Diagram source: doc/schema/plantuml/overview.puml.
| Factory | Proxy | Implementation | Contract |
|---|---|---|---|
CMTAT_UUPS_FACTORY |
ERC1967Proxy (UUPS) |
CMTATUpgradeableUUPS |
contracts/standard/CMTAT_UUPS_FACTORY.sol |
CMTAT_TP_FACTORY |
TransparentUpgradeableProxy |
CMTATStandardUpgradeable |
contracts/standard/CMTAT_TP_FACTORY.sol |
CMTAT_BEACON_FACTORY |
BeaconProxy (shared UpgradeableBeacon) |
CMTATStandardUpgradeable |
contracts/standard/CMTAT_BEACON_FACTORY.sol |
CMTAT_LIGHT_TP_FACTORY |
TransparentUpgradeableProxy |
CMTATUpgradeableLight |
contracts/light/CMTAT_LIGHT_TP_FACTORY.sol |
CMTAT_LIGHT_BEACON_FACTORY |
BeaconProxy (shared UpgradeableBeacon) |
CMTATUpgradeableLight |
contracts/light/CMTAT_LIGHT_BEACON_FACTORY.sol |
Each family ships in two access-control variants, sharing identical deployment logic and differing only in who may deploy:
| Policy | Contract | Who may deploy | When to choose it |
|---|---|---|---|
| Role-based | CMTAT_*_FACTORY |
holders of CMTAT_DEPLOYER_ROLE |
duties must be separable — several deployers, independently revocable, admin distinct from deployer |
| Single-owner | CMTAT_*_FACTORY_Ownable2Step |
the owner() |
one operator, and a handover that cannot be lost to a mistyped address (transferOwnership then acceptOwnership) |
The variants are chosen at deployment and are not interchangeable at a deployed address.
Ownable2Stephas exactly one privilege level and cannot express separated duties.
- Standard factories deploy the full-featured CMTAT (RuleEngine, documents, snapshots, debt, cross-chain, meta-transactions) and take the
CMTAT_ARGUMENTinitializer struct. - Light factories deploy the minimal
CMTATUpgradeableLight(ERC-20 with mint/burn, pause, enforcement, validation, access control) and take the smallerCMTAT_LIGHT_ARGUMENTstruct.
See Proxy patterns: Transparent vs UUPS vs Beacon to choose a pattern, and CMTAT versions: Standard vs Light to choose an implementation.
- Multiple proxy types — UUPS, Transparent, or Beacon, depending on your upgrade strategy.
- Deterministic addresses — proxies are deployed with
CREATE2;computedProxyAddress(...)/computedNextProxyAddress(...)return the address before deployment. - Pluggable access control — one deployment entrypoint, two policies:
CMTAT_DEPLOYER_ROLEor a singleOwnable2Stepowner, selected by which contract you deploy. - Deployment registry — every proxy is indexed by an incremental id and emitted in a
CMTATDeployedevent. - Versioned on-chain — factories expose ERC-8303
version(); current version is0.5.0.
All factories share the following surface (see Common factory API for details):
// returns the concrete proxy type: ERC1967Proxy, TransparentUpgradeableProxy or BeaconProxy
function deployCMTAT(bytes32 deploymentSaltInput, /* [address proxyAdminOwner,] */ CMTAT_ARGUMENT calldata) public returns (Proxy);
function computedProxyAddress(bytes32 deploymentSalt, /* [address proxyAdminOwner,] */ CMTAT_ARGUMENT calldata) public view returns (address);
function computedNextProxyAddress(/* ... same trailing args ... */) public view returns (address);
function nextDeploymentSalt() public view returns (bytes32);
function isCustomSaltUsed(bytes32 salt) public view returns (bool); // custom-salt mode: already consumed?
function CMTATProxyAddress(uint256 id) public view returns (address);
function version() public view returns (string memory);
event CMTATDeployed(address indexed proxy, address indexed deployer, uint256 indexed id, bytes32 salt);
⚠️ Salt mode. WithuseCustomSalt == falsethe salt is derived from the sharedcmtatCounterId, so a predicted address can be taken by another deployer. PreferuseCustomSalt == truewith a unique caller-chosen salt to reserve an address. See Salt behavior.
git clone git@github.com:CMTA/CMTATFactory.git --recurse-submodules
cd CMTATFactory
nvm use # Node 20.5.0
npm install
npx hardhat testOther useful commands:
npx hardhat compile
npm run coverage # solidity-coverage
npm run size # hardhat-contract-sizer
npm run lint:sol # solhint (add :fix to autofix)
npm run lint:js # eslint (add :fix to autofix)AI assistance: Parts of this project were written with the help of AI coding assistants, principally Claude Code (Anthropic) and Codex (OpenAI).
Toolchain: Hardhat ^2.26.1, Node 20.5.0, Solidity 0.8.36 (EVM prague), CMTAT v3.3.0-rc3, OpenZeppelin Contracts (+ Upgradeable) v5.7.0.
| Document | Content |
|---|---|
| doc/README.md | Full specification: architecture, library contracts, CREATE2, salt behavior, per-factory API, diagrams |
| doc/TOOLCHAIN.md | Toolchain details |
| doc/Solidity-API-Docgen.md | Generated Solidity API reference |
| doc/audits/AUDIT_OVERVIEW.md | Static-analysis reports and triage |
| contracts/interfaces/ICMTATFactory.sol | Import-free integration interface: the registry, salt and role surface every factory shares |
| doc/schema/ | PlantUML architecture diagrams (plantuml/, sources + renders), sol2uml class diagrams (sol2uml/), Surya inheritance / call graphs, drawio diagrams |
- Vulnerability disclosure: see SECURITY.md in the CMTAT main repository.
- Audit: this project has not undergone a formal audit.
- Static analysis: Slither, Aderyn, and Nethermind AuditAgent reports are versioned under doc/audits/; see the audit overview. For v0.5.0, neither Slither nor Aderyn reports anything to fix.
- Code quality: the v0.5.0 code-quality review found no vulnerabilities.
Taurus blog: Making CMTAT Tokenization More Scalable and Cost-Effective with Proxy and Factory Contracts (written for factory release 0.1.0).
The code is copyright (c) Capital Market and Technology Association, 2025-2026, and is released under Mozilla Public License 2.0.
