ERC-7943: Universal RWA Interface (uRWA)

The idea behind having 3 methods is that setFrozenTokens() is a super-power that explicitly “resolves” the race condition by ignoring it.

As a superpower it wouldn’t be available to most of the parties who are given the ability to freeze or unfreeze a quantum of tokens - and in the common case it is probably set not to be accessible to anyone.

I don’t understand the practical scenario where the race condition described for the delta methods arises - why are there 2 parties making overlapping demands on what should be the same tokens?

I do appreciate the gas efficiency argument - but does it hold true for a world where in practice you generally use the delta extensions?

The core question is about the use cases. If the assumption is that there is only one party able to freeze, and they do the relevant calculations offchain, then the absolute value makes sense. But that seems like a bad assumption to me. I cannot imagine a good reason to enable setting an absolute value (beyond the theoretical purity of making everyone work from first principles) unless you have one omnipotent central authority, and I can see plenty of problems with enabling that approach since in practice you probably then need to hem it in with extra checking any time it is exercised to ensure it isn’t a malicious over-reach.

I refer to my previous comment on delta updates.

I think we can make the assumption that the base use-case will be a single entrypoint or entity with the ability to freeze. More specific use-cases can be tailored on top of the standard.

For what’s in the spec, I’d value simplicity over completeness.

Nonetheless, there’s a valid argument in not settling for any specific implementation, which I think it holds more power than implementing both, or choosing delta over absolute updates.

TL;DR: OK. Yay for getting the spec to Last Call - “done” is a really important thing to achieve!

Seems there is a clear desire to start with the direct setting approach. As I noted, if the assumption is that in most cases there is only one authority that can activate the methods, that makes sense - and @tinom9 has just asserted that assumption. (It’s good to write down the motivating use cases and assess how they really work, precisely because they are relevant for decisions like this).

The big benefit in a standard is that implementors can re-use code and know that it will behave in a predictable way, which reduces cost and the likelihood of errors. This is why I think real us cases trump simplicity in the spec.

Side note: W3C has a concept of “priority of constituencies” where they explixitly adopted the idea that it is more important to help end-users than implementors, and more important to help implementors than to have “theoretical purity’. I think it’s a useful concept, although of course the details effectively need interpretation each time…

In my belief that there will be multiple authorities in many cases, I still think it’s worth setting out a standard interface for the delta case, even if it is listed as “SHOULD”. In particular I am thinking of secondary standards (e.g. regulatory or pseudo-regulatory) that directly address how to make tokens, in which it would be helpful to mandate using a particular form, such as that outlined in the spec as an example.

That said, it’s always possible to build an extension in a seperate spec if there is a demonstrated call for it, including for a secondary spec to directly copy the example and mandate it as the right way to deal with the question.

In other words, I am OK with the decision to continue as is.

I really like this ERC. It’s clear, simple and easy to implement.
I just have one question:

    /// @notice Error reverted when an account is not allowed to transact. 
    /// @param account The address of the account which is not allowed for transfers.
    error ERC7943CannotTransact(address account);

    /// @notice Checks if a specific account is allowed to transact according to token rules.
    function canTransact(address account) external view returns (bool allowed);

From this comments it’s not clear for me:
this account should be tx sender, from address, to address or any one of them (implementation-specific)?
Later in the canTransact() description it says:

- MUST perform a canTransact check on the from and to parameters. 

So i guess canTransact() should return false if an address is not allowed to be from or to.
Can such restricted address be msg.sender or tx.origin ?

Maybe it would make sense to clarify this in the ERC.

Some discussions happened recently in a working group and I’ll try to answer @pash7ka here and provide more context on latest discussions:

@pash7ka it seems to me that canTransact is pretty clear indeed, it checks elegibility for the account parameter, independently from what it represents. The one which is context-aware is canTransfer indeed, which might apply limitations based on context (msg.sender, tx.origin, block.timestamp or similar).

Round of updates after several discussions:

There’s seems to be some interest in getting some formatting done properly and there’s a PR at the work:

Among others thing, this PRs add a specification on canTransfer being exclusively for permissioned checks and that permissionless ones like balance checks are not to be take into account within the function execution. This clearly remaks the permissioned nature of 7943 tokens and suggests integrators to run any eventual permissionless check needed outside of it.

