Standards

ERC1400 Security Token Standard

A clear guide to ERC1400 security tokens enabling compliance-led issuance, permissioned transfers and structured asset control.

Last updated: 12/13/2025
Improve this page

ERC1400, known as the Security Token Standard, provides a unified framework for issuing and managing regulated digital securities on Ethereum and EVM-compatible chains. Instead of acting as a single interface like ERC20, it brings together multiple sub-modules that collectively address compliance needs. These components include ERC1410 for partitioned balances (such as locked vs. unlocked shares), ERC1594 for issuance and redemption with pre-transfer validation, ERC1643 for document references tied to legal disclosures, and ERC1644 for authorized or court-mandated transfers. Together, they enable granular control over how regulated assets are moved, audited, and updated while retaining compatibility with ERC20 style operations and tooling.
 

The standard was introduced to address long-standing fragmentation in security token architectures, where custom implementations led to incompatible flows, expensive audits, and limited liquidity. ERC1400 provides a shared compliance language, including standardized error codes (EIP-1066) to clearly communicate why a transfer fails, whether due to accreditation, jurisdiction, lockups, or regulatory windows. Although not published as a formal EIP, it has become a widely adopted reference model, forming the base for security token platforms like Polymath and Securitize, which collectively support over a billion dollars in tokenized assets.
 

In real-world asset environments, ERC1400 functions as the regulatory backbone for compliant fractional ownership. It allows issuers to tokenize securities while enforcing KYC/AML requirements, lockup periods, eligibility checks, disclosure access, and forced regulatory transfers when required. When combined with vault frameworks like ERC4626 for yield distribution or identity layers such as ERC3643, it supports full-stack security tokenization: programmable transfers, transparent document records, and interoperability across DeFi venues without sacrificing legal enforceability.

Use of ERC1400 in RWA Contexts

ERC1400 brings compliance, disclosure, and regulatory enforcement directly into the token model, making it suited for assets that must behave like securities even when fractionalized on-chain. Through partitions, document references, and controllable transfers, it allows tokenized real estate, private credit, carbon securities, and other regulated RWAs to operate with the same transactional flexibility as ERC20 while still honoring legal and jurisdictional requirements.
 

Key Applications in RWA Development

Partitioned Fractional Ownership Using ERC1410, issuers can divide a single asset into partitions that represent different classes of claims, such as voting vs. non-voting units or senior vs. junior tranches. transferByPartition ensures that secondary trades follow the rules associated with that specific class, enabling compliant liquidity without duplicating contracts.
 

Validated Issuance and Redemption ERC1594 adds pre-transfer and pre-issue validation, returning standardized status messages when conditions fail (for example, accreditation checks or jurisdiction limits). For RWA deals, this means an STO or debt issuance can be run transparently, with off-chain verification or oracle feeds integrated into the approval workflow.
 

Embedded Documentation for Legal Clarity ERC1643 gives each security token the ability to link directly to appraisal records, offering memoranda, subscription documents, or audited financials through URI or hash references. When updates occur, holders receive on-chain notifications, supporting disclosure requirements in regulated markets.
 

Regulatory Intervention and Forced Transfers ERC1644 enables custodians or appointed controllers to execute transfers in situations that require legal enforcement, such as regulatory freezes, AML holdbacks, court-ordered seizures, or loss recovery events. This aligns digital securities with real-world compliance expectations while preserving audit trails.
 

Developer Advantages in RWA Builds

Configurable Compliance Stack Sub-standards can be composed based on product needs: for example, ERC1410 plus ERC1594 for tokenized bonds, or ERC1410 plus ERC1643 for disclosure-heavy private equity offerings. Clear error codes make UX more readable for investors and compliance desks.
 

Storage-Efficient Partitioning Partitions use bytes32 identifiers, reducing the need for multiple contract deployments and lowering gas overhead for large multi-class capital structures.
 

Smooth Integration with Existing DeFi and Wallet Infrastructure ERC1400 can behave like ERC20 for basic interactions, enabling wallet compatibility and indexer support while still retaining permission checks, controlled redemption, or partition logic on transfer.
 

Future-Proof Extensions Data fields and validation hooks allow injective off-chain proofs, ZK attestations, or oracle references for conditions like ongoing accreditation status, lockup expiration, or geographic restrictions.
 

The following sequence diagram illustrates a compliant transfer in an RWA security token, from validation to partition update with controller override. It highlights modular enforcement for regulated flows.

Token standard.svg

Core Specification

