Standards

ERC7518 Dynamic Compliant Interop Security Token

A guide to ERC7518 security tokens supporting dynamic compliance, cross-protocol interoperability and regulated asset tokenization.

Last updated: 12/4/2025
Improve this page

ERC7518, also called DyCIST (Dynamic Compliant Interop Security Token), is a security-token standard built on top of ERC1155. It’s designed to handle compliant real-world asset (RWA) tokens in a flexible and efficient way. Each tokenId acts as a separate partition, representing a different class of assets with its own rights, privileges, and compliance rules. This setup makes it perfect for semi-fungible use cases like fractional ownership, multiple share classes, or separating investors under different regulatory regimes (for example, Reg D investors vs. Reg S investors).

The standard includes features that RWAs typically need, such as time-based lockups, forced transfers for recovery or legal actions, address freezing, efficient bulk payouts, and dynamic compliance using off-chain vouchers. All of this is layered on top of ERC1155’s multi-token architecture, keeping it gas-efficient and highly composable.

ERC7518 was created to solve gaps in earlier standards. ERC20 and ERC721 don’t support partitioning, so they can’t easily represent different compliance classes or investor groups. ERC3643 supports modular compliance but introduces extra overhead. ERC7518 strikes a balance by allowing dynamic allocation of tokens into the right partitions, temporary non-fungibility for segregated offerings, and granular compliance without splitting liquidity across many separate token contracts. Dedicated merge contracts can even recombine partitions once lockups expire.

The standard relies on ERC1155 and ERC165 for multi-token support and interface detection. It powers platforms like Zoniqx and Centrifuge for tokenized real estate, private equity, private credit, and bond offerings. In practice, teams often pair ERC7518 with ERC3643 for identity verification or ERC7943 for lightweight compliance enforcement, enabling interoperable RWA systems that can work smoothly across chains and protocols.

Use of ERC7518 in RWA Contexts

ERC7518 makes it possible to bake regulatory compliance directly into how RWA tokens behave. Because each tokenId acts as its own compliance partition, issuers can separate investor groups, enforce rules, automate yield payouts, and apply AML or KYC restrictions at a granular level. These partitions act like “compliance silos,” letting teams manage semi-fungible assets, such as fractionalized floors in a building or share classes, without deploying multiple contracts. This setup keeps costs down and improves liquidity since partitions can later be merged when restrictions expire.

Key Applications in RWA Development

Partitioned Tokenization Used for complex assets like commercial buildings, where each floor can be its own NFT-like partition and fractional shares within that floor are fungible. When investors buy in, tokens can be minted into the correct partition, such as Reg D for U.S. accredited investors or Reg S for non-U.S. buyers, based on compliance checks.

Vesting and Lockups Partitions can hold tokens during vesting schedules, holding periods, or regulatory lockups. Functions like unlockToken release assets automatically once the required time has passed. This is especially valuable for illiquid assets like infrastructure financing or private equity.

Compliance Enforcement Transfers can be validated through canTransfer, which uses off-chain vouchers (signed EIP-712 proofs) for KYC or accreditation. forceTransfer allows for key-recovery situations, court-ordered moves, or AML freezes, important for regulated products such as bonds or environmental credits.

Yield Distribution Using functions like batchPayout, issuers can distribute rental income, dividends, or interest payments across partitions on a pro-rata basis. This works well for real estate income, REIT structures, or NAV-based assets when paired with oracle data.

Developer Advantages in RWA Builds

  • Semi-Fungible Flexibility, letting a single contract handle both NFT-like partitions and fungible fractional units. This saves significant gas compared to deploying separate contracts and makes upgrades simpler.
  • Dynamic Compliance, since voucher-based rules can evolve off-chain without redeploying contracts. Partitions also remain intact when wrapped cross-chain.
  • Interoperability, thanks to ERC1155’s wide support across DEXs, vaults, and indexing tools. Events make it easy to build analytics and dashboards.
  • Scalability, with batch functions and efficient views that handle large, high-volume RWA flows such as supply-chain invoices or private credit pools.

