ERC-7943, the Universal Real-World Asset (uRWA) interface, defines the smallest common set of functions a compliant RWA token needs — eligibility checks, freezing and forced transfers — and lets you add them to an ERC-20, ERC-721, ERC-1155 or ERC-6909 token without adopting a full framework. It reached Final status in 2026 and was designed to align its naming with ERC-3643 and ERC-7518, so venues, wallets and custodians can integrate RWA tokens through one predictable interface.
Key takeaways
- Three interface variants: fungible (ERC-20 based), non-fungible (ERC-721 based) and multi-token (ERC-1155 / ERC-6909 based), each detectable through ERC-165.
- Core views:
canSend,canReceive,canTransfer,getFrozenTokens. Core actions:forcedTransfer,setFrozenTokens. - It specifies what must be checked, not how — identity, whitelists or claims are your choice.
- Public transfers must fail when
canTransfer,canSendorcanReceivereturn false, andcanTransfermust account for frozen balances.
The interface (fungible variant)
function canSend(address account) external view returns (bool allowed);
function canReceive(address account) external view returns (bool allowed);
function canTransfer(address from, address to, uint256 amount) external view returns (bool allowed);
function getFrozenTokens(address account) external view returns (uint256 amount);
function setFrozenTokens(address account, uint256 amount) external returns (bool result);
function forcedTransfer(address from, address to, uint256 amount) external returns (bool result);
event ForcedTransfer(address indexed from, address indexed to, uint256 amount);
event Frozen(address indexed account, uint256 amount);
The ERC-721 variant freezes individual token IDs (setFrozenTokens(account, tokenId, bool)), and the multi-token variant freezes amounts per ID. Custom errors such as ERC7943CannotSend, ERC7943CannotReceive and ERC7943InsufficientUnfrozenBalance give integrators precise failure reasons.
Design principles
- Minimalism. Only the functions needed for common compliance patterns; no identity framework, no modules.
- Separation of concerns.
canSendandcanReceivecheck account eligibility independently, so you can allow an account to exit a position while blocking new receipts. - Single freeze setter.
setFrozenTokensoverwrites the frozen amount instead of separate freeze/unfreeze calls. - Compatibility. Names follow ERC-3643 conventions (
forcedTransfer) to ease multi-standard integration.
When to use ERC-7943
- You already use ERC-1155 or ERC-721 for an RWA programme and want standard compliance hooks — for example a property portfolio or carbon credit vintages on ERC-1155.
- You run a platform issuing several token types and want venues and wallets to pre-check transfers the same way for all of them.
- You need a light footprint — fewer contracts and lower gas than a full ERC-3643 deployment — and your eligibility logic is simple.
- You are a venue or custodian wanting one integration path for diverse RWA tokens.
When ERC-3643 may still be better
If you need a ready-made identity model (ONCHAINID claims from trusted issuers), modular compliance rules and an established ecosystem of compliance tooling, ERC-3643 gives you more out of the box. The two are complementary: an ERC-3643 token can expose ERC-7943 functions too, although the spec notes ERC-3643’s canTransfer semantics differ slightly.
Implementation tips
- Implement checks in the internal update function so mint, burn and every transfer path are covered.
- Make
canTransfercallcanSendandcanReceiveand check unfrozen balances, as the spec requires. - Restrict
forcedTransferandsetFrozenTokensto an agent role on multisig; emit events for every use. - Decide whether forced transfers bypass
canReceive(e.g. to a recovery wallet) and document it. - For ERC-721/1155 variants, use re-entrancy guards — receiver hooks run external code.
- Advertise support via
supportsInterfacewith the correct interface ID.
Example: adding ERC-7943 to an ERC-20 token
// Illustrative fungible uRWA implementation — not audited.
contract URWAToken is ERC20, AccessControl, IERC7943Fungible {
bytes32 public constant AGENT_ROLE = keccak256("AGENT_ROLE");
IEligibility public eligibility;
mapping(address => uint256) private _frozen;
function canSend(address a) public view returns (bool) { return eligibility.allowedToSend(a); }
function canReceive(address a) public view returns (bool) { return eligibility.allowedToReceive(a); }
function getFrozenTokens(address a) public view returns (uint256) { return _frozen[a]; }
function canTransfer(address from, address to, uint256 amt) public view returns (bool) {
if (!canSend(from) || !canReceive(to)) return false;
return balanceOf(from) >= _frozen[from] + amt; // only unfrozen balance is transferable
}
function setFrozenTokens(address a, uint256 amt) external onlyRole(AGENT_ROLE) returns (bool) {
_frozen[a] = amt; emit Frozen(a, amt); return true;
}
function forcedTransfer(address from, address to, uint256 amt) external onlyRole(AGENT_ROLE) returns (bool) {
require(canReceive(to), "receiver not eligible");
// reduce frozen amount first if the forced transfer touches frozen tokens
uint256 free = balanceOf(from) - _frozen[from];
if (amt > free) { _frozen[from] -= (amt - free); emit Frozen(from, _frozen[from]); }
_bypass = true; _transfer(from, to, amt); _bypass = false;
emit ForcedTransfer(from, to, amt);
return true;
}
bool private _bypass;
function _update(address from, address to, uint256 amt) internal override {
if (!_bypass && from != address(0) && to != address(0)) require(canTransfer(from, to, amt), "uRWA: not allowed");
super._update(from, to, amt);
}
}
(Production implementations would use the custom errors defined by the standard and handle mint/burn eligibility explicitly.)
Why a minimal interface matters for the market
The RWA ecosystem has many token designs: ERC-3643 securities, ERC-1155 portfolios, ERC-721 titles, bespoke fund tokens. Venues, wallets, custodians and DeFi protocols cannot integrate each one bespoke. A shared minimal interface lets them:
- Pre-check transfers before submitting orders or settlement instructions.
- Display frozen balances accurately to investors.
- Recognise forced transfers in indexing and accounting.
- Detect support through ERC-165 and adapt automatically.
Migration path for existing tokens
- Add the ERC-7943 functions through an upgrade (if your token is upgradeable) or a wrapper.
- Map existing whitelist/compliance logic into
canSendandcanReceive. - Map existing freeze features into
setFrozenTokens/getFrozenTokens. - Emit the standard events for future actions.
- Advertise the interface ID and inform integrators.
Frequently asked questions
No. It is a minimal interface layered on an existing token standard. You still decide how eligibility is determined.
Yes. The multi-token variant is designed for ERC-1155 and ERC-6909, with freezing per token ID and amount.
It borrows ERC-3643’s naming for interoperability but stays framework-agnostic. A platform can use both.
It enforces the result of eligibility checks through canSend/canReceive. KYC itself happens off-chain with a regulated provider.
No. You may use whitelists, claims, verifiable credentials or any other mechanism behind canSend/canReceive.
It can express blacklist-style freezing and seizure in a standard way, but stablecoin regulation may impose additional requirements.
This article is for general information only and is not legal, tax or investment advice. Token standards evolve — always confirm the current status of an ERC at eips.ethereum.org and take advice from qualified counsel in each jurisdiction before issuing tokens.


