Releases: CMTA/RuleEngine
v3.0.0-rc3
Security
- Enforce an on-chain maximum rule count in
RulesManagementModuleto mitigate transfer liveness risk from unbounded per-transfer rule iteration (Nethermind AuditAgent finding 3 follow-up). - Add cap checks in both
addRuleandsetRules, reverting withRuleEngine_RulesManagementModule_MaxRulesExceeded(uint256)when exceeded. - Enforce on-chain privilege-separation for rule accounts:
RuleEngine.grantRolenow reverts for any role whenaccountis currently in the rules set.RuleEngineOwnableandRuleEngineOwnable2Stepnow rejecttransferOwnershiptargets that are currently in the rules set.
- Add T-REX compatibility path for compliance binding operations with admission control:
- token self-calls (
msg.sender == token) forbindToken(token)/unbindToken(token)are supported only when explicitly approved. - unapproved token self-calls are rejected and still require manager/owner authorization.
- token self-calls (
Added
- Add
maxRules()andsetMaxRules(uint256)toIRulesManagementModule. - Add
DEFAULT_MAX_RULES = 10and initialize module state with this default cap. - Add
SetMaxRules(uint256)event emitted on cap updates. - Add interface ID libraries:
ERC1404InterfaceIdforIERC1404(0xab84a5c8)OwnableInterfaceIdforIERC173(0x7f5828d0)Ownable2StepInterfaceIdfor Ownable2Step-specific methods (0x9ab669ef)
- Add dedicated access-control hook for cap governance:
RuleEngine:DEFAULT_ADMIN_ROLEcan update cap.RuleEngineOwnableandRuleEngineOwnable2Step: owner can update cap.
- Add
RuleEngine_RulesManagementModule_RuleAccountCannotReceivePrivileges()error for rule-account privilege/ownership target protection. - Add token self-binding approval management to
IERC3643ComplianceExtended/ERC3643ComplianceExtendedModule:setTokenSelfBindingApproval(address token, bool approved)isTokenSelfBindingApproved(address token)TokenSelfBindingApprovalSet(address indexed token, bool approved)event.
- Add batch self-binding approval API in
IERC3643ComplianceExtended/ERC3643ComplianceExtendedModule:setTokenSelfBindingApprovalBatch(address[] tokens, bool approved).TokenSelfBindingApprovalBatchSet(address[] tokens, bool approved)event.
Changed
- Ownable variants now rely on OpenZeppelin
ERC165inheritance inRuleEngineOwnableSharedfor base ERC-165 advertisement and extend it with RuleEngine + ERC-173 interface IDs. supportsInterfaceadvertisement now explicitly includesIERC1404in addition toIERC1404Extend.RuleEngineOwnable2Step.supportsInterfacenow advertises the Ownable2Step-specific interface ID in addition to inherited RuleEngine/Ownable interfaces.ERC3643ComplianceModuleauthorization logic now requires explicit per-token approval for token-driven self-bind/self-unbind flows.- Split compliance interfaces between standard and extensions:
IERC3643Compliancenow contains the base ERC-3643 compliance surface.- supplementary functions are grouped in
IERC3643ComplianceExtendedand advertised through a dedicated ERC-165 extension interface ID.
- Split compliance modules between standard and extensions:
ERC3643ComplianceModulenow contains the base ERC-3643 compliance surface.- supplementary functions are grouped in
ERC3643ComplianceExtendedModule.
- Batch self-binding approval event emission now uses a single batch event (
TokenSelfBindingApprovalBatchSet) per call instead of per-tokenTokenSelfBindingApprovalSetemissions.
Testing
- Add tests for default cap value, cap enforcement for
addRuleandsetRules, and access control onsetMaxRules. - Add event-emission coverage for
SetMaxRules. - Extend interface advertisement tests to validate interface IDs through both:
- library constants
type(<mock interface>).interfaceId
forIERC1404andIERC173.
- Extend
RuleEngineOwnable2Stepinterface support tests to assert:- library constant support (
Ownable2StepInterfaceId.IOWNABLE2STEP_INTERFACE_ID) - mock interface support (
type(IOwnable2StepSubset).interfaceId).
- library constant support (
- Add RBAC tests ensuring roles cannot be granted to rule accounts.
- Add ownable and ownable2step tests ensuring ownership cannot be transferred to rule accounts.
- Add compliance-binding authorization tests across RBAC/ownable/ownable2step variants for:
- approved token self-bind
- approved token self-unbind
- unapproved token self-bind/self-unbind denial
- cross-token bind/unbind denial
- Add tests for self-binding approval management across RBAC/ownable/ownable2step variants:
- single approval set
- batch approval set
- zero-address rejection
- unauthorized caller rejection.
- Add ERC-3643
setCompliance-style migration test with a dedicated mock token to validate unbind(old) + bind(new) flow against RuleEngine self-binding approval controls.
Documentation
- Clarify README multi-token guidance with explicit data-plane vs control-plane wording:
- data-plane = runtime compliance callbacks (
transferred,created,destroyed) - control-plane = governance/configuration actions (
bindToken,unbindToken, role grants, ownership changes, and rule management)
- data-plane = runtime compliance callbacks (
- Document that token-privilege separation in multi-token setups is an operational recommendation (not enforced on-chain) to preserve integrator flexibility for token-driven control-plane extensions.
- Document ERC-3643
setCompliancecompatibility details in README:- token self-bind/self-unbind feature support
- required explicit self-binding approval
- recommended operational sequence for compliance migration.
Acknowledge
We would like to thank @0xsereel, @Domson97, as well as CMTA Tech Comite for their valuable feedback and contributions to this release. Their input played an important role in improving the project, and we sincerely appreciate their support.
v3.0.0-rc2
Dependencies
- Update CMTAT submodule to v3.2.0.
- Update OpenZeppelin Contracts and OpenZeppelin Contracts Upgradeable submodules to v5.6.1.
- Set Solidity version to 0.8.34 in
hardhat.config.jsandfoundry.toml. - Standardize local OpenZeppelin imports on
@openzeppelin/contracts/...and remove the legacyOZ/remapping to avoid Hardhat source-name collisions.
Fixed
RuleEngineOwnable.supportsInterfaceincorrectly advertisedIAccessControlvia the inheritedAccessControl.supportsInterfacefallback. Replaced with an explicit whitelist;supportsInterface(IAccessControl)now returnsfalseas expected (Nethermind AuditAgent finding 2).- Advertise ERC-3643 compliance interface ID (
0x3144991c) and IERC7551Compliance subset interface ID (0x7157797f) insupportsInterfacefor bothRuleEngineandRuleEngineOwnable(Nethermind AuditAgent finding 6). - Fix Hardhat compatibility after the OpenZeppelin upgrade by removing duplicate import namespaces that resolved to the same file under
hardhat-foundry. - Fix
hardhat.config.jsSolidity config shape so Hardhat applies the configured optimizer and EVM target instead of falling back to defaults.
Added
- Move deployable contracts to
src/deployment/and rename RBAC deployable contractRuleEnginetoRuleEngine. RuleEngine.supportsInterfacenow advertisesIAccessControlEnumerable.
Changed
- Switch
RuleEngineRBAC base from OpenZeppelinAccessControltoAccessControlEnumerablewhile keeping the custom "default admin has all roles" behavior. - Remove
AccessControlinheritance fromRulesManagementModule; RBAC responsibilities are now explicitly held byRuleEngine, while the module remains access-control agnostic.
Security
- Add NatSpec and README warnings on
bindToken/unbindToken: in a multi-tenant setup (multiple tokens sharing one engine), all bound tokens must be equally trusted and governed together; ERC-3643 callbacks do not carry the token address to rules (Nethermind AuditAgent finding 1). - Add NatSpec warnings on
addRule,setRules, and_transferred: rule contracts must not be grantedRULES_MANAGEMENT_ROLEor admin privileges (Nethermind AuditAgent finding 5). - Add NatSpec warnings on
addRule,setRules, and_transferred: no on-chain maximum rule count is enforced; operators are responsible for sizing the rule set for the target chain gas limits (Nethermind AuditAgent finding 3). - Add restriction-code uniqueness convention to
IRule.canReturnTransferRestrictionCodeand_messageForTransferRestriction: codes must be unique across rules, or rules sharing a code must return the same message (Nethermind AuditAgent finding 4). - Add NatSpec on
setRulesdocumenting the empty-array rejection by design and referring toclearRulesfor explicit removal (Nethermind AuditAgent finding 7).
Testing
- Add
testDoesNotSupportIAccessControlInterfacetoRuleEngineOwnableCoverageassertingIAccessControlis not advertised. - Add ERC-3643 and IERC7551Compliance
supportsInterfacecoverage tests to bothRuleEngineCoverageandRuleEngineOwnableCoverage. - Add mock interfaces
src/mocks/ICompliance.solandsrc/mocks/IERC7551ComplianceSubset.solused by coverage tests. - Extend
RuleEngineDeploymentinterface coverage to assert support forIAccessControlEnumerable. - Add a small Hardhat smoke test (
test/hardhat/RuleEngine.smoke.js) to confirmRuleEnginecan be compiled, deployed, and queried through Hardhat. - Add the npm script
test:hardhatto run the Hardhat smoke test directly.
Documentation
- Add Nethermind AuditAgent scan #1 report and remediation assessment (
doc/security/audits/tools/nethermind-audit-agent/). - Update README Security section with Nethermind AuditAgent findings summary table.
- Update README toolchain and testing sections to mention Hardhat compilation support and the small Hardhat smoke test.
v3.0.0-rc1
Added
- Add
RuleEngineOwnablecontract variant using ERC-173 ownership (Ownable) as an alternative to the RBAC-basedRuleEngine. ERC-3643 compliance specification recommends ERC-173 for ownership. - Add ERC-165
supportsInterfacecheck when adding rules viaaddRule/setRules, ensuring that only valid rule contracts (implementingIRule) can be registered. - Use CMTAT library for ERC-165 interface ID constants (
RuleEngineInterfaceId,ERC1404ExtendInterfaceId). - Add compatibility with CMTAT v3.0.0 and v3.2.0-rc0 (dual-version test support via
CMTATDeploymentV3).
Fixed
- Fix deployment script
CMTATWithRuleEngineScript: deploy CMTAT with the deployer as admin instead of a hardcoded address, which causedsetRuleEngineto revert withAccessControlUnauthorizedAccount. - Remove dead code in
RuleEngineOwnableconstructor: the custom zero-address owner check was unreachable becauseOwnable(owner_)already reverts withOwnableInvalidOwner(address(0)). - Remove duplicate code across rule contracts.
Dependencies
- Update CMTAT library to v3.2.0-rc0
- Update OpenZeppelin Contracts to v5.4.0
- Update Foundry (forge-std) to v1.10.0
- Set Solidity version to 0.8.33 and EVM version to Prague (Pectra upgrade)
Code quality
- Resolve all
forge lintwarnings: convert plain imports to named imports, remove unused imports, rename variables/functions to mixedCase, refactor modifier logic, and add targeted lint suppressions where appropriate. - Replace Prettier and Ethlint/Solium with Foundry-native
forge fmtandforge lintfor formatting and linting. - Run
forge fmton the entire codebase.
Testing
- Add deployment script tests (
test/script/) forCMTATWithRuleEngineScriptandRuleEngineScript. - Add
RuleEngineOwnabletest suite: deployment, access control, ERC-3643 compliance, rules management, and coverage tests. - Add
IRuleInterfaceIdtest for ERC-165 interface ID computation. - Add integration tests with CMTAT v3.0.0 and v3.2.0-rc0.
- Improve code coverage with additional edge-case tests.
Documentation
- Expand README with contract variants comparison, constructor API, access control details, and ERC-173 ownership documentation.
- Add formatting & linting section to README and TOOLCHAIN documentation.
- Update surya diagrams, coverage reports, and specification documents.
Acknowledge
We would like to thank @amilazz, as well as CMTA Tech Comite for their valuable feedback and contributions to this release. Their input played an important role in improving the project, and we sincerely appreciate their support.
v3.0.0-rc0
-
Rule contracts, requires to perform compliance check, have now their own dedicated GitHub repository. It means that these contract will be developed and audited separately from the RuleEngine. This provides more flexibility and makes it easier to manage audits.
-
There is now only one type of rule (read-write rules). Before that:
- First RuleEngine version (audited) had only one type of rule, read-only (whitelist, blacklist)
- A second RuleEngine version (not audited) had two types of rules: operation (read-write) and validation (read-only). A read-write rule is typically a ConditionalTransfer check which require each transfer must be pre-approved.
-
Implement ERC-3643 compliance interface, which means that the RuleEngine can be also used with an ERC-3643 token to perform supplementary compliance check on transfer.
-
Technical:
- Use EnumerableSet from OpenZeppelin to store rules, which reduce the whole contract code size.
- Rename several abstract contract
RuleEngineOperation-> RulesManagementModule
MetaTxModuleStandalone -> ERC2771ModuleStandalone
v2.1.0
-
Update RuleEngine to CMTAT v3.0.0-rc5
-
Update OpenZeppelin to v.5.3.0
-
Add "partial" support of spender check introduced with CMTAT v3.0.0-rc5
-
Change several functions
--- operateOnTransfer -> transferred(...)
----Add functions detectTransferRestrictionFrom and canTransferFrom
v2.0.5
Fix a bug present in the Conditional Transfer rule with the option automatic approval and improve the corresponding tests.
git clone https://github.com/CMTA/RuleEngine
git checkout v2.0.5
forge install
forge build
cd lib/CMTAT
npm install
v2.0.4
- Fix a bug present in the Conditional Transfer rule and the corresponding test.
- Config file:
Set Solidity version to 0.8.27 in config file
Set EVM version to Cancun - Add events for the following rules : whitelist/blacklist and sanctionList rules
- Some improvements in testing
Integration test with CMTAT: set the CMTAT version to v2.5.1 - Access control: The default admin has by default all the roles for the RuleEngine and the different rules
git clone https://github.com/CMTA/RuleEngine
git checkout v2.0.4
forge install
forge build
cd lib/CMTAT
npm install
v2.0.3
- Small optimization in WhitelistWrapper; add a break in a loop
- Set Solidity version to 0.8.26 in config file
- Add constant VERSION
The release does not include the .git folder, which does not allow installing dependencies.
The easiest solution is to clone the project and perform a git checkout on the version tag
git clone https://github.com/CMTA/RuleEngine
git checkout v2.0.3
forge install
forge build
v2.0.2
- Create abstract contract ruleWhitelistCommon to contain code shared between ruleWhitelist & ruleWhitelistWrapper
- Split ADDRESS_LIST_ROLE in two distinct roles : ADDRESS_LIST_ADD_ROLE && ADDRESS_LIST_REMOVE_ROLE
The release does not include the .git folder, which does not allow installing dependencies.
The easiest solution is to clone the project and perform a git checkout on the version tag
git clone https://github.com/CMTA/RuleEngine
git checkout v2.0.2
forge install
forge build
v2.0.1
Add a new rule WhitelistWrapper
This rule can be used to restrict transfers from/to only addresses inside a group of whitelist rules managed by different operators.
`The release does not include the .git folder, which does not allow installing dependencies.
The easiest solution is to clone the project and perform a git checkout on the version tag
git clone https://github.com/CMTA/RuleEngine
git checkout v2.0.1
forge install
forge build