Full token standrads for blockchain

November 25, 2022

Intro

I collected of all token related standards proposed for the Ethereum network. This list can be used as note to recap and used during architecturing of the blockchain software. This list can be used compile solutions based on standards, many of the standards proposed by Ethereum developers and community and already have been implemented in Solidity.

List of Ethereum Tokens Standards

ERC-20 : Standard Fungible Token (EIP-20)

Standard API for fungible tokens, including transfer and balance tracking functionalities.

ERC-223 : Protecting Users From Accidental Contract Transfers (ERC-223)

ERC20 token standard is leading to money losses for end users. The main problem is lack of possibility to handle incoming ERC20 transactions, that were performed via transfer function of ERC20 token. ERC-223 describes standard functions a token contract and contract working with specified token can implement to prevent accidentally sends of tokens to contracts and make token transactions behave like ether transactions.

ERC-667 : transferAndCall Token Standard (ERC-667)

transferAndCall behaves similarly to transfer(address,uint256,bytes), but allows implementers to gain the functionality without the risk of inadvertently locking up tokens in non-ERC223 compatible contracts. It is distinct from ERC223’s transfer(address,uint256,bytes) only in name, but this distinction allows for easy distinguishability between tokens that are ERC223 and tokens that are simply ERC20 + ERC667.

ERC-721 : Non-fungible Token Standard (EIP-721)

While fungible tokens can be divided, non-fungible tokens (NFTs) can not. NFTs can be owned and transacted by individuals as well as consigned to third party brokers/wallets/auctioneers (“operators”). NFTs can represent ownership over digital or physical assets.

ERC-777 : Operator Based Token Standard (ERC-777)

Instead of using uints for approving third parties to transfer tokens on the users behalf, ERC-777 proposes to use a boolean mapping between users and operators. This simplifies the language, the approval process and decreases gas cost. 777 also includes data passing functions.

ERC-809 : Renting Standard for Rival, Non-Fungible Tokens (ERC-809)

Rival good: a good is rival if its consumption by one individual prevents simultaneous consumption by other individuals. For example, driving a car is rival but watching the sunset is non-rival.

Non-Fungible good: a good is non-fungible if it is not interchangeable. For example, cars are non-fungible but Ether is fungible.

ERC-809 allows an owner to rent access to their rival NFTs using a standard set of commands, thus allowing users to view all past and current rental agreements from a single wallet interface.

ERC-827 : transferFromAndCall & approveAndCall (ERC-827)

Insecure, removed.

ERC-864 : NFTs Shared Ownership (ERC-864)

This proposal aims to enable shared ownership of NFTs natively in the NFT contract.

ERC-865 : TransferPreSigned (ERC-865)

This proposal describes one standard function a token contract can implement to allow a user to delegate transfer of tokens to a third party. The third party pays for the gas, and takes a fee in tokens.

ERC-874 : Weighted Non Fungible Tokens (ERC-874)

Not all NFTs are created equal. Nothing exists to distinguish one NFT from another. Weight allows a DAO or other external actors to recognize some value for unique asset holdings.

ERC-888 : MultiDimensional Token Standard (ERC-888)

Proposing a model for multidimensional tokenization, which utilizes identifiers to refer to balances & data.

ERC-918 : Minable Token Standard (EIP-918)

A specification for a standardized Mineable Token that uses a Proof of Work algorithm for distribution.

ERC-965 : sendByCheque (ERC-965)

This proposal aims to allow pre-signing messages that will permit third parties to execute a token transfer without the original sender needing to do an on-chain transaction in the first place. The sender would simply need to sign a message and the third party would call sendByCheque() with the signature.

ERC-981 : Partial Ownership Standard (ERC-981)

This proposal serves to describe a new Ethereum Interface for issuing tokens for asset owners who come to a marketplace with a finite quantity of their asset to trade, representing 100% ownership of that particular issue. They then choose to divide the asset into divisible units that increase fungibility of that asset.

ERC-994 : Delegated Non-Fungible Token Standard (ERC-994)

Delegated Non-Fungible Tokens (DNFTs) are a proposed extension of the ERC721 standard designed with the use case of Ethereum-based registration of land and physical property in mind. NFTs are arranged in a federated, tree-like format (similar to DNS) where NFTs can delegate and sub-contract NFTs within a certain geospace.

