Skip to content

Commit b03089d

Browse files
committed
Isolate RBAC role constants into dedicated storage contracts and archive rc4 audit tool reports
1 parent 4e6c8d1 commit b03089d

60 files changed

Lines changed: 1758 additions & 887 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,52 @@ forge lint
4545
- Update surya doc by running the 3 scripts in [./doc/script](./doc/script)
4646
- Update changelog
4747

48+
49+
50+
### v3.0.0-rc4 - 2026-05-22
51+
52+
### Added
53+
54+
- Add `RuleMintAllowance` mock rule: admin-controlled per-minter mint allowance with `setMintAllowance(address, uint256)`, enforcement in `transferred(spender, from, to, value)` when `from == address(0)`, and `CODE_MINTER_INSUFFICIENT_ALLOWANCE` (code 81).
55+
- Add `ERC3643ComplianceModuleInvariantStorage` in `src/modules/library/` to hold all `RuleEngine_ERC3643Compliance_*` custom errors, following the invariant storage pattern already used by `RulesManagementModule`.
56+
- Add `ERC3643ComplianceRolesStorage` in `src/modules/library/` as a dedicated contract for `COMPLIANCE_MANAGER_ROLE`, separating role constants from error/event declarations.
57+
58+
### Changed
59+
60+
- `ERC3643ComplianceModule` now inherits `ERC3643ComplianceModuleInvariantStorage` and `ERC3643ComplianceRolesStorage`; errors and role constant are no longer declared inline.
61+
- `RuleWhitelist.detectTransferRestrictionFrom`: spender check is now skipped for mint (`from == address(0)`) and burn (`to == address(0)`) operations, as the operator in those cases is the authorized minter/burner rather than a delegated spender.
62+
- `RuleWhitelist.transferred` (both overloads): removed `view` modifier to match the intended mutable-callback semantics of the `IRule` interface.
63+
- `RuleMintAllowance.transferred(address, address, uint256)`: removed `view` modifier for the same reason.
64+
- `COMPLIANCE_MANAGER_ROLE` moved from inline declaration in `ERC3643ComplianceModule` to `ERC3643ComplianceRolesStorage`.
65+
- `VersionModule.VERSION` constant visibility changed from `private` to `internal` to allow direct access by inheriting contracts and tests.
66+
- `IRulesManagementModule.containsRule` now correctly declares `view`.
67+
- `IRulesManagementModule.setMaxRules` NatSpec documents that high cap values re-expose O(n) gas cost for administrative operations such as `clearRules`.
68+
- `IRulesManagementModule.clearRules` NatSpec updated to reflect O(n) cost relative to rule count and the interaction with `maxRules`.
69+
- `RulesManagementModule.setRules` NatSpec now documents that `ClearRules` is emitted when replacing a non-empty rule set, in addition to `AddRule` per new rule.
70+
- `RuleWhitelist` imports converted from plain imports with forge-lint suppression comments to named imports.
71+
- `RuleEngineOwnable2Step` constructor now has full `@notice`/`@param` NatSpec.
72+
- `RuleEngine.grantRole` NatSpec documents the intentional asymmetry: the check prevents granting roles to current rules but does not prevent adding a privileged address as a rule afterwards.
73+
- `ERC3643ComplianceModule.bindToken` and `ERC3643ComplianceExtendedModule.bindTokens` now carry a `@custom:security-note` warning about cross-token state contamination in multi-tenant setups with stateful/operation rules.
74+
75+
### Documentation
76+
77+
- CLAUDE.md / AGENTS.md:
78+
- Inheritance hierarchy corrected to show `ERC3643ComplianceExtendedModule``ERC3643ComplianceModule``ERC3643ComplianceModuleInvariantStorage`.
79+
- Access control pattern section now documents the `_onlyRulesLimitManager` hook alongside `_onlyRulesManager` and `_onlyComplianceManager`.
80+
- Rule Execution Flow diagram extended with `created` and `destroyed` ERC-3643 entry points.
81+
- README:
82+
- CMTAT target version updated to v3.3.0 in both the compatibility table and the dependencies section.
83+
- "Like CMTAT" section rewritten to document the v3.3.0 spender path for mint and burn, with an operation/address table and a rule-authoring note.
84+
- `bindToken`/`unbindToken` function table updated to reflect `COMPLIANCE_MANAGER_ROLE or approved token self-call` access path.
85+
86+
### Dependencies
87+
88+
- Update CMTAT submodule to v3.3.0-rc1.
89+
4890
### v3.0.0-rc3 - 2026-05-07
4991

92+
Commit: `5827604be4e38f65c055a929c7b62462a20f4bbd`
93+
5094
### Security
5195

