ERC-1450 RTA-Controlled Security Token
Final · Tokens · created 2018-09-25
A standard that records securities issued under US securities regulations (Reg CF, D, A) as tokens and allows only the Registered Transfer Agent (RTA) to execute transfers, issuance and burns.
Why it is needed
Turning securities such as stocks into blockchain tokens makes recording and transferring ownership easier, but a regular ERC-20 token can be sent freely by anyone, which conflicts with securities regulation. US securities regulation requires a Registered Transfer Agent (RTA) to have exclusive control over securities transfers. It also requires investor identity verification (KYC), anti-money laundering (AML), recovery of lost or stolen securities, forced transfers under court orders (divorce, inheritance, recovery of fraud losses and so on), and record keeping for regulatory examination. The existing ERC-20 has no such regulatory role, and other security token standards have not directly addressed the US RTA system. ERC-1450 fills this gap by making every token movement execute only through the RTA.
What to implement
function changeIssuer(address newIssuer) external;: Replaces the token issuer (owner). Only the RTA can call it, not the issuer, so tokens cannot be taken even if the issuer key is stolen.function setTransferAgent(address newTransferAgent) external;: Sets the transfer agent address. After the owner sets it once to an RTAProxy, it is locked, and from then on only the RTA can replace it through the proxy.function isTransferAgent(address account) external view returns (bool);: Checks whether the given address is the current RTA.function transfer(address to, uint256 amount) external override returns (bool);: Always reverts with the ERC1450TransferDisabled error. Direct transfers by holders are disabled.function approve(address spender, uint256 amount) external override returns (bool);: Always reverts with the ERC1450TransferDisabled error. Third-party approvals are also disabled.function transferFrom(address from, address to, uint256 amount) external override returns (bool);: Always reverts with the ERC1450TransferDisabled error. Actual transfers use transferFromRegulated, which carries regulation tracking.function transferFromRegulated(address from, address to, uint256 amount, uint16 regulationType, uint256 issuanceDate) external returns (bool);: Called only by the RTA. Transfers a specific batch of tokens between accounts, identified by regulation type and issuance date.function mint(address to, uint256 amount, uint16 regulationType, uint256 issuanceDate) external returns (bool);: Called only by the RTA. Creates new tokens while recording the issuance regulation type and the original issuance date.function burnFrom(address from, uint256 amount) external returns (bool);: Called only by the RTA. Burns tokens using a strategy chosen by the RTA (such as first in, first out).function processTransferRequest(uint256 requestId, bool approved) external;: The RTA approves or rejects a transfer request after a compliance review.function setBrokerStatus(address broker, bool isApproved) external;: The RTA registers a broker or revokes its registration after due diligence.function setAccountFrozen(address account, bool frozen) external;: The RTA freezes or unfreezes an account. A frozen account cannot send or receive tokens.function isSecurityToken() external pure returns (bool);: Always returns true for an ERC-1450 token. Wallets and exchanges use it to detect that a token has transfer restrictions.event IssuerChanged(address indexed previousIssuer, address indexed newIssuer);: Emitted when the issuer is replaced.event TransferAgentUpdated(address indexed previousAgent, address indexed newAgent);: Emitted when the transfer agent changes.
In depth
A restricted ERC-20 interface that blocks direct transfers
ERC-1450 extends ERC-20 but behaves differently. transfer, approve and transferFrom must always revert with the ERC1450TransferDisabled error, and allowance must always return 0. Actual value movement happens only through the RTA-only functions transferFromRegulated, mint and burnFrom. This keeps read functions such as balanceOf and totalSupply compatible with existing ERC-20 infrastructure while routing every token movement through a single regulated RTA. Errors follow the ERC-6093 standard error format for tooling compatibility.
Separation of three roles and the security design of changeIssuer
Roles are divided into three: issuer (Owner/Issuer), RTA, and token holder. The issuer creates and owns the securities but cannot control token transfers, and only the RTA has the authority to transfer, issue and burn. In particular, changeIssuer can be called only by the RTA, not by the issuer. This differs from OpenZeppelin Ownable, where the owner hands over ownership themselves, so even if the issuer's private key is stolen, an attacker cannot replace the RTA or steal tokens. setTransferAgent is for the issuer to set an RTAProxy once at the start, after which it is locked and only the RTA can replace itself through the proxy.
Tracking regulation type and issuance date per batch
Every issuance must specify a regulation type (regulationType, uint16) and the original issuance date (issuanceDate), and no security exists without a regulation. A TokensMinted event must be emitted for every mint and a TokensBurned event for every burn, so the full shareholder register (cap table) can be reconstructed from events alone. When tokenizing an existing security, issuanceDate is recorded as the time the investor originally bought it, and the RTA uses it to calculate the holding period. getHolderRegulations, getRegulationSupply and getDetailedBatchInfo let you query a holder's composition by batch and the total issuance by regulation, and batchMint, batchTransferFrom and batchBurnFrom handle bulk operations such as dividend distribution or redemption.
Transfer requests, fees and the broker system
A holder can request a transfer with requestTransferWithFee, but no value moves until the RTA approves and executes it. If msg.sender is not the holder, it must be a broker registered with setBrokerStatus, and the RTA approves a broker after an off-chain application, KYC and AML screening, and contract signing. The fee is paid in the fee token set by the RTA (getFeeToken), and is either flat or a percentage based on basis points. A request follows the state machine Requested, UnderReview, Approved, Rejected, Executed, Expired, and each requestId is executed only once. On rejection, a uint16 reason code (for example 1 for KYC failure, 13 for jurisdiction restriction, 14 for failing the accredited investor requirement) and whether the fee is refunded are recorded, and the implementation must clearly document its refund policy.
Lost wallet recovery and court-ordered transfers
The essential basis for recovery is controllerTransfer. The RTA verifies the investor's identity using existing off-chain KYC records, executes the transfer immediately, and must emit a ControllerTransfer event (compatible with ERC-1644). The same function is used for court orders such as divorce, inheritance and recovery of fraud losses. The optional structured recovery process uses initiateRecovery to submit supporting documents (name, URI and hash in the ERC-1643 style), and executes with executeRecovery after a time lock against disputes (for example 30 days) has passed. If evidence of fraud emerges or the original owner proves access, it is cancelled with cancelRecovery. Personal information is not stored on-chain directly, and only the document URI and hash are submitted. Separately, setAccountFrozen can freeze an account to block sending and receiving.
Interface detection and optional extensions
supportsInterface must return true for the ERC-165 ID (0x01ffc9a7) and the IERC1450 specific ID, and must return false for the ERC-20 ID (0x36372b07). The ABI is compatible with ERC-20, but because transfer always fails, the design is meant to keep wallets from wrongly assuming the behavior is compatible as well. isSecurityToken always returns true to signal a restricted token. Optional extensions include document management (setDocument and so on), a structured recovery process, KYC status lookup (isKYCVerified), gasless fee approval using EIP-2612 permit (requestTransferWithPermit), and off-chain pre-compliance checks based on EIP-3668 (CCIP-Read) (preCheckCompliance). The pre-check is for reference only and is not binding, and final authority always rests with the RTA. This standard has been finalized with Final status.