Skip to content

Commit 5ed2727

Browse files
committed
docs: state that RuleChainlinkPoR is ERC-20 only and fix the README ERC-7943/ITransferContext support claims
1 parent a401773 commit 5ed2727

3 files changed

Lines changed: 31 additions & 7 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ Custom changelog tag: `Dependencies`, `Documentation`, `Testing`
4949

5050
_Nothing yet._
5151

52-
## v0.5.0 - 2026-08-11
52+
## v0.5.0 - 2026-08-12
5353

5454
Commit: _pending — not yet committed at the time of writing._
5555

@@ -85,6 +85,7 @@ requires a second Foundry profile — **`forge test` alone no longer runs everyt
8585
- **Revert-free read path** — one `code.length` check covers both feed calls (Solidity's extcodesize revert on a `try` to a codeless address is uncatchable), `decimals()` and `latestRoundData()` are both wrapped in `try/catch`, `MAX_FEED_DECIMALS` is re-checked at read time so the scaling exponent cannot overflow, decimal scaling saturates rather than overflows, and the supply comparison uses remaining headroom. The ERC-1404 / ERC-3643 views therefore return a code instead of reverting under every feed failure mode.
8686
- **Token validated at configuration** — a non-contract address is rejected explicitly (`RuleChainlinkPoR_TokenIsNotAContract`) and `totalSupply()` is probed (`RuleChainlinkPoR_TokenTotalSupplyUnavailable`), so a token that cannot serve the restriction check fails loudly at setup instead of silently bricking the read path. At run time a reverting or codeless token yields code `78` rather than a revert.
8787
- `maxBackedSupply()` previews the current limit without simulating a mint.
88+
- **ERC-20 only.** Like `RuleMaxTotalSupply`, the rule exposes no ERC-7943 `tokenId` overloads and no `ITransferContext` entrypoints — it inherits `RuleTransferValidation` rather than `RuleNFTAdapter` — and it requires an aggregate `totalSupply()`, which plain ERC-721 lacks and which is per-id for ERC-1155. Deliberate: a reserve cap on a fungible supply has no `tokenId` dimension. Recorded in the overload matrix in `RULE_SEMANTICS.md`.
8889
- **Documented:** one instance protects one token. The rule reads `totalSupply()` from its configured `tokenContract` rather than from the token that triggered the check, and has no binding to enforce the pairing — sharing an instance across RuleEngines silently evaluates both tokens against the first one's supply and feed. Same exposure as `RuleMaxTotalSupply`; see [One instance per protected token](./doc/technical/RuleChainlinkPoR.md#one-instance-per-protected-token).
8990
- **`RuleReceiverWhitelist`** — a whitelist that screens **only the receiver**, reproducing ERC-3643's eligibility rule as a CMTAT compliance rule. It fills the gap between `RuleWhitelist` (both parties) and `RuleSpenderWhitelist` (spender only). Restriction code `81`. Available as `RuleReceiverWhitelist` (AccessControl) and `RuleReceiverWhitelistOwnable2Step`.
9091
- The sender and the spender are **never** screened. That is the point, not an omission: screening the sender traps de-listed holders, and ERC-3643 checks only the receiver precisely so a lapsed investor can still exit their position.
@@ -111,7 +112,8 @@ requires a second Foundry profile — **`forge test` alone no longer runs everyt
111112

112113
- New [`doc/technical/RuleReceiverWhitelist.md`](./doc/technical/RuleReceiverWhitelist.md), including why receiver-only screening is the conformant choice and how the parity suite tests it.
113114
- New [`doc/technical/IdentityRegistryWhitelist.md`](./doc/technical/IdentityRegistryWhitelist.md), including a table of which ERC-3643 token functions call the registry and how, the `recoveryAddress` call sequence, and five documented limitations.
114-
- New [`doc/technical/RuleChainlinkPoR.md`](./doc/technical/RuleChainlinkPoR.md), including a point-by-point comparison against Chainlink's `SecureMintPolicy 1.2.0` (vendored at `lib/chainlink-ace/`); `RULE_SEMANTICS.md` and `README.md` updated with the new rule.
115+
- New [`doc/technical/RuleChainlinkPoR.md`](./doc/technical/RuleChainlinkPoR.md), including a point-by-point comparison against Chainlink's `SecureMintPolicy 1.2.0` (vendored at `lib/chainlink-ace/`) and a *Token compatibility: ERC-20 only* section; `RULE_SEMANTICS.md` and `README.md` updated with the new rule.
116+
- **README ERC-721/ERC-1155 section corrected.** It listed only `RuleConditionalTransferLight` and `RuleMaxTotalSupply` as ERC-20 only, and described `IERC7943NonFungibleCompliance*` as "implemented by validation rules only" — a category claim that `RuleChainlinkPoR`, itself a validation rule, does not satisfy, so the README implied the opposite of the truth for the new rule. The exclusions are now named individually and the missing `totalSupply()` requirement is stated. The `ITransferContext` paragraph had the same defect and claimed `RuleMaxTotalSupply` exposes the fungible variant, which it does not — it exposes neither, as do `RuleChainlinkPoR` and `RuleMintAllowance`. `RULE_SEMANTICS.md` already had the correct matrix row for all of them; the README sections now link to it.
115117

116118
### Testing
117119

README.md

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,12 @@ _Diagram source: doc/img/readme-erc3643-integration.puml._
100100

101101
### ERC-721/ERC-1155
102102

103-
To improve compatibility with [ERC-721](https://eips.ethereum.org/EIPS/eip-721) and [ERC-1155](https://eips.ethereum.org/EIPS/eip-1155), most validation rules implement the interface `IERC7943NonFungibleComplianceExtend` which includes compliance functions with the `tokenId` argument. Operation rules (such as `RuleConditionalTransferLight`) are ERC-20 only and do not expose the ERC-721/1155 interfaces. `RuleMaxTotalSupply` is ERC-20 only as well and does not expose ERC-721/1155 interfaces.
103+
To improve compatibility with [ERC-721](https://eips.ethereum.org/EIPS/eip-721) and [ERC-1155](https://eips.ethereum.org/EIPS/eip-1155), most validation rules implement the interface `IERC7943NonFungibleComplianceExtend` which includes compliance functions with the `tokenId` argument.
104+
105+
- Operation rules (such as `RuleConditionalTransferLight`) are ERC-20 only and do not expose the ERC-721/1155 interfaces.
106+
- The two supply-cap validation rules, `RuleMaxTotalSupply` and `RuleChainlinkPoR`, are ERC-20 only as well and do not expose the ERC-721/1155 interfaces. This is deliberate: they cap a fungible supply, so a `tokenId` dimension would be meaningless for them. Both also require the protected token to expose an aggregate `totalSupply()`, which plain ERC-721 does not (only `ERC721Enumerable` does) and which is not per-id for ERC-1155.
107+
108+
The full per-rule overload matrix is in [`doc/technical/RULE_SEMANTICS.md`](./doc/technical/RULE_SEMANTICS.md#3-overload-surface-erc-7943-tokenid--itransfercontext).
104109

105110
While no rules currently apply restriction on the token id, the validation interfaces can be used to implement flexible restriction on ERC-721 or ERC-1155 tokens.
106111

@@ -120,7 +125,11 @@ function transferred(address from, address to, uint256 tokenId, uint256 value) e
120125
function transferred(address spender, address from, address to, uint256 tokenId, uint256 value) external;
121126
```
122127

123-
The diagram below shows a non-fungible transfer flowing through the `tokenId`-aware compliance signatures. For validation rules a single `transferred(...)` call both validates and reverts — it internally runs `detectTransferRestrictionFrom` and requires `TRANSFER_OK` — so no separate pre-check is required in the transfer path; the read-only `detectTransferRestriction*` / `canTransfer*` overloads remain available for off-chain queries. The `RuleNFTAdapter` carries the `tokenId` argument but currently delegates to the address-based checks (`from` / `to` / `spender`), so no rule restricts on the token id yet.
128+
The diagram below shows a non-fungible transfer flowing through the `tokenId`-aware compliance signatures.
129+
130+
For validation rules a single `transferred(...)` call both validates and reverts — it internally runs `detectTransferRestrictionFrom` and requires `TRANSFER_OK` — so no separate pre-check is required in the transfer path; the read-only `detectTransferRestriction*` / `canTransfer*` overloads remain available for off-chain queries.
131+
132+
The `RuleNFTAdapter` carries the `tokenId` argument but currently delegates to the address-based checks (`from` / `to` / `spender`), so no rule restricts on the token id yet.
124133

125134
![ERC-721 / ERC-1155 compliance interface flow](./doc/img/readme-erc721-erc1155-compliance.png)
126135

@@ -222,7 +231,11 @@ This makes rules directly pluggable into CMTAT without any intermediary RuleEngi
222231

223232
### Transfer Context Helper
224233

225-
Rules also expose an optional unified entrypoint using `MultiTokenTransferContext` / `FungibleTransferContext` (see `ITransferContext`) to pass a single struct instead of multiple arguments. This is a helper API inspired by [TokenF](https://github.com/dl-tokenf/contracts) and does not replace the standard ERC-3643 / RuleEngine interfaces. Validation rules generally expose both the non-fungible and fungible variants; `RuleConditionalTransferLight` and `RuleMaxTotalSupply` expose only the fungible variant.
234+
Rules also expose an optional unified entrypoint using `MultiTokenTransferContext` / `FungibleTransferContext` (see `ITransferContext`) to pass a single struct instead of multiple arguments.
235+
236+
This is a helper API inspired by [TokenF](https://github.com/dl-tokenf/contracts) and does not replace the standard ERC-3643 / RuleEngine interfaces.
237+
238+
Validation rules generally expose both the non-fungible and fungible variants. `RuleConditionalTransferLight` and `RuleConditionalTransferLightMultiToken` expose only the fungible variant, and `RuleMaxTotalSupply`, `RuleChainlinkPoR` and `RuleMintAllowance` expose neither — see the per-rule matrix in [`doc/technical/RULE_SEMANTICS.md`](./doc/technical/RULE_SEMANTICS.md#3-overload-surface-erc-7943-tokenid--itransfercontext).
226239

227240
Two struct variants are available:
228241

@@ -1286,7 +1299,7 @@ If the address does not exist in the whitelist, there is no change for this addr
12861299

12871300
### IERC7943NonFungibleCompliance
12881301

1289-
Compliance interface for ERC-721 / ERC-1155–style non-fungible assets. This is implemented by validation rules only. `RuleConditionalTransferLight` and `RuleMaxTotalSupply` are ERC-20 only and do not implement this interface.
1302+
Compliance interface for ERC-721 / ERC-1155–style non-fungible assets. It is implemented by the address-screening validation rules only: the operation rules (such as `RuleConditionalTransferLight`) and the supply-cap rules `RuleMaxTotalSupply` and `RuleChainlinkPoR` are ERC-20 only and do not implement this interface.
12901303
For ERC-721, `amount` must always be `1`.
12911304

12921305
------
@@ -1339,7 +1352,7 @@ Verifies whether a token transfer is permitted according to the rule-based compl
13391352

13401353
### IERC7943NonFungibleComplianceExtend
13411354

1342-
Extended compliance interface for ERC-721 / ERC-1155 non-fungible assets. This is implemented by validation rules only. `RuleConditionalTransferLight` and `RuleMaxTotalSupply` are ERC-20 only and do not implement this interface.
1355+
Extended compliance interface for ERC-721 / ERC-1155 non-fungible assets. It is implemented by the address-screening validation rules only: the operation rules (such as `RuleConditionalTransferLight`) and the supply-cap rules `RuleMaxTotalSupply` and `RuleChainlinkPoR` are ERC-20 only and do not implement this interface.
13431356
Adds restriction-code reporting, spender-aware checks, and a post-transfer hook.
13441357

13451358
For ERC-721, `amount` / `value` must always be `1`.

doc/technical/RuleChainlinkPoR.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,15 @@ Only mint operations (`from == address(0)`) are gated. Plain transfers do not ch
1010

1111
The rule is modelled on Chainlink's [`SecureMintPolicy`](https://docs.chain.link/ace/reference/policy-library/secure-mint-policy) from the ACE policy library, re-expressed as an ERC-1404 / ERC-3643 compliance rule for this library and deliberately simplified: the ACE policy's configurable reserve margin is not carried over.
1212

13+
## Token compatibility: ERC-20 only
14+
15+
`RuleChainlinkPoR` is **not usable with an ERC-721 or ERC-1155 token**, for two independent reasons:
16+
17+
- **No ERC-7943 entrypoints.** The rule inherits `RuleTransferValidation` directly, not `RuleNFTAdapter`, so the `tokenId`-carrying overloads (`detectTransferRestriction(from, to, tokenId, amount)`, `transferred(from, to, tokenId, value)`, …) and the `ITransferContext` struct entrypoints do not exist on it, and it does not advertise `IERC7943NonFungibleComplianceExtend` through ERC-165. See the overload matrix in [`RULE_SEMANTICS.md`](./RULE_SEMANTICS.md#3-overload-surface-erc-7943-tokenid--itransfercontext).
18+
- **An aggregate `totalSupply()` is mandatory.** Configuration probes it and reverts with `RuleChainlinkPoR_TokenTotalSupplyUnavailable` when it is absent. Plain ERC-721 has no `totalSupply()` — only `ERC721Enumerable` does — and ERC-1155 supply is per token id (`ERC1155Supply.totalSupply(id)`), so an aggregate figure mixes every id together and a reserve cap derived from it means nothing for a multi-id collection.
19+
20+
This is a design choice, not an omission: the rule caps a *fungible supply* against a reserve figure, so a `tokenId` dimension carries no information for it. `RuleMaxTotalSupply` is ERC-20 only for the same reason. To cap issuance of a non-fungible asset, screen the participants with an address-based validation rule (`RuleWhitelist`, `RuleReceiverWhitelist`, …), all of which do expose the ERC-7943 overloads.
21+
1322
## Schema
1423

1524
### Graph

0 commit comments

Comments
 (0)