Unlike digital assets (like CryptoKitties) physical property requires more than just an accurate identification in a database- it also requires legal validity within the context of physical sovereignty. DNFT zones can established by land registry authorities as a root DNFT encompassing a wide area, and can delegate DNFTs as subdivisions of the root zone to existing property holders as a way to upgrade land registries.

ERC-995 : Pre and Post Transfer Calls (ERC-995)

This standard provides an augmented token transfer functionality besides legacy proven ERC20 functionality. It allows to execute calls on transfers and approvals both before and after tokens are transferred regardless if the receiving address is a contract or not.

ERC-998 : Composable Non-Fungible Token Standard (ERC-998)

A standard extension for any non-fungible token to own another non-fungible ERC-721 or standard fungible ERC-20 tokens. Transferring the token composition means transferring the entire hierarchy of items. For example, a cryptokitty may own a scratching post and a feeding dish; the dish may contain some amount of fungible “chow” tokens.

ERC-1067 : Upgradeable Token Contract Standard (ERC-1067)

The following proposal describes a more distributed token contract architecture that has a simple upgrade-ability protocol and allows to bring in new functions after being deployed.

ERC-1132 : Token Locking Capability Standard (ERC-1132)

This proposal provides basic functionality to time-lock tokens within a contract for multiple utilities without the need of transferring tokens. It also allows fetching token balances of locked and unlocked tokens (tokens available for transfer).

ERC-1155 : Multi-Tokens Standard (ERC-1155)

Contract that keep tracks of multiple token balances and ownership to improve batch transfer efficiency.

ERC-1178 : Multi-Class Token Standard (ERC-1178)

Standard interface for token contract with multiple token classes.

ERC-1190 : Non-Fungible Royalty Token Standard (ERC-1190)

A standard interface for non-fungible tokens that pay royalties for a digital asset to the original creator(s) and/or owner(s).

ERC-1203 : Multi-Class Token Standard (ERC-20 Extension) (ERC-1203)

Standard interface for token contract with multiple token classes that is also ERC-20 compatible.

ERC-1238 : Non-Transferrable Tokens AKA Badges (ERC-1238)

Non-transferable tokens that represent “badges”.

ERC-1400 : Security Token Standard (ERC-1400)

Represents a library of standards for security tokens on Ethereum.

In aggregate provides a suite of standard interfaces for issuing / redeeming security tokens, managing their ownership and transfer restrictions and providing transparency to token holders on how different subsets of their token balance behave with respect to transfer restrictions, rights and obligations.

Standards should be backwards compatible with ERC-20 and easily extended to be compatible with ERC-777.

Accelerate the issuance and management of securities on the Ethereum blockchain by specifying standard interfaces through which security tokens can be operated on and interrogated by all relevant parties.

Taken together, these security token standards provide document management, error signalling, gate keeper (operator) access control, off-chain data injection, issuance / redemption semantics and expose partially fungible subsets of a token holders balance.

Requirements Moving the issuance, trading and lifecycle events of a security onto a public ledger requires having a standard way of modelling securities, their ownership and their properties on-chain.

The following requirements have been compiled following discussions with parties across the Security Token ecosystem.

MUST have a standard interface to query if a transfer would be successful and return a reason for failure. MUST be able to perform forced transfer for legal action or fund recovery. MUST emit standard events for issuance and redemption. MUST be able to attach metadata to a subset of a token holder’s balance such as special shareholder rights or data for transfer restrictions. MUST be able to modify metadata at time of transfer based on off-chain data, on-chain data and the parameters of the transfer. MUST support querying and subscribing to updates on any relevant documentation for the security. MAY require signed data to be passed into a transfer transaction in order to validate it on-chain. SHOULD NOT restrict the range of asset classes across jurisdictions which can be represented. MUST be ERC-20 compatible. COULD be ERC-777 compatible.

Interface


/// @title IERC1400 Security Token Standard
/// @dev See https://github.com/SecurityTokenStandard/EIP-Spec

interface IERC1400 is IERC20 {

  // Document Management
  function getDocument(bytes32 _name) external view returns (string, bytes32);
  function setDocument(bytes32 _name, string _uri, bytes32 _documentHash) external;