ERC1400 tokens must expose ERC20 interfaces for basic wallet and exchange compatibility, while layering in additional sub-standards for compliance, documentation, and controlled transfers. Each transfer can include a data payload used to carry proofs, accreditation details, or compliance attestations. Before execution, canTransfer validates the request and returns a (success, code, reason) tuple following EIP-1066 semantics, allowing systems to understand whether a transfer failed due to eligibility, jurisdiction, lockup status, or disclosure rules. Balances are organized into partitions identified by bytes32 keys, and forced actions such as administrative recalls or legal freezes are only permitted if the token explicitly flags itself as controllable via isControllable.
 

Key definitions

  • Partition A bytes32 identifier representing a distinct segment of the total supply, such as “Restricted,” “Locked,” “Accredited Only,” or “Freely Tradable.” Each partition can have independent rules, disclosures, and lockup timelines.
     
  • Status Code A single byte returning an EIP-1066-formatted result, for example 0x51 meaning “invalid request” or 0x52 meaning “unsupported operation.” These codes allow wallets, brokers, and custodians to show clear UX-level reasons for failed transfers.
     
  • Controller An authorized address allowed to perform forced transfers under ERC1644, typically representing a transfer agent, custodian, regulator, or court-appointed administrator.
     
  • Document A legally relevant reference stored under a bytes32 label containing a URI, hash, and timestamp. This may point to offering memoranda, audit reports, deeds, appraisals, or risk disclosures.
     
  • Data Injection Arbitrary bytes attached to transfers or issuance operations containing proofs such as KYC, AML attestations, accreditation signatures, or oracle-fed validation inputs.

ERC1400 composes four sub-standards. Below are the full ABI-compliant interfaces extracted from EIPs and implementations.
 

IERC1400 (Umbrella Interface)

1// From implementations (e.g., ndaxio/ERC1400)
2interface IERC1400 {
3    // Token Info
4    function name() external view returns (string);
5    function symbol() external view returns (string);
6    function totalSupply() external view returns (uint256);
7    function balanceOf(address owner) external view returns (uint256);
8    function granularity() external view returns (uint256);
9
10    // Operators
11    function controllers() external view returns (address[]);
12    function authorizeOperator(address operator) external;
13    function revokeOperator(address operator) external;
14    function isOperator(address operator, address tokenHolder) external view returns (bool);
15    event AuthorizedOperator(address indexed operator, address indexed tokenHolder);
16    event RevokedOperator(address indexed operator, address indexed tokenHolder);
17
18    // Transfers
19    function transferWithData(address to, uint256 value, bytes data) external;
20    function transferFromWithData(address from, address to, uint256 value, bytes data, bytes operatorData) external;
21
22    // Issuance/Redemption
23    function redeem(uint256 value, bytes data) external;
24    function redeemFrom(address from, uint256 value, bytes data, bytes operatorData) external;
25    event Issued(address indexed operator, address indexed to, uint256 value, bytes data, bytes operatorData);
26    event Redeemed(address indexed operator, address indexed from, uint256 value, bytes data, bytes operatorData);
27}

IERC1410 (Partially Fungible - Partitions)

1interface IERC1410 {
2    // Balances
3    function balanceOfByPartition(bytes32 partition, address tokenHolder) external view returns (uint256);
4    function partitionsOf(address tokenHolder) external view returns (bytes32[]);
5
6    // Transfers
7    function transferByPartition(bytes32 partition, address to, uint256 value, bytes data) external returns (bytes32);
8    function operatorTransferByPartition(bytes32 partition, address from, address to, uint256 value, bytes data, bytes operatorData) external returns (bytes32);
9    function canTransferByPartition(address from, address to, bytes32 partition, uint256 value, bytes data) external view returns (byte, bytes32, bytes32);
10
11    // Operators
12    function controllersByPartition(bytes32 partition) external view returns (address[]);
13    function authorizeOperatorByPartition(bytes32 partition, address operator) external;
14    function revokeOperatorByPartition(bytes32 partition, address operator) external;
15    function isOperatorForPartition(bytes32 partition, address operator, address tokenHolder) external view returns (bool);
16
17    // Issuance/Redemption
18    function issueByPartition(bytes32 partition, address tokenHolder, uint256 value, bytes data) external;
19    function redeemByPartition(bytes32 partition, uint256 value, bytes data) external;
20    function operatorRedeemByPartition(bytes32 partition, address tokenHolder, uint256 value, bytes operatorData) external;
21
22    event TransferByPartition(bytes32 indexed fromPartition, address operator, address indexed from, address indexed to, uint256 value, bytes data, bytes operatorData);
23    event ChangedPartition(bytes32 indexed fromPartition, bytes32 indexed toPartition, uint256 value);
24    event AuthorizedOperatorByPartition(bytes32 indexed partition, address indexed operator, address indexed tokenHolder);
25    event RevokedOperatorByPartition(bytes32 indexed partition, address indexed operator, address indexed tokenHolder);
26    event IssuedByPartition(bytes32 indexed partition, address indexed operator, address indexed to, uint256 value, bytes data, bytes operatorData);
27    event RedeemedByPartition(bytes32 indexed partition, address indexed operator, address indexed from, uint256 value, bytes data, bytes operatorData);
28}