The following sequence diagram depicts a compliant transfer in an RWA partition (e.g., Reg D shares), including lock checks, voucher validation, and enforcement. It highlights the dynamic compliance layer for regulated flows.

Dynamic Compliant.svg

Core Specification

ERC7518 tokens must build on ERC1155 and override safeTransferFrom so that every transfer passes through compliance checks. The standard adds functions that are aware of partitions, letting each tokenId enforce its own rules. Transfers revert whenever canTransfer returns false, and lock or freeze logic uses timestamps and flexible bytes data fields to handle different regulatory or business requirements. View functions are designed to be pure and non-reverting wherever possible.

Key definitions:

  • Partition: A tokenId that represents a semi-fungible class, such as a share type or investor group, each with its own rules and lockup conditions.
  • Transferable Balance: The portion of a user’s balance that can actually move, calculated as balanceOf(account, id) - lockedBalanceOf(account, id).
  • Locked Balance: The amount within a partition that is restricted by time or other conditions.
  • Voucher Data: Arbitrary bytes used for off-chain proofs, such as signed EIP-712 compliance attestations.
  • Frozen Address: An account blocked from sending or receiving tokens or payouts, optionally with metadata describing the reason.
  • Force Transfer: An admin-level operation that bypasses normal rules for recovery or enforcement, with a dedicated event for transparency.

Tokens declare support for the standard using ERC165 with interface ID  0x01ffc9a7  for IERC7518.

The standard defines a single core interface extending ERC1155 and ERC165. Below is the full ABI-compliant code from the EIP.

1// SPDX-License-Identifier: CC0-1.0
2pragma solidity ^0.8.0;
3
4import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
5import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
6
7interface IERC7518 is IERC1155, IERC165 {
8    // Events
9    event TokensLocked(address indexed account, uint indexed id, uint256 amount, uint256 releaseTime);
10    event TokenUnlocked(address indexed account, uint indexed id);
11    event TokensForceTransferred(address indexed from, address indexed to, uint indexed id, uint256 amount);
12    event AddressFrozen(address indexed account, bytes data);
13    event AddressUnfrozen(address indexed account, bytes data);
14    event TransferRestricted(uint indexed id);
15    event TransferRestrictionRemoved(uint indexed id);
16    event PayoutDelivered(address indexed from, address indexed to, uint256 amount);
17
18    // Functions
19    function transferableBalance(address account, uint id) external view returns (uint);
20    function lockedBalanceOf(address account, uint256 id) external view returns (uint256);
21    function restrictTransfer(uint id) external returns (bool);
22    function removeRestriction(uint id) external returns (bool);
23    function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external returns (bool);
24    function canTransfer(address from, address to, uint id, uint amount, bytes calldata data) external view returns (bool status);
25    function lockTokens(address account, uint id, uint256 amount, uint256 releaseTime) external returns (bool);
26    function unlockToken(address account, uint256 id) external;
27    function forceTransfer(address from, address to, uint256 id, uint256 amount, bytes memory data) external returns (bool);
28    function freezeAddress(address account, bytes calldata data) external returns (bool);
29    function unFreeze(address account, bytes memory data) external returns (bool);
30    function payout(address calldata to, uint256 calldata amount) external returns (bool);
31    function batchPayout(address[] calldata to, uint256[] calldata amount) external returns (bool);
32}

Detailed Function Breakdown

transferableBalance(address account, uint id) external view returns (uint) Calculates how much of a user’s balance can actually be moved, using balanceOf(account, id) - lockedBalanceOf(account, id). In RWA systems, this is essential for front ends showing available balances in partitioned vaults and is ideal for gasless simulations since it is a pure view.

lockedBalanceOf(address account, uint256 id) external view returns (uint256) Returns the amount of tokens locked for a specific partition. For RWAs, this is commonly used to reflect vesting schedules or regulatory lockups and can be combined with timestamps to determine when tokens unlock automatically.

restrictTransfer(uint id) external returns (bool) Makes a partition non-transferable and emits a TransferRestricted event. This is useful in RWAs for enforcing holding periods in bond or equity tranches and is typically restricted to admin roles.

