This project has not undergone an audit and is provided as-is without any warranties.
CMTAT is a framework for the tokenization of securities and other financial instruments in compliance with local regulations. This project implements a CMTAT version in Cairo allowing financial institutions to adopt the standard on Starknet.
This implementation is based on the Solidity version.
- CMTAT framework implementation
- Four Module Variants - Light, Allowlist, Debt, and Standard implementations
- ERC20 Compliance with regulatory extensions
- Role-Based Access Control with role getter functions
- Batch Operations for efficient multi-address operations
- Transfer Validation (ERC-1404 compatible)
- OpenZeppelin Components for security and reliability
Install scarb, a toolchain and package manager for Cairo and Starknet ecosystems.
# Build all contracts
scarb build
# Run tests
scarb test# Deploy complete ecosystem
./scripts/deploy.shMinimal feature set for basic CMTAT compliance
Constructor:
constructor(
admin: ContractAddress,
name: ByteArray,
symbol: ByteArray,
initial_supply: u256,
recipient: ContractAddress
)Features:
- Basic ERC20 functionality
- Minting (mint, batch_mint)
- Burning (burn, burn_from, batch_burn, forced_burn, burn_and_mint)
- Pause/Unpause/Deactivate
- Address freezing (set_address_frozen, batch_set_address_frozen)
- Information management (terms, information, token_id)
- Batch balance queries
- 4 Role constants (DEFAULT_ADMIN, MINTER, PAUSER, ENFORCER)
Use Cases: Standard token deployments, simple compliance requirements
All Light features plus allowlist functionality
Constructor:
constructor(
admin: ContractAddress,
name: ByteArray,
symbol: ByteArray,
initial_supply: u256,
recipient: ContractAddress
)Additional Features:
- Allowlist control (enable_allowlist, set_address_allowlist, batch_set_address_allowlist)
- Partial token freezing (freeze_partial_tokens, unfreeze_partial_tokens)
- Active balance queries (get_active_balance_of)
- Engine management (snapshot_engine, document_engine)
- 9 Role constants (includes ERC20ENFORCER, SNAPSHOOTER, DOCUMENT, EXTRA_INFORMATION)
Use Cases: Regulated tokens with whitelist requirements, KYC/AML compliance
Specialized for debt securities
Constructor:
constructor(
admin: ContractAddress,
name: ByteArray,
symbol: ByteArray,
initial_supply: u256,
recipient: ContractAddress
)Debt-Specific Features:
- Debt information management (debt, set_debt)
- Credit events tracking (credit_events, set_credit_events)
- Debt engine integration (debt_engine, set_debt_engine)
- Default flagging (flag_default)
- All Allowlist features (except allowlist-specific)
- 10 Role constants (includes DEBT_ROLE)
Use Cases: Corporate bonds, structured debt products, fixed income securities
Full feature set with transfer validation
Constructor:
constructor(
admin: ContractAddress,
name: ByteArray,
symbol: ByteArray,
initial_supply: u256,
recipient: ContractAddress
)Advanced Features:
- Transfer validation (restriction_code, message_for_transfer_restriction)
- ERC-1404 compliance
- All core CMTAT features
- 9 Role constants
Use Cases: Advanced compliance, institutional securities with transfer validation
Here is the list of implemented functions.
Information Management:
fn terms(self: @ContractState) -> ByteArray
fn set_terms(ref self: ContractState, new_terms: ByteArray) -> bool
fn information(self: @ContractState) -> ByteArray
fn set_information(ref self: ContractState, new_information: ByteArray) -> bool
fn token_id(self: @ContractState) -> ByteArray
fn set_token_id(ref self: ContractState, new_token_id: ByteArray) -> boolBatch Operations:
fn batch_balance_of(self: @ContractState, accounts: Span<ContractAddress>) -> Array<u256>
fn batch_mint(ref self: ContractState, tos: Span<ContractAddress>, values: Span<u256>) -> bool
fn batch_burn(ref self: ContractState, accounts: Span<ContractAddress>, values: Span<u256>) -> boolRole Getters:
fn get_default_admin_role(self: @ContractState) -> felt252
fn get_minter_role(self: @ContractState) -> felt252
fn get_pauser_role(self: @ContractState) -> felt252
// ... all role gettersMinting & Burning:
fn mint(ref self: ContractState, to: ContractAddress, value: u256) -> bool
fn burn(ref self: ContractState, value: u256) -> bool
fn burn_from(ref self: ContractState, from: ContractAddress, value: u256) -> bool
fn burn_and_mint(ref self: ContractState, from: ContractAddress, to: ContractAddress, value: u256) -> boolPause & Freeze:
fn paused(self: @ContractState) -> bool
fn pause(ref self: ContractState) -> bool
fn unpause(ref self: ContractState) -> bool
fn deactivated(self: @ContractState) -> bool
fn deactivate_contract(ref self: ContractState) -> bool
fn set_address_frozen(ref self: ContractState, account: ContractAddress, is_frozen: bool) -> bool
fn batch_set_address_frozen(ref self: ContractState, accounts: Span<ContractAddress>, frozen: Span<bool>) -> bool
fn is_frozen(self: @ContractState, account: ContractAddress) -> boolAllowlist Module:
fn enable_allowlist(ref self: ContractState, status: bool) -> bool
fn is_allowlist_enabled(self: @ContractState) -> bool
fn set_address_allowlist(ref self: ContractState, account: ContractAddress, status: bool) -> bool
fn batch_set_address_allowlist(ref self: ContractState, accounts: Span<ContractAddress>, statuses: Span<bool>) -> bool
fn is_allowlisted(self: @ContractState, account: ContractAddress) -> boolDebt Module:
fn debt(self: @ContractState) -> ByteArray
fn set_debt(ref self: ContractState, debt_: ByteArray) -> bool
fn credit_events(self: @ContractState) -> ByteArray
fn set_credit_events(ref self: ContractState, credit_events_: ByteArray) -> bool
fn debt_engine(self: @ContractState) -> ContractAddress
fn set_debt_engine(ref self: ContractState, debt_engine_: ContractAddress) -> bool
fn flag_default(ref self: ContractState) -> boolStandard Module:
fn restriction_code(self: @ContractState, from: ContractAddress, to: ContractAddress, value: u256) -> StandardCMTAT::RESTRICTION_CODE
fn message_for_transfer_restriction(self: @ContractState, restriction_code: StandardCMTAT::RESTRICTION_CODE) -> ByteArrayNote: The
restriction_codeandmessage_for_transfer_restrictionfunction signatures now useStandardCMTAT::RESTRICTION_CODEinstead ofu8for improved type safety. Callers must regenerate ABI/dispatcher after this signature change.
| Feature | Light | Allowlist | Debt | Standard |
|---|---|---|---|---|
| Basic ERC20 | ✅ | ✅ | ✅ | ✅ |
| Minting | ✅ | ✅ | ✅ | ✅ |
| Burning | ✅ | ✅ | ✅ | ✅ |
| Forced Burn | ✅ | ❌ | ❌ | ❌ |
| Pause/Unpause | ✅ | ✅ | ✅ | ✅ |
| Deactivation | ✅ | ✅ | ✅ | ✅ |
| Address Freezing | ✅ | ✅ | ✅ | ✅ |
| Partial Token Freezing | ❌ | ✅ | ✅ | ✅ |
| Batch Operations | ✅ | ✅ | ✅ | ✅ |
| Information Management | ✅ | ✅ | ✅ | ✅ |
| Allowlist | ❌ | ✅ | ❌ | ❌ |
| Debt Management | ❌ | ❌ | ✅ | ❌ |
| Transfer Validation | ❌ | ❌ | ❌ | ✅ |
| Engine Integration | ❌ | ✅ | ✅ | ✅ |
| Role Count | 4 | 9 | 10 | 9 |
cairo-cmtat/
├── src/
│ ├── contracts/
│ │ ├── light_cmtat.cairo # Minimal CMTAT (4 roles)
│ │ ├── allowlist_cmtat.cairo # With allowlist (9 roles)
│ │ ├── debt_cmtat.cairo # For debt securities (10 roles)
│ │ └── standard_cmtat.cairo # Full feature set (10 roles)
│ ├── engines/
│ │ ├── rule_engine.cairo # Transfer restrictions
│ │ └── snapshot_engine.cairo # Balance snapshots
│ └── interfaces/
│ └── icmtat.cairo # Interface definitions
├── tests/
│ └── cmtat_tests.cairo # Comprehensive tests
└── scripts/
└── deploy.sh # Deployment automation
// Deploy Allowlist CMTAT for KYC/AML compliance
let allowlist_cmtat = deploy_allowlist_cmtat(
admin,
"Regulated Security Token",
"RST",
1000000 * 10^18,
treasury
);
// Enable allowlist
allowlist_cmtat.enable_allowlist(true);
// Add approved addresses
let kyc_addresses = array![addr1, addr2, addr3];
let statuses = array![true, true, true];
allowlist_cmtat.batch_set_address_allowlist(kyc_addresses, statuses);// Deploy Debt CMTAT for bond issuance
let bond_token = deploy_debt_cmtat(
admin,
"Corporate Bond 2025",
"BOND25",
10000000 * 10^18,
issuer
);
// Set debt information
bond_token.set_debt("5% Senior Notes due 2025");
bond_token.set_credit_events("Investment Grade BBB+");
// Integrate debt calculation engine
bond_token.set_debt_engine(debt_calculation_engine);- DEFAULT_ADMIN_ROLE: Master administrator, can grant/revoke all roles
- MINTER_ROLE: Can create new tokens
- BURNER_ROLE: Can destroy tokens
- PAUSER_ROLE: Can pause/unpause contract
- ENFORCER_ROLE: Can freeze/unfreeze addresses
- ERC20ENFORCER_ROLE: Can freeze partial tokens
- SNAPSHOOTER_ROLE: Can create snapshots
- DOCUMENT_ROLE: Can manage documents
- EXTRA_INFORMATION_ROLE: Can update token metadata
- DEBT_ROLE: Can manage debt parameters
All modules implement transfer restrictions via ERC20 hooks:
- Pause state check
- Sender/recipient freeze check
- Active balance validation (for partial freezing)
- Custom validation (via transfer validation in Standard)
scarb buildcp .env.example .env
# Edit .env with your configuration./scripts/deploy.shThe script will:
- Deploy all four CMTAT modules
- Set up proper role assignments
- Configure engine integrations
- Output all contract addresses
# Run all tests
scarb test
# Run specific test
scarb test test_name
# Run with verbose output
scarb test --verboseFull API documentation for all modules available in-code documentation.
- Cairo 2.13.1
- Scarb 2.13.1
- Sierra: 1.7.0
- OpenZeppelin Cairo v2.0.0
src/contracts/ # Token implementations
src/engines/ # Compliance engines
src/interfaces/ # Contract interfaces
tests/ # Test suite
scripts/ # Deployment scripts
Contributions are welcome! Please follow these guidelines:
- Fork the repository
- Create a feature branch
- Write tests for new functionality
- Ensure all tests pass
- Submit a pull request
Mozilla Public License 2.0 (MPL-2.0)
- Starknet: https://starknet.io
- CMTAT: https://www.cmtat.org
- OpenZeppelin Cairo: https://github.com/OpenZeppelin/cairo-contracts
Built for compliant securities on Starknet
Version 0.1.0 - ABI Compatible Implementation