ERC-1404 - Simple Restricted Token Standard

Soliciting feedback for ERC-1404.

The repository to check out is here.

Use of the standard lends to writing small, reusable smart contracts that are responsible for enforcing a single transfer restriction pattern.

Tokens implementing the standard are best constructed by composing said restrictions through multiple contract inheritance.

The examples in the above repo demonstrate several of these individual restriction implementations.

Would love to see criticism of the utility of these examples, their source code, and the standard itself!

1 Like

Hello @youfoundron and other potential people interested,

I have also posted on the Github issue but I post also here since this is the official place to discuss about ERC.

I wanted to ask about the current status of ERC-1404. Is there any plan to move it toward a finalized version or coordinate with the Ethereum Foundation to make it an official ERC standard?

There may be potential improvements (e.g., using uint256 instead of uint8 for restriction codes), but these could also be addressed in a different ERC since this ERC is already used as is for a long time

For context, I am one of the maintainer of CMTAT and we are using ERC-1404 in the CMTAT security token framework: CMTAT ( CMTA · GitHub )

ERC-1404 is still used today by other projects such as Centrifuge, blockdaemon

It would be great to hear any updates or thoughts on the standard’s next steps.

Hello everybody,

Following a discussion with @SamWilsn , I have opened a PR with an adapted version of the ERC-1404 content in the issue.

Let me know in this thread if you have any comments on the updated version!

detectTransferRestrictionFrom

New update regarding the interface

Add a spender-aware companion to detectTransferRestriction, called detectTransferRestrictionFrom, plus a note on reusing it for mint/burn.

  • this change is backward compatible.
  • Nothing in the mandatory ERC-1404 interface changes, the mandatory ERC-165 interface id stays the same, and any existing implementation remains compliant with no edits.

Reason

detectTransferRestriction(from, to, value) describes a transfer purely in terms of from, to, and value.

It has no spender parameter, so it can’t express a restriction that depends on the party initiating a delegated transfer.

For ERC-20, transferFrom is executed by a spender that may differ from from. A perfectly reasonable compliance policy — “this operator is frozen”, or “this operator hasn’t passed its own KYC/AML” — is therefore invisible to detectTransferRestriction.

An integrator predicting a transferFrom outcome by calling only the base method mispredicts exactly these cases: the view returns 0, and the transferFrom then reverts.

What I’m proposing to add

1. Optional detectTransferRestrictionFrom

function detectTransferRestrictionFrom(address spender, address from, address to, uint256 value) external view returns (uint8);

Returns a restriction code for the delegated transfer of value from from to to initiated by spender, or 0 if unrestricted. Same restriction-code space as detectTransferRestriction, same messageForTransferRestriction lookup.

An implementation that exposes it MUST:

  • keep it consistent with delegated-transfer enforcement — a transferFrom by spender is rejected if detectTransferRestrictionFrom(spender, from, to, value) returns non-zero;
  • return exactly detectTransferRestriction(from, to, value) when spender == from (a direct transfer is the degenerate delegated transfer whose initiator is the holder);
  • not change the meaning of, or consistency required of, the base method — the base method still describes the from/to/value conditions; the extension only adds the spender dimension.

2. A separate ERC-165 id for discovery

  • Mandatory ERC-1404 id: 0xab84a5c8 — unchanged, XOR of the two base-method selectors.
  • Optional extension id: 0x78a8de7d — XOR of all three selectors.

An implementation exposing the extension advertises both. The extension id deliberately covers all three selectors so a single supportsInterface(0x78a8de7d) == true proves all three methods are present. (It has to be computed as an explicit XOR of the three selectors — type(IExtension).interfaceId on an interface that only declares the added method would cover just one selector and mustn’t be used here.)

3. Mint/burn can reuse the spender path

Mint and burn stay out of the mandatory scope (supply-changing ops, not transfer/transferFrom), and checking them stays an optional MAY.

The new note: where an implementation does check mint/burn and exposes the extension, the spender parameter of detectTransferRestrictionFrom MAY carry the operator initiating the mint or burn, so the policy can restrict that operator directly — rather than trying to pass address(0) (the ERC-20 mint/burn counterparty) into the base method, which a whitelist policy would just reject.

Why it’s backward compatible

  • Mandatory interface unchangeddetectTransferRestriction and messageForTransferRestriction keep identical signatures and semantics. An existing ERC-1404 token is still conforming with zero changes.
  • Mandatory ERC-165 id unchangedsupportsInterface(0xab84a5c8) still answers for the two base methods; the extension lives under a distinct id a base-only integrator can ignore.
  • Purely additive and optional — the extension is a MAY. A token that never implements it loses nothing and violates nothing; base-only integrators keep working exactly as before.
  • Consistent by construction where it matters — the spender == from rule forces the extension to agree with the base method on direct transfers, so the two can’t contradict each other for the case they both describe.
  • No new mandatory conformance bar — the mint/burn note is doubly gated (MAY check and MAY use spender), imposing nothing on existing implementations.

Feedback

Let me know if you have any feedback on that. The Pull Request contains already the different changed proposed here