While we came to an agreement about adding a specification like that, we started discussing about practice uses of canTransact which seems to be unable to distinguish between whether an user can send or receive funds, or if those abilities depends on amounts. As it stands it just provides a way to know whether someone is eligible to interact at all with the token contract.

This marks a perfection distinction between a quantitative/context-aware function like canTransfer (that receives also amounts in and depends on context), and a qualitative/context-free function like canTransact to know if an user can interact. @mihaic195 proposed even add this distinction to the specs which I might be ok with.

However, there are contrasting opinions on whether canTransact function should return two booleans (bool canSend, bool canReceive) instead of one, which would enable granular use cases without compromising the qualitative/context-free approach of canTransact (meaning it still has no clue of amounts or other context specific parameters) and still making the function a bit smarter. The good about such change would also be that the function signature would not change and the interface would be kept minimal.

@tinom9 suggested to run this to the community so here we are trying to see whether such latest addition would make sense. Happy to know thoughts !

1 Like

That’s the core of my point: elegibility for what?
To be sender, to be receiver, to be operator, or transaction sender?

Since you considering (bool canSend, bool canReceive), maybe it would make sense to go further and work with it as flags (uint8)?
0b00000001 - can be sender
0b00000010 - can be receiver
0b00000100 - can be spender (msg.sender)
0b00001000 - can be tx sender (tx.origin)
so that 0x00 allows no roles, 0x0F allows any of above roles.

While setFrozenTokens() can be extended with delta-based freeze/unFreeze functions, the current event signature lacks the context required for quick off-chain synchronization / crosschecks.

I propose changing the event from a single-value absolute end state to a state-transition signature:

Current: event Frozen(address indexed account, uint256 amount);

Proposed: event Frozen(address indexed account, uint256 previousAmount, uint256 newAmount);

Scenario Example

This change clarifies state updates during complex operations like forced transfers and several consecutive requests from authorities:

  1. Initial Freeze request (1000 tokens): emit Frozen(account, 0, 1000)
  2. Force Transfer request (800 tokens): If the holder only has 600 tokens, the frozen balance must be adjusted to cover the remainder. emit Frozen(account, 1000, 400) (assuming 600 were deducted from the frozen bucket, 200 yet to transfer in the future, 200 outstanding (1000-800))
  3. Additional Freeze request (500 tokens): emit Frozen(account, 400, 900) - this one clearly demonstrates delta = +500 i.e. consistent to the formal request

Hey @radek

Thanks for the input !

If you look at the top of the conversation we already went through this topic

The conclusion was that indeed indexers will need to track either way something, and balances or allowances updates are not providing this feature and it seems the industry lives well without it too. I agree with @tinom9 there. I believe that expecially with deltas extensions, it might have more sense to do so.

Apologies, I somehow missed that in the surrounding noise :slight_smile:

You both are right - the delta extensions might cover the delta view / events with I would say even different event semantics.

Hi

Interesting thread , i v been following since the early freeze/unfreeze discussions.

One gap I keep running into building on top of RWA tokens: uRWA standardizes how the token behaves (freeze, force transfer, compliance hooks), but there’s no standard way to query what’s behind the token. Is the custodian solvent? Has the asset been audited recently? What’s the bridge dependency? When Aave lost $196M last week from rsETH, the token interface worked perfectly — the problem was invisible dependencies in the underlying asset.

We ran into this building a quality oracle on Base (120+ RWA assets scored across 7 risk layers — issuance, counterparty, market, contagion, regulatory, smart contract, operational). The scoring works, but every integration is custom because there’s no standard way to expose that data.

Would uRWA consider an optional extension for machine-readable asset metadata beyond compliance , something like a getRiskLayer(uint8 layer) view function? Or is that intentionally out of scope?

Re Context: working on a related ERC for trust infrastructure that could compose with uRWA on this front.

Patrick - Tkanks

Happy to work on composable extensions for 7943, but I would consider we should not put this at the base layer. Let’s ping me on anything you’re working on to compose on top and I’ll be happy to help

Thanks @xaler

much appreciated.

On our side: IRWAPassport interface + 7-layer risk schema, reference implementation live on Base + Gnosis (120+ RWA assets scored). Spec is in the ERC-8240 thread, post #2.

I’ll draft a short composition note this week or early next, showing how a 7943-compliant token reads quality data via IRWAPassport at the consumer layer

base layer untouched, as you suggest. Will send it your way and welcome any pushback.

Patrick