IERC1594 (Core Security Token)

1interface IERC1594 is IERC20 {
2    // Transfers
3    function transferWithData(address to, uint256 value, bytes data) external;
4    function transferFromWithData(address from, address to, uint256 value, bytes data) external;
5
6    // Issuance
7    function isIssuable() external view returns (bool);
8    function issue(address tokenHolder, uint256 value, bytes data) external;
9
10    // Redemption
11    function redeem(uint256 value, bytes data) external;
12    function redeemFrom(address tokenHolder, uint256 value, bytes data) external;
13
14    // Validation
15    function canTransfer(address to, uint256 value, bytes data) external view returns (bool, byte, bytes32);
16    function canTransferFrom(address from, address to, uint256 value, bytes data) external view returns (bool, byte, bytes32);
17
18    event Issued(address indexed operator, address indexed to, uint256 value, bytes data);
19    event Redeemed(address indexed operator, address indexed from, uint256 value, bytes data);
20}

IERC1643 (Document Management)

1interface IERC1643 {
2    // Documents
3    function getDocument(bytes32 name) external view returns (string uri, bytes32 documentHash, uint256 timestamp);
4    function setDocument(bytes32 name, string uri, bytes32 documentHash) external;
5    function removeDocument(bytes32 name) external;
6    function getAllDocuments() external view returns (bytes32[] names);
7
8    event DocumentRemoved(bytes32 indexed name, string uri, bytes32 documentHash);
9    event DocumentUpdated(bytes32 indexed name, string uri, bytes32 documentHash);
10}

IERC1644 (Controller Operations)

1interface IERC1644 is IERC20 {
2    // Controllability
3    function isControllable() external view returns (bool);
4
5    // Controller Transfers
6    function controllerTransfer(address from, address to, uint256 value, bytes data, bytes operatorData) external;
7    function controllerRedeem(address tokenHolder, uint256 value, bytes data, bytes operatorData) external;
8
9    event ControllerTransfer(address controller, address indexed from, address indexed to, uint256 value, bytes data, bytes operatorData);
10    event ControllerRedemption(address controller, address indexed tokenHolder, uint256 value, bytes data, bytes operatorData);
11}

Detailed Function Breakdown

transferByPartition(bytes32 partition, address to, uint256 value, bytes data) external returns (bytes32) Executes a transfer from a specific partition and may return a different partition if the asset transitions between states. It emits TransferByPartition to signal movement. In real-world asset flows, this is commonly used when shares move from a restricted or lockup class into a freely tradable partition once compliance or vesting conditions are cleared.
 

canTransferByPartition(...) external view returns (byte status, bytes32 reason, bytes32 partition) Performs a compliance check without altering state and returns an EIP-1066 status byte alongside a reason code and the relevant partition. Front ends and trading desks use this to pre-validate transfers, particularly to confirm accreditation or jurisdiction checks before executing an RWA secondary trade.
 

issue(address tokenHolder, uint256 value, bytes data) external Creates new security tokens for the specified holder and emits Issued including any compliance data passed in. In RWA issuance workflows, this enables banks or transfer agents to mint regulated credit instruments to investors while embedding KYC, allocation records, or subscription details in data.
 

controllerTransfer(address from, address to, uint256 value, ...) external Allows a designated controller to perform a forced transfer and emits ControllerTransfer. For regulated real-world assets, this is activated during AML holds, court orders, executor authority events, or custodial corrections where tokens must move even without user consent.
 

setDocument(bytes32 name, string uri, bytes32 hash) external Links a document reference to the security and emits DocumentUpdated. For RWAs, this typically attaches property deeds, offering memoranda, valuation reports, audit files, or legal compliance disclosures so that investors and regulators can view authoritative documentation on-chain.

Reference Implementation

The reference implementation is at ndaxio/ERC1400, providing Solidity contracts for the full suite. It inherits OZ ERC20, adds partition mappings (mapping(bytes32 => mapping(address => uint256)) _balancesByPartition), and implements all sub-interfaces with Ownable for banks.

