
REGISTRY-STATE REFERENCE
A mandate bound to one specific right. The authority is scoped to a single instrument by the mandate itself, so the mandate registry refuses the wrong instrument before any compliance logic of ours is reached. Built at the request of the ERC-8226 author.
Version 1 · 10 September 2026 Ethereum Sepolia · test network Synthetic instruments
An ERC-8226 mandate names an asset, which is a contract address, and a contract can hold many
rights. The action field is a bytes32 label, and an implementation may bind selected
call parameters into it rather than using a bare function selector. Here the label is computed
per instrument, so a mandate granted over instrument 1 carries no authority over instrument 2.
| Asset | 0x16EFE870B7E1a50bd95f70d80196B8ECd49d3B65 · source verified on Sourcify, exact match |
|---|---|
| Agent | 0x24aED5d14EAA4Dc677E4FE75775C12DB0dc2d5c3 · its own wallet, because authority is scoped per wallet |
| Mandate registry | 0xB7e7B1ca762144A135FB43F9f543Ee76B21B8583 · Brickken, unmodified |
| Refused transaction | 0xc8a4923c…40ae5025 · block 11674884 |
Both instrument 1 and instrument 2 were published as current in the FACTOS registry, with the same holder. Registry state is therefore not what separates them. Neither is identity: the same agent, the same holder, the same asset and the same mandate are in play. The only difference is the action label the mandate enumerates.
| Instrument 1 | canExecute answers (true, OK) · the agent acts |
|---|---|
| Instrument 2 | canExecute answers (false, 6) · the operation reverts with NoMandate(agent, 6) |
state at block … is pruned
rather than the result. Any archive endpoint works; https://sepolia.gateway.tenderly.co
is one. This is the same trap that made our own test suite pass only on the machine that had
already cached the data.
cast call 0x16EFE870B7E1a50bd95f70d80196B8ECd49d3B65 \
"actionFor(uint256)(bytes32)" 1 --rpc-url <archive>
# 0x5f4958916a8d370b970c4a6bdbe9bc2d6065d51c27df1b7382c211e41d5687c2
cast call 0xB7e7B1ca762144A135FB43F9f543Ee76B21B8583 \
"canExecute(address,address,address,bytes32,uint256)(bool,uint8)" \
0x24aED5d14EAA4Dc677E4FE75775C12DB0dc2d5c3 0x06a1cb40BeDb8f8462cF9C5E8aa84bad1Fa36929 \
0x16EFE870B7E1a50bd95f70d80196B8ECd49d3B65 \
0x5f4958916a8d370b970c4a6bdbe9bc2d6065d51c27df1b7382c211e41d5687c2 \
100000000000000000000 --rpc-url <archive> --block 11674884
# true 0 instrument 1: the mandate covers it
# same call with the label for instrument 2
# 0xfb31040b64366fe15ce45243795cefbf2509d3b4448c566fd02528c40ec40951
# false 6 instrument 2: it does not
A parameter-scoped action binds the mandate to an instrument at the moment it is granted, and that binding is static. It says nothing about whether the right still exists, or whether the holder is still the holder, at the moment the agent acts. Those are answered by the registry read in FACTOS-PRS-2026-09-08. The two controls sit at different moments and neither replaces the other.
We also reported that reason code 6, ACTION_NOT_ENABLED, reads as though the
operation were forbidden when in fact it is permitted on a different object. That reading was
answered in the thread and the answer is better than ours: because the action label is opaque to
the mandate registry, the registry cannot know which part of the label failed to match, so the
correct fix is to define the existing code precisely rather than to add another one.