5296
- Enforce an on-chain maximum rule count in `RulesManagementModule` to mitigate transfer liveness risk from unbounded per-transfer rule iteration (Nethermind AuditAgent finding 3 follow-up).

README.md

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1404,20 +1404,20 @@ Here is the list of report performed with [Slither](https://github.com/crytic/sl
14041404

14051405
| Version | Report | Assessment |
14061406
| ------- | ------ | ---------- |
1407-
| v3.0.0-rc2 | [slither-report.md](./doc/security/audits/tools/slither-report.md) | [slither-report-feedback.md](./doc/security/audits/tools/slither-report-feedback.md) |
1407+
| v3.0.0-rc4 | [slither-report.md](./doc/security/audits/tools/v3.0.0-rc4/slither-report.md) | [slither-report-feedback.md](./doc/security/audits/tools/v3.0.0-rc4/slither-report-feedback.md) |
1408+
| v3.0.0-rc3 | [slither-report.md](./doc/security/audits/tools/v3.0.0-rc3/slither-report.md) | [slither-report-feedback.md](./doc/security/audits/tools/v3.0.0-rc3/slither-report-feedback.md) |
1409+
| v3.0.0-rc2 | [slither-report.md](./doc/security/audits/tools/v3.0.0-rc2/slither-report.md) | [slither-report-feedback.md](./doc/security/audits/tools/v3.0.0-rc2/slither-report-feedback.md) |
14081410

14091411
```bash
14101412
slither . --checklist --filter-paths "openzeppelin-contracts|test|CMTAT|forge-std|mocks" > slither-report.md
14111413
```
14121414

1413-
4 finding categories — 0 High · 0 Medium · 10 Low · 4 Informational
1415+
2 finding categories — 0 High · 0 Medium · 10 Low · 2 Informational
14141416

14151417
| ID | Detector | Impact | Instances | Assessment |
14161418
|----|----------|--------|-----------|------------|
14171419
| 0–9 | `calls-loop` | Low | 10 | Accepted by design — fan-out to rule contracts is the core architecture |
1418-
| 10 | `dead-code` | Informational | 1 | Accepted / no action — `_msgData` override is required by inheritance/context pattern |
1419-
| 11 | `naming-convention` | Informational | 1 | Ignored — finding is in external CMTAT dependency code |
1420-
| 12–13 | `unindexed-event-address` | Informational | 2 | Deferred — adding `indexed` to `TokenBound`/`TokenUnbound` is interface-breaking |
1420+
| 10–11 | `unindexed-event-address` | Informational | 2 | Deferred — adding `indexed` to `TokenBound`/`TokenUnbound` is interface-breaking |
14211421

14221422
#### Aderyn
14231423

@@ -1429,21 +1429,23 @@ aderyn -x mocks --output aderyn-report.md
14291429

14301430
| Version | Report | Assessment |
14311431
| ------- | ------ | ---------- |
1432-
| v3.0.0-rc2 | [aderyn-report.md](./doc/security/audits/tools/aderyn-report.md) | [aderyn-report-feedback.md](./doc/security/audits/tools/aderyn-report-feedback.md) |
1432+
| v3.0.0-rc4 | [aderyn-report.md](./doc/security/audits/tools/v3.0.0-rc4/aderyn-report.md) | [aderyn-report-feedback.md](./doc/security/audits/tools/v3.0.0-rc4/aderyn-report-feedback.md) |
1433+
| v3.0.0-rc3 | [aderyn-report.md](./doc/security/audits/tools/v3.0.0-rc3/aderyn-report.md) | [aderyn-report-feedback.md](./doc/security/audits/tools/v3.0.0-rc3/aderyn-report-feedback.md) |
1434+
| v3.0.0-rc2 | [aderyn-report.md](./doc/security/audits/tools/v3.0.0-rc2/aderyn-report.md) | [aderyn-report-feedback.md](./doc/security/audits/tools/v3.0.0-rc2/aderyn-report-feedback.md) |
14331435

1434-
Report scope: 18 Solidity files, 542 nSLOC.
1436+
Report scope: 24 Solidity files, 629 nSLOC.
14351437

14361438
0 High · 8 Low
14371439

14381440
| ID | Finding | Instances | Assessment |
14391441
|----|---------|-----------|------------|
14401442
| L-1 | Centralization Risk | 14 | Accepted by design — privileged compliance tool |
1441-
| L-2 | Unspecific Solidity Pragma | 14 | Accepted by design — intentional for library reusability |
1442-
| L-3 | PUSH0 Opcode | 18 | Not applicable — project targets Prague EVM |
1443+
| L-2 | Unspecific Solidity Pragma | 19 | Accepted by design — intentional for library reusability |
1444+
| L-3 | PUSH0 Opcode | 24 | Not applicable — project targets Prague EVM |
14431445
| L-4 | Modifier Invoked Only Once | 1 | Accepted by design — keeps hook-style access-control abstraction |
14441446
| L-5 | Empty Block | 9 | Accepted by design — access-control hook pattern |
1445-
| L-6 | Loop Contains `require`/`revert` | 1 | Accepted by design — `setRules` is an atomic batch operation |
1446-
| L-7 | Costly Operations Inside Loop | 1 | Accepted — unavoidable `SSTORE` in `setRules` |
1447+
| L-6 | Loop Contains `require`/`revert` | 4 | Accepted by design — `setRules` and `bindTokens`/`unbindTokens` are atomic batch operations |
1448+
| L-7 | Costly Operations Inside Loop | 4 | Accepted — unavoidable `SSTORE` in batch operations |
14471449
| L-8 | Unchecked Return | 1 | Accepted — `_grantRole` return is irrelevant in constructor |
14481450

14491451
## Documentation

doc/coverage/code-coverage.png

-783 Bytes
Loading

doc/coverage/coverage/index-sort-b.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
</tr>
3838
<tr>
3939
<td class="headerItem">Date:</td>
40-
<td class="headerValue">2026-05-06 17:22:22</td>
40+
<td class="headerValue">2026-05-22 15:31:49</td>
4141
<td></td>
4242
<td class="headerItem">Functions:</td>
4343
<td class="headerCovTableEntry">79</td>

doc/coverage/coverage/index-sort-f.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
</tr>
3838
<tr>
3939
<td class="headerItem">Date:</td>
40-
<td class="headerValue">2026-05-06 17:22:22</td>
40+
<td class="headerValue">2026-05-22 15:31:49</td>
4141
<td></td>
4242
<td class="headerItem">Functions:</td>
4343
<td class="headerCovTableEntry">79</td>

doc/coverage/coverage/index-sort-l.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
</tr>
3838
<tr>
3939
<td class="headerItem">Date:</td>
40-
<td class="headerValue">2026-05-06 17:22:22</td>
40+
<td class="headerValue">2026-05-22 15:31:49</td>
4141
<td></td>
4242
<td class="headerItem">Functions:</td>
4343
<td class="headerCovTableEntry">79</td>

doc/coverage/coverage/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
</tr>
3838
<tr>
3939
<td class="headerItem">Date:</td>
40-
<td class="headerValue">2026-05-06 17:22:22</td>
40+
<td class="headerValue">2026-05-22 15:31:49</td>
4141
<td></td>
4242
<td class="headerItem">Functions:</td>
4343
<td class="headerCovTableEntry">79</td>

doc/coverage/coverage/src/RuleEngineBase.sol.func-sort-c.html

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
</tr>
3838
<tr>
3939
<td class="headerItem">Date:</td>
40-
<td class="headerValue">2026-05-06 17:22:22</td>
40+
<td class="headerValue">2026-05-22 15:31:49</td>
4141
<td></td>
4242
<td class="headerItem">Functions:</td>
4343
<td class="headerCovTableEntry">14</td>
@@ -78,14 +78,14 @@
7878
</tr>
7979
<tr>
8080
<td class="coverFn"><a href="RuleEngineBase.sol.gcov.html#41">RuleEngineBase.transferred.0</a></td>
81-
<td class="coverFnHi">5</td>
81+
<td class="coverFnHi">6</td>
8282
</tr>
8383
<tr>
84-
<td class="coverFn"><a href="RuleEngineBase.sol.gcov.html#95">RuleEngineBase.detectTransferRestrictionFrom</a></td>
85-
<td class="coverFnHi">18</td>
84+
<td class="coverFn"><a href="RuleEngineBase.sol.gcov.html#54">RuleEngineBase.transferred.1</a></td>
85+
<td class="coverFnHi">17</td>
8686
</tr>
8787
<tr>
88-
<td class="coverFn"><a href="RuleEngineBase.sol.gcov.html#54">RuleEngineBase.transferred.1</a></td>
88+
<td class="coverFn"><a href="RuleEngineBase.sol.gcov.html#95">RuleEngineBase.detectTransferRestrictionFrom</a></td>
8989
<td class="coverFnHi">18</td>
9090
</tr>
9191
<tr>

doc/coverage/coverage/src/RuleEngineBase.sol.func.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
</tr>
3838
<tr>
3939
<td class="headerItem">Date:</td>
40-
<td class="headerValue">2026-05-06 17:22:22</td>
40+
<td class="headerValue">2026-05-22 15:31:49</td>
4141
<td></td>
4242
<td class="headerItem">Functions:</td>
4343
<td class="headerCovTableEntry">14</td>
@@ -118,11 +118,11 @@
118118
</tr>
119119
<tr>
120120
<td class="coverFn"><a href="RuleEngineBase.sol.gcov.html#41">RuleEngineBase.transferred.0</a></td>
121-
<td class="coverFnHi">5</td>
121+
<td class="coverFnHi">6</td>
122122
</tr>
123123
<tr>
124124
<td class="coverFn"><a href="RuleEngineBase.sol.gcov.html#54">RuleEngineBase.transferred.1</a></td>
125-
<td class="coverFnHi">18</td>
125+
<td class="coverFnHi">17</td>
126126
</tr>
127127
</table>
128128
<br>

doc/coverage/coverage/src/RuleEngineBase.sol.gcov.html

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
</tr>
3838
<tr>
3939
<td class="headerItem">Date:</td>
40-
<td class="headerValue">2026-05-06 17:22:22</td>
40+
<td class="headerValue">2026-05-22 15:31:49</td>
4141
<td></td>
4242
<td class="headerItem">Functions:</td>
4343
<td class="headerCovTableEntry">14</td>
@@ -111,26 +111,26 @@
111111
<a name="40"><span class="lineNum"> 40 </span> : : /*</a>
112112
<a name="41"><span class="lineNum"> 41 </span> : : * @inheritdoc IRuleEngine</a>
113113
<a name="42"><span class="lineNum"> 42 </span> : : */</a>
114-
<a name="43"><span class="lineNum"> 43 </span> :<span class="lineCov"> 5 : function transferred(address spender, address from, address to, uint256 value)</span></a>
114+
<a name="43"><span class="lineNum"> 43 </span> :<span class="lineCov"> 6 : function transferred(address spender, address from, address to, uint256 value)</span></a>
115115
<a name="44"><span class="lineNum"> 44 </span> : : public</a>
116116
<a name="45"><span class="lineNum"> 45 </span> : : virtual</a>
117117
<a name="46"><span class="lineNum"> 46 </span> : : override(IRuleEngine)</a>
118118
<a name="47"><span class="lineNum"> 47 </span> : : onlyBoundToken</a>
119119
<a name="48"><span class="lineNum"> 48 </span> : : {</a>
120120
<a name="49"><span class="lineNum"> 49 </span> : : // Apply on RuleEngine</a>
121-
<a name="50"><span class="lineNum"> 50 </span> :<span class="lineCov"> 4 : RulesManagementModule._transferred(spender, from, to, value);</span></a>
121+
<a name="50"><span class="lineNum"> 50 </span> :<span class="lineCov"> 5 : RulesManagementModule._transferred(spender, from, to, value);</span></a>
122122
<a name="51"><span class="lineNum"> 51 </span> : : }</a>
123123
<a name="52"><span class="lineNum"> 52 </span> : : </a>
124124
<a name="53"><span class="lineNum"> 53 </span> : : /**</a>
125125
<a name="54"><span class="lineNum"> 54 </span> : : * @inheritdoc IERC3643IComplianceContract</a>
126126
<a name="55"><span class="lineNum"> 55 </span> : : */</a>
127-
<a name="56"><span class="lineNum"> 56 </span> :<span class="lineCov"> 18 : function transferred(address from, address to, uint256 value)</span></a>
127+
<a name="56"><span class="lineNum"> 56 </span> :<span class="lineCov"> 17 : function transferred(address from, address to, uint256 value)</span></a>
128128
<a name="57"><span class="lineNum"> 57 </span> : : public</a>
129129
<a name="58"><span class="lineNum"> 58 </span> : : virtual</a>
130130
<a name="59"><span class="lineNum"> 59 </span> : : override(IERC3643IComplianceContract)</a>
131131
<a name="60"><span class="lineNum"> 60 </span> : : onlyBoundToken</a>
132132
<a name="61"><span class="lineNum"> 61 </span> : : {</a>
133-
<a name="62"><span class="lineNum"> 62 </span> :<span class="lineCov"> 16 : _transferred(from, to, value);</span></a>
133+
<a name="62"><span class="lineNum"> 62 </span> :<span class="lineCov"> 15 : _transferred(from, to, value);</span></a>
134134
<a name="63"><span class="lineNum"> 63 </span> : : }</a>
135135
<a name="64"><span class="lineNum"> 64 </span> : : </a>
136136
<a name="65"><span class="lineNum"> 65 </span> : : /// @inheritdoc IERC3643Compliance</a>

0 commit comments

Comments
 (0)