1import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
2import "./IERC1400.sol";
3
4contract SecurityToken is ERC20, IERC1400 {
5    mapping(bytes32 => mapping(address => uint256)) private _balancesByPartition;
6    // Document mapping: mapping(bytes32 => Document) documents;
7    address[] public controllers;
8
9    constructor(string memory name, string memory symbol) ERC20(name, symbol) {}
10}

This initializes the token with ERC20 compatibility and adds support for partition-based balances. Issuers typically define their initial partitions during deployment, for example creating a default “General” or “Restricted” class.

Key Functions

transferByPartition

1function transferByPartition(bytes32 partition, address to, uint256 value, bytes memory data) external override returns (bytes32) {
2    (byte status, bytes32 reason, bytes32 newPartition) = canTransferByPartition(partition, msg.sender, to, value, data);
3    require(status == 0x50, string(abi.encodePacked("Transfer failed: ", reason)));
4    _transferByPartition(partition, msg.sender, to, value);
5    emit TransferByPartition(partition, address(0), msg.sender, to, value, data, "");
6    return newPartition;
7}

This function routes a transfer through a specific partition and only proceeds if canTransferByPartition returns the success code 0x50. The action is logged through TransferByPartition, allowing downstream systems and dashboards to clearly track compliance-driven transfers. In RWA contexts, issuers often add oracle checks here to confirm things like accreditation status or lockup expiry before the move.
 

setDocument

1function setDocument(bytes32 name, string memory uri, bytes32 documentHash) external override onlyOwner {
2    documents[name] = Document({uri: uri, documentHash: documentHash, modified: block.timestamp});
3    emit DocumentUpdated(name, uri, documentHash);
4}

This attaches a legally relevant document to the token, such as a deed, prospectus, appraisal, or offering memorandum. The update event provides a clear audit trail, helping regulators, custodians, and investors confirm that the underlying information is current and unaltered.

Case Study

By Team Tokinvest

Why did you choose this standard?

We selected ERC-1404 because it provides a simple, familiar extension of the ERC-20 token standard while enabling the regulatory controls required for compliant RWA issuance. It allows us to enforce transfer restrictions and investor eligibility checks at the token level while remaining compatible with retail wallets such as MetaMask, providing a user-friendly, Web3-ready experience.

How do you apply it in practice?

On-chain flow: Our tokenisation platform generates the ERC-1404 smart contract during the asset listing process. Token creation and lifecycle management sit under our operational control to ensure compliance, and the automated settlement engine handles on-chain token delivery once a purchase is confirmed.

Off-chain flow:  Tokinvest currently operates as a primarily fiat-based broker-dealer, managing payment flows off-chain. Once funds are confirmed, tokens are automatically released to the buyer on-chain. Our roadmap includes enabling fully on-chain payment and settlement options to create a seamless end-to-end tokenisation flow.

Key lessons learned during implementation

  • We use tokens to support distribution across our partner network, where issuers and distributors may transfer inventory between one another. This highlighted the need for a common, interoperable token standard that works across different partners and blockchain environments.
  • ERC-1404 provided the fastest path to compatibility and ecosystem reach, but our broader objective is to evolve toward a multi-chain interoperable framework that supports the diverse blockchains used by our partners.

Security Considerations

ERC1400’s strength is its flexibility, but that same flexibility introduces configuration risk, especially around controllers, partitions, and injected data. In RWA environments, where tokens represent regulated financial claims, these flaws can escalate into legal or custodial failures rather than just smart-contract bugs.
 

Controller Compromise

If a controller wallet is exposed, controllerTransfer can be abused to move assets without holder consent. How to reduce risk: assign controllers through multisig, use timelocks for sensitive force actions, and disable controllability (isControllable = false) once governance stabilizes.
 

Partition Leakage

Incorrect validation in transferByPartition can allow tokens to move between partitions that should remain segregated, such as restricted vs. freely tradable units. How to reduce risk: enforce strict partition rules in canTransferByPartition, validate totals across partitions during testing, and run fuzzing specifically on cross-class movement.
 

Unsafe Data Payloads

Transfers that include arbitrary bytes for proof or KYC data can become an attack surface if they trigger external calls or parsing flaws. How to reduce risk: never execute external calls while parsing data, treat payloads as read-only proofs, and sanitize parsing in hooks to avoid reentrancy or malicious calldata execution.
 

Operator Authority Drift

Operators removed from one partition may still retain control in others if permissions are not consistently revoked. How to reduce risk: apply revocations per partition, monitor operator changes through emitted events, and include off-chain reconciliation checks to ensure revocations match operational intent.

ERC7208 On-Chain Data Containers
Solana Token-2022 Guide

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