removeRestriction(uint id) external returns (bool) Removes a transfer restriction from a partition and emits TransferRestrictionRemoved. In RWAs, this is triggered once a lockup period ends to restore liquidity.

safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external Overrides ERC1155 to include compliance checks through canTransfer. It reverts on invalid addresses, insufficient transferable balance, or failed compliance. This is the main entry point for compliant peer to peer transfers, and the data field is often used for passing voucher proofs.

canTransfer(address from, address to, uint id, uint amount, bytes calldata data) external view returns (bool) Checks whether a transfer is allowed, validating unlocked balances, partition restrictions, and any external rules like KYC status. For RWAs, this is the main hook for dynamic regulation based on jurisdiction, investor eligibility, or holding caps.

lockTokens(address account, uint id, uint256 amount, uint256 releaseTime) external returns (bool) Locks a specified token amount until releaseTime and emits TokensLocked. In RWAs, this is commonly used for vesting cliffs, private equity lockups, or mandatory holding periods.

unlockToken(address account, uint256 id) external Releases tokens whose lock period has expired and emits TokenUnlocked. It can also be batch-called to unlock many accounts at once, which is helpful for large RWA distributions.

forceTransfer(address from, address to, uint256 id, uint256 amount, bytes memory data) external returns (bool) Allows an admin to transfer tokens even when restrictions apply, especially when the sender is frozen. This emits a TokensForceTransferred event. In RWA environments, this is used for AML related recoveries or legal enforcement and should always require strong multisig authorization.

freezeAddress(address account, bytes calldata data) external returns (bool) Freezes an account so it cannot transfer or receive tokens or payouts, and emits AddressFrozen. For RWAs, this is used for regulatory holds, suspicious activity reviews, or compliance investigations, with the data field providing context for auditors.

unFreeze(address account, bytes memory data) external returns (bool) Removes a freeze on an address and emits AddressUnfrozen. In RWAs, this is used after a compliance review or dispute has been resolved.

payout(address to, uint256 amount) external returns (bool) Sends a single payout, provided the receiver is not frozen and the issuer has enough balance. Emits PayoutDelivered. This is useful for dividends, rental distributions, or interest payments.

batchPayout(address[] to, uint256[] amount) external returns (bool) Executes multiple payouts atomically, applying all compliance checks. In RWAs, this is ideal for distributing yields across large investor groups or multiple partitions efficiently.

Reference Implementation

The reference implementation is an audited Solidity suite at zoniqx/erc7518_reference. It extends OZ ERC1155 with TokenPartition structs, voucher verification (EIP-712), and RBAC via AccessControl.

Constructor and Setup

1import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
2import "@openzeppelin/contracts/access/AccessControl.sol";
3import "./IERC7518.sol";
4
5contract DyCIST is ERC1155, AccessControl, IERC7518 {
6    struct TokenPartition {
7        string name;
8        bytes32 complianceRules;  // Hashed rules/voucher schema
9        uint256 lockPeriod;
10        bool transferRestricted;
11        mapping(address => uint256) lockedBalances;
12        uint256 releaseTime;
13    }
14    mapping(uint256 => TokenPartition) public partitions;
15
16    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
17    mapping(address => bool) public frozen;
18
19    constructor(string memory uri) ERC1155(uri) {
20        _grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
21    }
22
23    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC1155, IERC165, AccessControl) returns (bool) {
24        return super.supportsInterface(interfaceId) || interfaceId == type(IERC7518).interfaceId;
25    }
26}

This setup initializes metadata through the ERC1155 URI, defines partition structures, and grants admin and minter roles through AccessControl. In real RWA integrations, issuers typically add more granular roles for compliance officers or oracle managers.

Key Functions

canTransfer

1function canTransfer(address from, address to, uint id, uint amount, bytes calldata data) external view override returns (bool status) {
2    if (frozen[from] || frozen[to] || partitions[id].transferRestricted) return false;
3    uint256 transferable = balanceOf(from, id) - partitions[id].lockedBalances[from];
4    if (amount > transferable) return false;
5    // Verify EIP-712 voucher in data
6    (bool valid,) = _verifyVoucher(data, partitions[id].complianceRules);
7    return valid && kycRegistry.isVerified(to);  // External KYC
8}

