ERC-1400 is a proposed standard dated from 2018 and originally proposed by Polymath.
Its objective is to represent securities on Ethereum and EVM blockchains and allow tokenizing financial assets. To achieve this, it adds several functionalities over the ERC-20 standard related to the management of securities.
It is important to note that this standard never reached the final stage as an ERC, contrary to ERC-3643, and is still considered a proposal. Its specifications are available on GitHub.
Details
ERC-1400 contains four other ERC proposals: ERC-1410, ERC-1594, ERC-1643, and ERC-1644.
These proposals define how to transfer tokens and introduce additional features, such as the management of documents for ERC-1644. The main features include:
-
Represent partially-fungible tokens (ERC-1410).
Every ERC1400 token can be partitioned. The partition of a token represents its state and can be used to represent different classes of assets, performing corporate actions, etc.
-
In terms of interoperability, it is compatible with ERC-20 since it also implements its interface.
-
Standard interface to query if a transfer would be successful and return a reason for failure (ERC-1594).
-
Perform forced transfers for legal action or fund recovery (ERC-1644).
The data field can be used to supply any additional authorization or details associated with the transfer (e.g. signed data from an authorized entity required to perform the transfer)
-
Attach metadata to a subset of a token holder's balance, such as special shareholder rights or data for transfer restrictions.
-
Manage documents on-chain (ERC-1643).
In short, ERC1400 offers the following advantages:
-
By implementing the ERC-20 interface, it ensures compatibility with the entire ERC-20 ecosystem, including DApps, tools and crypto exchange.
-
It enables the representation of various asset classes, such as lock tokens and collateralized tokens.
-
Finally, by allowing data to be attached to transfers, it supports enhanced verification processes based on this filed, such as signature validation.
Implementation and setup
One of the available ERC-1400 implementations is UniversalToken written by Consensys, a reputable and well-known company in the blockchain industry. The implementation is also under Apache-2.0 license, a permissive license.
Another implementation is from Polymath, but we have decided not to use it, as the code is more complex, and the project has not appeared to be publicly maintained since 2019.
As a disclaimer, we used this implementation for our tests, without making any modifications. We have also not carried out an external security audit on smart contracts, and we guarantee neither the security nor the proper functioning of these contracts.
We have created a fork of this project, available on the Taurus GitHub, to compile it with Hardhat and the following configuration:
-
Solidity version: 0.8.7 (same version as the original project)
-
OpenZeppelin version: 4.7.3 (latest compatible OpenZeppelin version)
We tested our setup using our product Taurus-CAPITAL, a platform to deploy and manage smart contracts, as well as Taurus-PROTECT, for the custody part. We ran the test on an Ethereum testnet (Sepolia)
You can find comparison with other standard (CMTAT, ERC-3643, tokenF) in our articles:
-
Tokenization on Ethereum and EVM Blockchains: Which Smart Contract Should You Use?
-
Security Token Standards Compared: CMTAT vs ERC-1400 vs ERC-3643
Overview
Here is the UML diagram of the architecture made with solidity-visual-auditor.
-
Access Control
The access control is defined with several different roles.
The schemas were created using draw.io.
There is also a specific access control for each specific partition.
The default partitions are not concerned by this access control.
Proof of concept
Here is the list of the different actors and their address:
Actor |
Use |
Address |
---|---|---|
Controller / owner |
Control and own the token smart contract |
0xcc6dfa08b554716b59cb80a0cf1f2adbd27a7f0f |
Token holder A |
Original token holder |
0x776ef597cd2f87d5c2388c02b602434a3a3c6d53 |
Token holder B |
Use as a recipient to test transfer functions |
0x5950537bf855bf8b6246ba75da3540031910e83b |
Token holder C |
Use to test a force transfer |
0xa6a3c6ef2e780e7d41c7e86816cd8ea69694ab9a |
Deployment
Here is the parameter used for deployment:
Parameter |
Description |
Value |
Details |
---|---|---|---|
tokenName |
Name of the token |
ERC1400N |
- |
tokenSymbol |
Symbol of the token |
ERC1400S |
- |
tokenGranularity* |
Granularity of the token |
1 |
Token granularity can not be lower than 1. In practice, it often 1 |
initialControllers |
Array of initial controllers |
0xcc6dfa08b554716b59cb80a0cf1f2adbd27a7f0f |
Empowerment of controllers with the ability to send tokens on behalf of other addresses (e.g. force transfer). |
defaultPartitions |
Partitions chosen by default, when partition is not specified, for example for a classic ERC-20 transfer. |
First default partition (Issued in hex) Second default partition (locked in hex) 0x6c6f636b65640000000000000000000000000000000000000000000000000000 |
Can be later updated with the function setDefaultPartitions |
*Note that the granularity is a concept taken from ERC-777 which is an internal representation used to specify the minimum divisible unit of the token.
Typically, if you want to create a token which is not divisible, since decimals are set to 18 in UniversalToken, you must put a granularity of 18.
Currently (2025), the granularity is not really used in practice and if you don’t want decimals, you will set them at 0, directly in the smart contract code or at deployment.
You can find more details about ERC-777 and its granularity in this article, used as a reference: wealtech - Understanding ERC-777 token contracts.
See transaction on Etherscan Sepolia.
Issue tokens
To issue new tokens, there are two functions issue and issueByPartition.
Issue
Since this function doesn’t take a partition in argument, tokens will be minted to the first default partition.
We issue tokens to our first token holder A: 0x776ef597cd2f87d5c2388c02b602434a3a3c6d53.
Taurus-CAPITAL
See transaction on Sepolia Etherscan.
Balance check
We check the total balance of our token holder A by calling the ERC-20 function balanceOf and the balance of the default partition by calling the specific ERC-1400 function balanceOfByPartition.
Issue with partition
Newly partition
We will use now to a newly specific partition:
0x7265736572766564000000000000000000000000000000000000000000000000
Taurus-CAPITAL
See transaction on Etherscan Sepolia.
Check balance
We can check the difference balance.
The total ERC20 balance is now 90 since our token created for the new partition are added to the tokens related for the default partition (previous example).
ERC20 Total Supply
After our two issuances, the ERC20 total supply is also worth 90.
-
50 tokens in the first default partition
-
40 tokens in our newly partition: 0x7265736572766564000000000000000000000000000000000000000000000000
Taurus-CAPITAL Second default partition
When we use the standard ERC-20 transfer, the issued tokens will be contained inside the first default partition.
If we want to issue tokens to our second default partition created at deployment, we have to use the function issueByPartition.
Taurus-CAPITAL
See transaction on Sepolia Etherscan.
Total Partition
Each partition, including default partitions, which have more than 0 tokens associated, is included in the list of total partition.
If all the tokens are burned with one of the functions redeem, then the partition will be removed from the list.
Transfer
Transfer by partition
Transfer by Partition
See transaction on Sepolia Etherscan.
Code:
ERC20 Transfer
In the case of an ERC-20 transfer, the function will go through all the different default participations and will transfer tokens from each participation until the value is reached:
See transaction on Sepolia Etherscan,
Balance:
Total balance is 105 (Issuance) - 10 (first transfer) - 45 (second transfer) = 50
Our first token holder has now zero in the balance of its partition. It initially had 50 tokens, but we have transferred 55 tokens with our 2 transfers.
The balance of its second partition has decreased by 5 from 15 to 10 because 5 tokens were missing in the first partition to complete the transfer.
Transferred more that owned
We will try now to perform a transfer with more tokens that are owned by our token holder C.
Taurus-CAPITAL
In this case, the smart contract will revert with the string error 52 and Taurus-CAPITAL will directly show an error message to avoid sending the transactions on the blockchain and lose gas fees. Typically, we will have the following error message (see picture).
Inside the smart contract, 52 is the error code to indicate that the balance is not sufficient to perform the transfer. This is defined in the ERC-1400 specification.
Taurus-CAPITAL
Force transfer
ERC-777 token contracts introduce the concept of operators. An operator is a third party that can act on behalf of a token holder, specifically with the ability to move tokens from the holder’s address. The concept was taken up by the ERC-1400 which, in addition to the concept of operator, introduces that of controller.
A controller is the default operator for all default partitions.
A new controller can only be set by the contract owner, defined at deployment
Force transfer by Partitions
operatorTransferByPartition
If the token is controllable (isControllable returns TRUE) then the controller may use operatorTransferByPartition to perform a force transfer without being explicitly authorised by the token holder.
Check balance
Before performing our test, we check the balance of our token holder A for our target partition.
Perform the transfer
We will try now to perform a force transfer of the tokens held by our token holder A to our token holder C.
Taurus-CAPITAL
Unfortunately, the smart contract rejects the transaction and Taurus-CAPITAL shows a message in the GUI.
Note the transaction is not broadcasted to the blockchain to avoid paying gas fees.
Taurus-CAPITAL
So why we have an error?
Our sender address is a controller and also the owner of the contract.
But when you want to perform a force transfer by specifying the partition, you must be a controller of this partition.
Since we are also the owner of this contract, we can call the function setPartitionControllersto set our address (0xcc6dfa08b554716b59cb80a0cf1f2adbd27a7f0f) as the controller of this partition.
We can now try again, and it works!
ForceTransfer with ERC20 TransferFrom
Transfer tokens from one address to another.
If the sender is a sender operator or a controller, he can transfer tokens on behalf of the token holder without allowance.
Since our account is a controller, we can perform a transfer without the allowance:
Check balance
Token Holder A
Token Holder C
Performing the transfer
Taurus-CAPITAL
See transaction on Etherscan Sepolia.
New Balance
Token Holder A: 40 -10 = 30
Token Holder C: 10 + 10 = 20
Redeem (Burn)
Redeem its own tokens
A token holder can redeem (burn) its own tokens.
We will burn 5 tokens from the main partition with the wallet of our token holder C.
Balance check
Function call
Taurus-CAPITAL
Balance check
Our token holder has now 50 - 5 = 45 tokens
Force Burn
operatorRedeemByPartition
Since the token is controllable (isControllable returns TRUE), the controller can burn tokens through operatorRedeemByPartition or redeemFrom being explicitly authorised by the token holder.
We will burn tokens held by our token holder A in our third partition, a non-default partition: 0x7265736572766564000000000000000000000000000000000000000000000000.
Balance check
Our token holder has now 45-5 = 40 tokens.
Additional points
Compatibility with other ERC
ERC20 compatibility
The ERC-1400 specification indicates that an ERC-1400 implementation must be ERC-20 compatible.
Function |
UniversalToken implementation |
---|---|
decimals |
Set at 18 by default |
balanceOf |
Implemented Return the smallest part of the token that is not divisible. |
totalSupply |
Number of tokens for each partition |
transfer |
Transfer tokens from the default partitions |
transferfrom |
Transfer tokens from one address to another. If the sender is an operator, he can transfer tokens on behalf of the token holder without allowance. |
ERC-777 compatibility
The ERC-1400 specification indicates that an ERC-1400 implementation could be ERC-777 compatible.
The implementation by Consensys does not implement all functionalities from ERC-777 but share similar functionalities through ERC-1400.
Note that ERC-777 is an old standard, it is little used in 2025. OpenZeppelin has also deprecated their implementation of the standard since their version v.5.0.0 in 2023.
Function |
UniversalToken and ERC-1400 implementation |
---|---|
name, symbol, balanceOf, totalSupply |
See ERC-20 compatibility |
granularity |
Returns the total number of tokens hold by the token holder for each partitions |
defaultOperators |
Replaced by the function controllers |
isOperatorFor |
Replaced by isOperator and isOperatorForPartition |
authorizeOperator |
Same function |
revokeOperator |
Same function |
send |
Not implemented |
burn |
Replaced by redeem, redeemByPartition and redeemFrom in ERC-1400 |
operatorBurn |
Replaced by operatorRedeemByPartition in ERC-1400 |
The UniversalToken implementation itself is not compatible with the proxy architecture.
Instead, it implements a function migrate and use the standard ERC-1820 to indicate the address of the new contract.
Note that the function migrate doesn’t move tokens to the new contract but only updates the ERC-1820 registry.
Also, more modern standard implementations (ERC-3643/T-REX, CMTAT) tend to only use the proxy architecture as defined in the ERC-1967.
Document Management (ERC-1643)
Using ERC-1643, ERC-1400 allows you to manage documents on-chain.
A document is identified by its name (bytes32) and contains the following information:
-
An URI
-
A hash
-
And finally, a timestamp to indicate the last modification
UniversalToken
Conclusion
ERC-1400 was one of the first tokenization standard proposed for EVM and Ethereum and it comes with a list of robust features: interoperability with ERC-20, defined error codes, partial fungibility, and the ability to attach data to each transfer.
With the Universal Token, Consensys has done a robust job in 2022 by releasing one of the most complete ERC-1400 implementations, with the one from Polymath.
The project, unfortunately, no longer seems to be actively maintained, and the industry has also moved toward other standards:
-
Polymath, the initiators of this standard, has progressively moved from ERC-1400 toward their own blockchain Polymesh.
-
ERC-3643 by Tokeny and the association with the same name (ERC3643 Association). This standard has been formalized as a final ERC in 2024, contrary to ERC-1400 which is still in the proposal state.
-
A new official standard, suitable also for tokenization, has also been formalized as a final ERC in 2024: ERC-1363. This standard was proposed by Vittorio Minacori and is notably used by Spiko for their tokenized money market funds (see their GitHub).
-
Another standard, proposed by Solv Finance and finalized as an ERC in 2022, allows to represent semi-fungible tokens: ERC-3525. This standard is compatible with the standard ERC-721 (NFT).
-
And finally, several actors, including Taurus, such as Daura, Obligate, or the project Guardian use the standard CMTAT. A blockchain agnostic framework to tokenize assets on the blockchain, with an implementation available for Ethereum and EVM in Solidity, but also for Tezos (SmartyPy and Ligo) and Aztec.