This EIP proposes the Universal RWA (uRWA) standard, a set of interfaces for tokenized Real World Assets (RWAs) such as securities, real estate, commodities, or other physical/financial assets on the blockchain.
Real World Assets often require regulatory compliance features not found in standard tokens, including the ability to freeze assets, perform enforcement transfers for legal compliance, and restrict transfers to authorized users. The uRWA standard extends common token standards like ERC-20, ERC-721, or ERC-1155 by introducing essential compliance functions while remaining minimal and not opinionated about specific implementation details.
This enables DeFi protocols and applications to interact with tokenized real-world assets in a standardized way, knowing they can check transfer permissions, whether users are allowed to interact, handle frozen assets appropriately, and integrate with compliant RWA tokens regardless of the underlying asset type or internal compliance logic. It also adopts ERC-165 for introspection.
Real World Assets (RWAs) represent a significant opportunity to bridge traditional finance and decentralized finance (DeFi). By tokenizing assets like real estate, corporate bonds, commodities, art, or securities, we can unlock benefits such as fractional ownership, programmable compliance, enhanced liquidity through secondary markets for traditionally illiquid assets, and integration with decentralized protocols.
However, tokenizing real world assets introduces regulatory requirements often absent in purely digital assets, such as allowlists for users, transfer restrictions, asset freezing, or law enforcement rules. Existing token standards like ERC-20, ERC-721, and ERC-1155 lack the inherent structure to address these compliance needs directly within the standard itself.
Attempts at defining universal RWA standards historically imposed unnecessary complexity and gas overhead for simpler use cases that do not require the full spectrum of features like granular role-based access control, mandatory on-chain whitelisting, specific on-chain identity solutions, or metadata handling solutions mandated by the standard.
Additionally, the broad spectrum of RWA classes inherently suggests the need to move away from a one-size-fits-all solution. This means a minimalistic approach, an unopinionated features list, and maximal compatibility have been kept in mind as design goals.
The uRWA standard seeks a more refined balance by defining an essential interface, establishing a common ground for interaction regarding compliance and control, without dictating the underlying implementation mechanisms. This allows core token implementations to remain lean while providing standard functions for RWA-specific interactions.
The final goal is to build composable DeFi around RWAs, providing the same interface when dealing with compliance and regulation.
The key words "MUST", "MUST NOT", "REQUIRED", "SHOULD", and "MAY" in this document are to be interpreted as described in RFC 2119 and RFC 8174.
The following defines the standard interfaces for an ERC-7943 token contract, which MUST extend from one base token interface such as ERC-20, ERC-721, ERC-1155, or ERC-6909. Note that ERC-6909-based implementations can use the multi token interface:
/// @notice Interface for ERC-20 based implementations.
interface IERC7943Fungible is IERC165 {
/// @notice Emitted when tokens are taken from one address and transferred to another.
/// @param from The address from which tokens were taken.
/// @param to The address to which seized tokens were transferred.
/// @param amount The amount seized.
event ForcedTransfer(address indexed from, address indexed to, uint256 amount);
/// @notice Emitted when `setFrozenTokens` is called, changing the frozen `amount` of tokens for `account`.
/// @param account The address of the account whose tokens are being frozen.
/// @param amount The amount of tokens frozen after the change.
event Frozen(address indexed account, uint256 amount);
/// @notice Error reverted when an account is not allowed to send tokens.
/// @param account The address of the account which is not allowed to send.
error ERC7943CannotSend(address account);
/// @notice Error reverted when an account is not allowed to receive tokens.
/// @param account The address of the account which is not allowed to receive.
error ERC7943CannotReceive(address account);
/// @notice Error reverted when a transfer is not allowed according to internal rules.
/// @param from The address from which tokens are being sent.
/// @param to The address to which tokens are being sent.
/// @param amount The amount sent.
error ERC7943CannotTransfer(address from, address to, uint256 amount);
/// @notice Error reverted when a transfer is attempted from `account` with an `amount` less than or equal to its balance, but greater than its unfrozen balance.
/// @param account The address holding the tokens.
/// @param amount The amount being transferred.
/// @param unfrozen The amount of tokens that are unfrozen and available to transfer.
error ERC7943InsufficientUnfrozenBalance(address account, uint256 amount, uint256 unfrozen);
/// @notice Takes tokens from one address and transfers them to another.
/// @dev Requires specific authorization. Used for regulatory compliance or recovery scenarios.
/// @param from The address from which `amount` is taken.
/// @param to The address that receives `amount`.
/// @param amount The amount to force transfer.
/// @return result True if the transfer executed correctly. Reverts on failure.
function forcedTransfer(address from, address to, uint256 amount) external returns (bool result);
/// @notice Changes the frozen status of `amount` tokens belonging to `account`.
/// @dev Overwrites the current value, similar to an `approve` function.
/// Requires specific authorization. Frozen tokens cannot be transferred by the account.
/// @param account The address of the account whose tokens are to be frozen.
/// @param amount The amount of tokens to freeze. It can be greater than the account balance.
/// @return result True if the freezing executed correctly. Reverts on failure.
function setFrozenTokens(address account, uint256 amount) external returns (bool result);
/// @notice Checks if a specific account is allowed to send tokens according to token rules.
/// @dev This is often used for allowlist/KYC/KYB/AML checks.
/// @param account The address to check.
/// @return allowed True if the account is allowed to send, false otherwise.
function canSend(address account) external view returns (bool allowed);
/// @notice Checks if a specific account is allowed to receive tokens according to token rules.
/// @dev This is often used for allowlist/KYC/KYB/AML checks.
/// @param account The address to check.
/// @return allowed True if the account is allowed to receive, false otherwise.
function canReceive(address account) external view returns (bool allowed);
/// @notice Checks the frozen status/amount.
/// @param account The address of the account.
/// @dev It could return an amount higher than the account's balance.
/// @return amount The amount of tokens currently frozen for `account`.
function getFrozenTokens(address account) external view returns (uint256 amount);
/// @notice Checks if a transfer is currently possible according to token rules. It enforces validations on the frozen tokens.
/// @dev This can involve checks like allowlists, blocklists, transfer limits, and other policy-defined restrictions.
/// @param from The address sending tokens.
/// @param to The address receiving tokens.
/// @param amount The amount being transferred.
/// @return allowed True if the transfer is allowed, false otherwise.
function canTransfer(address from, address to, uint256 amount) external view returns (bool allowed);
}
/// @notice Interface for ERC-721 based implementations.
interface IERC7943NonFungible is IERC165 {
/// @notice Emitted when `tokenId` is taken from one address and transferred to another.
/// @param from The address from which `tokenId` is taken.
/// @param to The address to which seized `tokenId` is transferred.
/// @param tokenId The ID of the token being transferred.
event ForcedTransfer(address indexed from, address indexed to, uint256 indexed tokenId);
/// @notice Emitted when `setFrozenTokens` is called, changing the frozen status of `tokenId` for `account`.
/// @param account The address of the account whose `tokenId` is subjected to freeze/unfreeze.
/// @param tokenId The ID of the token subjected to freeze/unfreeze.
/// @param frozenStatus Whether `tokenId` has been frozen or unfrozen.
event Frozen(address indexed account, uint256 indexed tokenId, bool indexed frozenStatus);
/// @notice Error reverted when an account is not allowed to send tokens.
/// @param account The address of the account which is not allowed to send.
error ERC7943CannotSend(address account);
/// @notice Error reverted when an account is not allowed to receive tokens.
/// @param account The address of the account which is not allowed to receive.
error ERC7943CannotReceive(address account);
/// @notice Error reverted when a transfer is not allowed according to internal rules.
/// @param from The address from which tokens are being sent.
/// @param to The address to which tokens are being sent.
/// @param tokenId The ID of the token being sent.
error ERC7943CannotTransfer(address from, address to, uint256 tokenId);
/// @notice Error reverted when a transfer is attempted from `account` with a `tokenId` which has been previously frozen.
/// @param account The address holding the token with `tokenId`.
/// @param tokenId The ID of the token being frozen and unavailable to be transferred.
error ERC7943InsufficientUnfrozenBalance(address account, uint256 tokenId);
/// @notice Takes `tokenId` from one address and transfers it to another.
/// @dev Requires specific authorization. Used for regulatory compliance or recovery scenarios.
/// @param from The address from which `tokenId` is taken.
/// @param to The address that receives `tokenId`.
/// @param tokenId The ID of the token being transferred.
/// @return result True if the transfer executed correctly. Reverts on failure.
function forcedTransfer(address from, address to, uint256 tokenId) external returns (bool result);
/// @notice Changes the frozen status of `tokenId` belonging to an `account`.
/// @dev Overwrites the current value, similar to an `approve` function.
/// Requires specific authorization. Frozen tokens cannot be transferred by the account.
/// @param account The address of the account whose tokens are to be frozen.
/// @param tokenId The ID of the token to freeze.
/// @param frozenStatus Whether `tokenId` is being frozen or not.
/// @return result True if the freezing executed correctly. Reverts on failure.
function setFrozenTokens(address account, uint256 tokenId, bool frozenStatus) external returns (bool result);
/// @notice Checks if a specific account is allowed to send tokens according to token rules.
/// @dev This is often used for allowlist/KYC/KYB/AML checks.
/// @param account The address to check.
/// @return allowed True if the account is allowed to send, false otherwise.
function canSend(address account) external view returns (bool allowed);
/// @notice Checks if a specific account is allowed to receive tokens according to token rules.
/// @dev This is often used for allowlist/KYC/KYB/AML checks.
/// @param account The address to check.
/// @return allowed True if the account is allowed to receive, false otherwise.
function canReceive(address account) external view returns (bool allowed);
/// @notice Checks the frozen status of a specific `tokenId`.
/// @dev It could return true even if the account does not hold the token.
/// @param account The address of the account.
/// @param tokenId The ID of the token.
/// @return frozenStatus Whether `tokenId` is currently frozen for `account`.
function getFrozenTokens(address account, uint256 tokenId) external view returns (bool frozenStatus);
/// @notice Checks if a transfer is currently possible according to token rules. It enforces validations on the frozen tokens.
/// @dev This can involve checks like allowlists, blocklists, transfer limits, and other policy-defined restrictions.
/// @param from The address sending tokens.
/// @param to The address receiving tokens.
/// @param tokenId The ID of the token being transferred.
/// @return allowed True if the transfer is allowed, false otherwise.
function canTransfer(address from, address to, uint256 tokenId) external view returns (bool allowed);
}
/// @notice Interface for ERC-1155 based implementations.
interface IERC7943MultiToken is IERC165 {
/// @notice Emitted when tokens are taken from one address and transferred to another.
/// @param from The address from which tokens were taken.
/// @param to The address to which seized tokens were transferred.
/// @param tokenId The ID of the token being transferred.
/// @param amount The amount seized.
event ForcedTransfer(address indexed from, address indexed to, uint256 indexed tokenId, uint256 amount);
/// @notice Emitted when `setFrozenTokens` is called, changing the frozen `amount` of `tokenId` tokens for `account`.
/// @param account The address of the account whose tokens are being frozen.
/// @param tokenId The ID of the token being frozen.
/// @param amount The amount of tokens frozen after the change.
event Frozen(address indexed account, uint256 indexed tokenId, uint256 amount);
/// @notice Error reverted when an account is not allowed to send tokens.
/// @param account The address of the account which is not allowed to send.
error ERC7943CannotSend(address account);
/// @notice Error reverted when an account is not allowed to receive tokens.
/// @param account The address of the account which is not allowed to receive.
error ERC7943CannotReceive(address account);
/// @notice Error reverted when a transfer is not allowed according to internal rules.
/// @param from The address from which tokens are being sent.
/// @param to The address to which tokens are being sent.
/// @param tokenId The ID of the token being sent.
/// @param amount The amount sent.
error ERC7943CannotTransfer(address from, address to, uint256 tokenId, uint256 amount);
/// @notice Error reverted when a transfer is attempted from `account` with an `amount` of `tokenId` less than or equal to its balance, but greater than its unfrozen balance.
/// @param account The address holding the `amount` of `tokenId` tokens.
/// @param tokenId The ID of the token being transferred.
/// @param amount The amount of `tokenId` tokens being transferred.
/// @param unfrozen The amount of tokens that are unfrozen and available to transfer.
error ERC7943InsufficientUnfrozenBalance(address account, uint256 tokenId, uint256 amount, uint256 unfrozen);
/// @notice Takes tokens from one address and transfers them to another.
/// @dev Requires specific authorization. Used for regulatory compliance or recovery scenarios.
/// @param from The address from which `amount` is taken.
/// @param to The address that receives `amount`.
/// @param tokenId The ID of the token being transferred.
/// @param amount The amount to force transfer.
/// @return result True if the transfer executed correctly. Reverts on failure.
function forcedTransfer(address from, address to, uint256 tokenId, uint256 amount) external returns (bool result);
/// @notice Changes the frozen status of `amount` of `tokenId` tokens belonging to an `account`.
/// @dev Overwrites the current value, similar to an `approve` function.
/// Requires specific authorization. Frozen tokens cannot be transferred by the account.
/// @param account The address of the account whose tokens are to be frozen.
/// @param tokenId The ID of the token to freeze.
/// @param amount The amount of tokens to freeze. It can be greater than the account balance.
/// @return result True if the freezing executed correctly. Reverts on failure.
function setFrozenTokens(address account, uint256 tokenId, uint256 amount) external returns (bool result);
/// @notice Checks if a specific account is allowed to send tokens according to token rules.
/// @dev This is often used for allowlist/KYC/KYB/AML checks.
/// @param account The address to check.
/// @return allowed True if the account is allowed to send, false otherwise.
function canSend(address account) external view returns (bool allowed);
/// @notice Checks if a specific account is allowed to receive tokens according to token rules.
/// @dev This is often used for allowlist/KYC/KYB/AML checks.
/// @param account The address to check.
/// @return allowed True if the account is allowed to receive, false otherwise.
function canReceive(address account) external view returns (bool allowed);
/// @notice Checks the frozen status/amount of a specific `tokenId`.
/// @dev It could return an amount higher than the account's balance.
/// @param account The address of the account.
/// @param tokenId The ID of the token.
/// @return amount The amount of `tokenId` tokens currently frozen for `account`.
function getFrozenTokens(address account, uint256 tokenId) external view returns (uint256 amount);
/// @notice Checks if a transfer is currently possible according to token rules. It enforces validations on the frozen tokens.
/// @dev This can involve checks like allowlists, blocklists, transfer limits, and other policy-defined restrictions.
/// @param from The address sending tokens.
/// @param to The address receiving tokens.
/// @param tokenId The ID of the token being transferred.
/// @param amount The amount being transferred.
/// @return allowed True if the transfer is allowed, false otherwise.
function canTransfer(address from, address to, uint256 tokenId, uint256 amount) external view returns (bool allowed);
}
canSend, canReceive, canTransfer, and getFrozenTokensThese provide views into the implementing contract's compliance, transfer policy logic, and freezing status.
canSend and canReceive are account-level eligibility checks, independent of any specific transfer parameters (counterparty, amount, or token identifier). These functions:
msg.sender.canTransfer.canTransfer is a transfer-level authorization check that evaluates whether a specific transfer is permissible under permissioned compliance rules. This function:
msg.sender.amount being transferred doesn't exceed the unfrozen amount (which is the difference between the current balance and the frozen balance).canSend check on the from parameter and a canReceive check on the to parameter. Note that ERC-3643 does not perform this check within canTransfer as this standard requires.canSend/canReceive, or anything else that requires privileged actors.getFrozenTokens will return the absolute frozen amount, which MAY exceed the account's current balance. In ERC-721 tokens, it MAY return true even if the account does not hold the token.
forcedTransferThis function provides a standard mechanism for forcing a transfer from a from address to a to address. The function:
from to to either by transferring or burning from from and minting to to.ForcedTransfer event.canTransfer checks. If this happens, and the transfer involves tokens that are currently counted as frozen, it MUST unfreeze the assets first and emit a Frozen event before the underlying base token transfer event reflecting the change. Having the unfrozen amount changed before the actual transfer is critical for tokens that might be susceptible to reentrancy attacks doing external checks on recipients, as is the case for ERC-721 and ERC-1155 tokens.canReceive check on the to parameter to ensure compliance.canTransfer checks and SHOULD NOT bypass the frozen constraints.canReceive checks return false or fail.setFrozenTokensIt provides a way to freeze or unfreeze assets held by a specific account. This is useful for temporary lock mechanisms. This function:
Frozen event.The contract MUST implement the ERC-165 supportsInterface function and MUST return true for the bytes4 value (representing the interfaceId):
0x3edbb4c4 for the fungible interface.0xbf1ef5fe for the non-fungible interface.0x41c4fbad for the multi token interface.Implementations of these interfaces MUST implement the necessary functions of their chosen base standard (e.g., ERC-20 for the fungible interface, ERC-721 for the non-fungible interface, ERC-1155 or ERC-6909 for the multi token interface) and MUST also restrict access to sensitive functions like forcedTransfer and setFrozenTokens using an appropriate access control mechanism (e.g., onlyOwner, Role-Based Access Control). The specific mechanism is NOT mandated by this interface standard.
Implementations MUST ensure their transfer methods exhibit the following behavior:
transfer, transferFrom, safeTransferFrom, etc.) MUST NOT succeed in cases where canTransfer would return false, or where canSend would return false for the from address, or canReceive would return false for the to address.mint functions) MUST NOT succeed for accounts where canReceive on the recipient would return false. In permissioned contexts (e.g., authorized minting by privileged roles), minting SHOULD respect canReceive checks on the recipient, though implementations MAY bypass these checks when necessary for operational or compliance reasons.burn functions) MUST respect the canTransfer check, MUST respect the canSend check on the token holder, and MUST NOT allow burning more assets than the unfrozen amount. In permissioned contexts (e.g., authorized burning by privileged roles), burning MAY succeed for accounts where canSend on the token holder would return false, and MAY burn more assets than the unfrozen amount, in which case the contract MUST update the frozen status accordingly and emit a Frozen event before the underlying base token transfer event.The ERC7943CannotSend/ERC7943CannotReceive/ERC7943CannotTransfer errors MAY be used as a general revert mechanism whenever internal calls to canSend/canReceive/canTransfer return false. They MAY be replaced by more specific errors depending on the custom checks performed inside those calls, or simply not used.
In general, the standard prioritizes error specificity, meaning that specific errors such as ERC7943InsufficientUnfrozenBalance SHOULD be thrown when applicable. The ERC7943InsufficientUnfrozenBalance error SHOULD be triggered when a transfer is attempted from account with an amount less than or equal to its balance, but greater than its unfrozen balance, or with a tokenId which is currently frozen. If the amount is greater than the whole balance or the tokenId is not owned by the account, unrelated to the frozen amount, more specific errors from the base standard SHOULD be used instead.
forcedTransfer, setFrozenTokens, canSend, canReceive, canTransfer, getFrozenTokens) and associated events/errors needed for common RWA compliance and control patterns, avoiding mandated complexity or opinionated features. The reason to introduce specific errors (ERC7943CannotSend, ERC7943CannotReceive, ERC7943CannotTransfer, and ERC7943InsufficientUnfrozenBalance) is to provide completeness with the introduced functionalities (canSend, canReceive, canTransfer, and getFrozenTokens). As dictated in the specifications, error specificity is prioritized, leaving space for implementations to accommodate more explicit errors. Regarding the events Frozen and ForcedTransfer, the reason for their existence is to signal uncommon transfers (like in forcedTransfer) but also to help off-chain indexers correctly keep track and account for asset seizures and freezing. As mentioned in the specifications, the order in which these events are emitted in relation to the base token contract events is important in practice and merits special attention.canSend, canReceive) from transfer-level authorization (canTransfer). canSend and canReceive evaluate whether an account is eligible to participate independently of any specific transfer parameters such as counterparty, amount, or token identifier. canTransfer evaluates whether a specific transfer is permissible under permissioned compliance rules, taking into account frozen balances, transfer limits, counterparty restrictions, and account eligibility. This separation provides clear semantics for integrators and avoids confusion between account eligibility and transfer-specific validation. It also enables one-way restrictions where an account may be blocked from receiving but still allowed to send, which is common in regulated environments.canSend, canReceive, canTransfer, getFrozenTokens) for compliance checks without dictating how those checks are implemented internally by the token contract. This allows diverse compliance strategies.forcedTransfer and setFrozenTokens as standard functions, acknowledging their importance for regulatory enforcement in the RWA space, distinct from standard transfers. Mandates access control for these sensitive functions. To maintain a lean EIP, a single setFrozenTokens function (which overwrites the frozen asset quantity) and one Frozen event were favored over distinct freeze/unfreeze functions and events.As an example, an AMM pool or a lending protocol can integrate with ERC-7943-based ERC-20 tokens by calling canSend, canReceive, or canTransfer to handle these assets in a compliant manner. Enforcement actions like forcedTransfer and setFrozenTokens can either be called by third-party entities or be integrated by external protocols to allow for automated and programmable compliance. Users can then expand these tokens with additional features to fit the specific needs of individual asset types, such as on-chain identity systems, historical balance tracking for dividend distributions, semi-fungibility with token metadata, and other custom functionalities.
While this ERC provides the necessary primitives for regulated assets, any additional feature can be added through extensions. A few examples:
1) If for any administrative function like setFrozenTokens it is necessary to attach a proof to the call, the contract can have a function that batches operations like:
contract TokenWithLegalProofs is IERC7943MultiToken {
...
function setFrozenTokensWithProof(address account, uint256 tokenId, uint256 amount, bytes calldata legalProof) external onlyOwner returns (bool result) {
/// do anything with `legalProof`
return setFrozenTokens(account, tokenId, amount);
}
}
2) Since the setFrozenTokens function overwrites the absolute frozen amount and given the fact that the standard allows for multiple privileged accounts, some race-conditions might happen. If that's the case, one can build an extension function that works with expected values of amounts frozen, like:
function setFrozenTokensIf(address account, uint256 expectedPrev, uint256 newAmount) external onlyOwner returns (bool result) {
require(frozenTokens[account] == expectedPrev, ERC7943ExpectedValueMismatch(expectedPrev, frozenTokens[account]));
return setFrozenTokens(account, newAmount);
}
Alternatively, another solution can be using delta amounts:
function setFrozenTokensDelta(address account, int256 deltaAmount) external onlyOwner returns (bool result) {
uint256 actualValue = frozenTokens[account];
if(deltaAmount >= 0) actualValue += uint256(deltaAmount);
else {
uint256 sub = uint256(-deltaAmount);
require(sub <= actualValue, ERC7943ExpectedValueMismatch(sub, actualValue));
actualValue -= sub;
}
return setFrozenTokens(account, actualValue);
}
Note: These helpers reduce accidental overwrites and expand in functionalities but do not prevent same-block conflicting updates or mempool ordering races by different privileged actors.
3) Developers can also perform several operations through the use of multicall patterns similar to the one defined in ERC-6357 so that a mix of the given primitives with additional features can be batched in one transaction:
contract ERC7943Fungible is IERC7943Fungible, Multicall {
// Now any combination of `setFrozenTokens`/`forcedTransfer`
// coupled with other functionalities like the ones to blacklist/whitelist users
// can be submitted in one transaction through the use of `multicall` function
}
4) Functionalities like pausability can be added on top, either through the use of modifiers or directly within functions implementations:
function canTransfer(address from, address to, uint256 amount) external view returns (bool allowed) {
if(paused()) return allowed;
// ... other checks
}
The naming conventions in this ERC were carefully chosen to establish clarity and semantic consistency within the broader RWA ecosystem while maintaining neutrality and broad applicability.
forcedTransfer: This term was selected for its neutrality. While names like confiscation, revocation, or recovery describe specific motivations, forcedTransfer purely denotes the direct action of transferring assets, irrespective of the underlying reason. forcedTransfer was preferred over forceTransfer to maintain backward compatibility with ERC-3643.canSend / canReceive: These names were chosen to clearly express the directional nature of account eligibility: whether an account is allowed to send or receive tokens. This separation enables one-way restrictions (e.g., an account blocked from receiving but still allowed to send), which are common in regulated environments such as KYC expiry, AML alerts, or jurisdictional constraints.canTransfer: This name was preferred over isTransferAllowed for consistency with established RWA standards including ERC-3643 and ERC-7518. This alignment promotes interoperability and reduces cognitive overhead when working across different RWA tokens.setFrozenTokens / getFrozenTokens: These names were chosen for managing transfer restrictions and align with ERC-3643 naming patterns. Frozen was also selected for its general applicability to both fungible (amount-based) and non-fungible (status-based) assets, as terms like amount or asset(s) might not be universally fitting.ERC7943InsufficientUnfrozenBalance: Discussions around insufficient being similar to unavailable arose, where unavailable might have better suggested a temporal condition like a freezing status. However, the term available/unavailable was also overlapping with frozen/unfrozen creating more confusion and duality. Finally, coupling insufficient with the specified unfrozen balance better represents the domain, prefix, and subject of the error, according to ERC-6093 guidelines.This EIP defines a new interface standard and does not alter existing ones like ERC-20, ERC-721, and ERC-1155. Standard wallets and explorers can interact with the base token functionality of implementing contracts, subject to the rules enforced by that contract's implementation of canSend, canReceive, canTransfer, and getFrozenTokens functions. Full support for the ERC-7943 functions requires explicit integration.
Reference implementations of uRWA for ERC-20, ERC-721, and ERC-1155 token implementations are provided in the assets folder. They use the OpenZeppelin library and include separate send/receive whitelists and enumerable role-based access control. These examples are provided for educational purposes only and are not audited.
forcedTransfer and setFrozenTokens: The security of the mechanism chosen by the implementer to restrict access to these functions is paramount. Unauthorized access could lead to asset theft. Secure patterns (multisig, timelocks) are highly recommended.forcedTransfer and setFrozenTokens functions: Both functions are susceptible to front-running, similar to the approve function of ERC-20. Furthermore, if the suggestion to allow freezing more than what an account owns is not followed, any account may be incentivized to front-run attempts to freeze its balance when receiving new funds. Additional features to gradually increment or decrement the frozen status MAY be considered for implementation.Copyright and related rights waived via CC0.