This function enforces all compliance rules before any movement of tokens. It checks freezes, partition-level restrictions, locked balances, and voucher-based eligibility. In RWA contexts, this is commonly extended with oracle-backed KYC or dynamic whitelist logic.

safeTransferFrom

1function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) public override(ERC1155, IERC7518) {
2    require(canTransfer(from, to, id, amount, data), "Compliance failed");
3    super.safeTransferFrom(from, to, id, amount, data);
4}

By overriding ERC1155’s transfer handler, every transfer automatically passes through compliance checks. For RWAs, additional partition-specific data or proofs can be included in the data field.

lockTokens

1function lockTokens(address account, uint id, uint256 amount, uint256 releaseTime) external override onlyRole(MINTER_ROLE) returns (bool) {
2    require(balanceOf(account, id) >= amount, "Insufficient balance");
3    partitions[id].lockedBalances[account] += amount;
4    partitions[id].releaseTime = releaseTime;
5    emit TokensLocked(account, id, amount, releaseTime);
6    return true;
7}

This function handles vesting or regulatory lockups by restricting balances until a given timestamp. In RWA systems, it's often batch-executed for large investor groups or to enforce mandatory holding periods.

forceTransfer

1function forceTransfer(address from, address to, uint256 id, uint256 amount, bytes memory data) external override onlyRole(DEFAULT_ADMIN_ROLE) returns (bool) {
2    require(frozen[from], "Not frozen");  // Or other auth
3    safeTransferFrom(from, to, id, amount, data);  // Reuse hooks if partial
4    emit TokensForceTransferred(from, to, id, amount);
5    return true;
6}

This privileged operation allows transfers in situations where compliance or recovery procedures require it, such as AML freezes or account recovery cases. In practice, these actions are secured behind multisigs and often tied to off-chain legal processes.

Security Considerations

ERC7518 introduces powerful features like partitions, vouchers, and admin controls, but these also expand the attack surface. Around a third of bugs tend to appear in transfer hooks or voucher logic. Public discussions also highlight risks tied to oracle dependencies and broad admin authority.

Voucher and Oracle Manipulation

Signed vouchers can be exploited through replay attacks, forged signatures, or corrupted oracle feeds.

Mitigation includes using EIP-712 with nonces and expiry fields, relying on multiple oracles for consensus, and securing signing keys in HSMs. For RWAs, voucher formats and schemas should be carefully audited to prevent bypasses.

Admin Abuse Through forceTransfer or freezeAddress

Since admins can freeze accounts or move tokens, compromised or malicious roles can drain or lock real-world assets.

Mitigation includes strict role-based access control, multisig or timelock protection, and real-time event monitoring. In RWA deployments, governance via a DAO or committee helps distribute authority.

Lock or Partition Misconfigurations

Errors in lock periods, release times, or partition merges can unintentionally dilute holdings or block valid transfers.

Mitigation includes validating all inputs, enforcing invariants such as "total locked <= total supply", and fuzz-testing edge cases to catch unexpected behavior.

Cross-Chain Replay Attacks

Cross-chain wrappers may accidentally reuse the same vouchers or token states, creating duplicated partitions or unauthorized mints.

Mitigation includes adding nonces to bridge messages, using burn and mint flows with proof verification, and logging cross-chain state transitions for auditability.

ERC7765 Privileged Non-Fungible Tokens Tied To RWA
ERC4907 Rental NFT, an Extension of EIP-721

WE SECURE EVERYTHING YOU BUILD.

From day-zero risk mapping to exchange-ready audits — QuillAudits helps projects grow with confidence. Smart contracts, dApps, infrastructure, compliance — secured end-to-end.

DeFi SecurityplumeUniswap FoundationAethiropt-collectivePolygon SPNBNB Chain Kickstart

Office 104/105 Level 1, Emaar Square, Building 4 Sheikh Mohammed Bin Rashid Boulevard Downtown Dubai, United Arab Emirates P.O box: 416654

[email protected]

All Rights Reserved. © 2026. QuillAudits - LLC

Privacy Policy