  // Token Information
  function balanceOfByPartition(bytes32 _partition, address _tokenHolder) external view returns (uint256);
  function partitionsOf(address _tokenHolder) external view returns (bytes32[]);

  // Transfers
  function transferWithData(address _to, uint256 _value, bytes _data) external;
  function transferFromWithData(address _from, address _to, uint256 _value, bytes _data) external;

  // Partition Token Transfers
  function transferByPartition(bytes32 _partition, address _to, uint256 _value, bytes _data) external returns (bytes32);
  function operatorTransferByPartition(bytes32 _partition, address _from, address _to, uint256 _value, bytes _data, bytes _operatorData) external returns (bytes32);

  // Controller Operation
  function isControllable() external view returns (bool);
  function controllerTransfer(address _from, address _to, uint256 _value, bytes _data, bytes _operatorData) external;
  function controllerRedeem(address _tokenHolder, uint256 _value, bytes _data, bytes _operatorData) external;

  // Operator Management
  function authorizeOperator(address _operator) external;
  function revokeOperator(address _operator) external;
  function authorizeOperatorByPartition(bytes32 _partition, address _operator) external;
  function revokeOperatorByPartition(bytes32 _partition, address _operator) external;

  // Operator Information
  function isOperator(address _operator, address _tokenHolder) external view returns (bool);
  function isOperatorForPartition(bytes32 _partition, address _operator, address _tokenHolder) external view returns (bool);

  // Token Issuance
  function isIssuable() external view returns (bool);
  function issue(address _tokenHolder, uint256 _value, bytes _data) external;
  function issueByPartition(bytes32 _partition, address _tokenHolder, uint256 _value, bytes _data) external;

  // Token Redemption
  function redeem(uint256 _value, bytes _data) external;
  function redeemFrom(address _tokenHolder, uint256 _value, bytes _data) external;
  function redeemByPartition(bytes32 _partition, uint256 _value, bytes _data) external;
  function operatorRedeemByPartition(bytes32 _partition, address _tokenHolder, uint256 _value, bytes _operatorData) external;

  // Transfer Validity
  function canTransfer(address _to, uint256 _value, bytes _data) external view returns (byte, bytes32);
  function canTransferFrom(address _from, address _to, uint256 _value, bytes _data) external view returns (byte, bytes32);
  function canTransferByPartition(address _from, address _to, bytes32 _partition, uint256 _value, bytes _data) external view returns (byte, bytes32, bytes32);    

  // Controller Events
  event ControllerTransfer(
      address _controller,
      address indexed _from,
      address indexed _to,
      uint256 _value,
      bytes _data,
      bytes _operatorData
  );

  event ControllerRedemption(
      address _controller,
      address indexed _tokenHolder,
      uint256 _value,
      bytes _data,
      bytes _operatorData
  );

  // Document Events
  event Document(bytes32 indexed _name, string _uri, bytes32 _documentHash);

  // Transfer Events
  event TransferByPartition(
      bytes32 indexed _fromPartition,
      address _operator,
      address indexed _from,
      address indexed _to,
      uint256 _value,
      bytes _data,
      bytes _operatorData
  );

  event ChangedPartition(
      bytes32 indexed _fromPartition,
      bytes32 indexed _toPartition,
      uint256 _value
  );

  // Operator Events
  event AuthorizedOperator(address indexed _operator, address indexed _tokenHolder);
  event RevokedOperator(address indexed _operator, address indexed _tokenHolder);
  event AuthorizedOperatorByPartition(bytes32 indexed _partition, address indexed _operator, address indexed _tokenHolder);
  event RevokedOperatorByPartition(bytes32 indexed _partition, address indexed _operator, address indexed _tokenHolder);

  // Issuance / Redemption Events
  event Issued(address indexed _operator, address indexed _to, uint256 _value, bytes _data);
  event Redeemed(address indexed _operator, address indexed _from, uint256 _value, bytes _data);
  event IssuedByPartition(bytes32 indexed _partition, address indexed _operator, address indexed _to, uint256 _value, bytes _data, bytes _operatorData);
  event RedeemedByPartition(bytes32 indexed _partition, address indexed _operator, address indexed _from, uint256 _value, bytes _operatorData);


}