forked from DecentralizedClimateFoundation/DCIPs
231 lines
11 KiB
Markdown
231 lines
11 KiB
Markdown
---
|
|
eip: 1203
|
|
title: ERC-1203 Multi-Class Token Standard (ERC-20 Extension)
|
|
author: Jeff Huang <jeffishjeff@gmail.com>, Min Zu <crawlregister@gmail.com>
|
|
discussions-to: https://github.com/ethereum/EIPs/issues/1203
|
|
status: Stagnant
|
|
type: Standards Track
|
|
category: ERC
|
|
created: 2018-07-01
|
|
---
|
|
|
|
## Simple Summary
|
|
|
|
A standard interface for multi-class tokens (MCTs).
|
|
|
|
## Abstract
|
|
|
|
The following standard allows for the implementation of a standard API for MCTs within smart contracts. This standard provides basic functionality to track, transfer, and convert MCTs.
|
|
|
|
## Motivation
|
|
|
|
This standard is heavily inspired by ERC-20 Token Standard and ERC-721 Non-Fungible Token Standard. However, whereas these standards are chiefly concerned with representation of items/value in a single class, fungible or note, this proposed standard focus on that of a more complexed, multi-class system. It is fair to think of MCTs as a hybrid of fungible tokens (FT) and non-fungible tokens (NFTs), that is tokens are fungible within the same class but non-fungible with that from a different class. And conversions between classes may be optionally supported.
|
|
|
|
MCTs are useful in representing various structures with heterogeneous components, such as:
|
|
|
|
- **Abstract Concepts:** A company may have different classes of stocks (e.g. senior preferred, junior preferred, class A common, class B common) that together make up its outstanding equities. A shareholder's position of such company composites of zero or more shares in each class.
|
|
|
|
- **Virtual Items:** A sandbox computer game may have many types of resources (e.g. rock, wood, berries, cows, meat, knife, etc.) that together make up that virtual world. A player's inventory has any combination and quantity of these resources
|
|
|
|
- **Physical Items:** A supermarket may have many SKUs it has available for purchase (e.g. eggs, milk, beef jerky, beer, etc.). Things get added or removed from a shopper's cart as it moves down the aisle.
|
|
|
|
It's sometimes possible, especially with regard to abstract concepts or virtual items, to convert from one class to another, at a specified conversion ratio. When it comes to physical items, such conversion essentially is the implementation of bartering. Though it might generally be easier to introduce a common intermediary class, i.e. money.
|
|
|
|
## Specification
|
|
|
|
```solidity
|
|
contract ERC20 {
|
|
function totalSupply() public view returns (uint256);
|
|
function balanceOf(address _owner) public view returns (uint256);
|
|
function transfer(address _to, uint256 _value) public returns (bool);
|
|
function approve(address _spender, uint256 _value) public returns (bool);
|
|
function allowance(address _owner, address _spender) public view returns (uint256);
|
|
function transferFrom(address _from, address _to, uint256 _value) public returns (bool);
|
|
|
|
event Transfer(address indexed _from, address indexed _to, uint256 _value);
|
|
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
|
|
}
|
|
|
|
contract ERC1203 is ERC20 {
|
|
function totalSupply(uint256 _class) public view returns (uint256);
|
|
function balanceOf(address _owner, uint256 _class) public view returns (uint256);
|
|
function transfer(address _to, uint256 _class, uint256 _value) public returns (bool);
|
|
function approve(address _spender, uint256 _class, uint256 _value) public returns (bool);
|
|
function allowance(address _owner, address _spender, uint256 _class) public view returns (uint256);
|
|
function transferFrom(address _from, address _to, uint256 _class, uint256 _value) public returns (bool);
|
|
|
|
function fullyDilutedTotalSupply() public view returns (uint256);
|
|
function fullyDilutedBalanceOf(address _owner) public view returns (uint256);
|
|
function fullyDilutedAllowance(address _owner, address _spender) public view returns (uint256);
|
|
function convert(uint256 _fromClass, uint256 _toClass, uint256 _value) public returns (bool);
|
|
|
|
event Transfer(address indexed _from, address indexed _to, uint256 _class, uint256 _value);
|
|
event Approval(address indexed _owner, address indexed _spender, uint256 _class, uint256 _value);
|
|
event Convert(uint256 indexed _fromClass, uint256 indexed _toClass, uint256 _value);
|
|
}
|
|
```
|
|
|
|
### ERC-20 Methods and Events (fully compatible)
|
|
|
|
Please see [ERC-20 Token Standard](./eip-20.md) for detailed specifications. Do note that these methods and events only work on the "default" class of an MCT.
|
|
|
|
```solidity
|
|
function totalSupply() public view returns (uint256);
|
|
function balanceOf(address _owner) public view returns (uint256);
|
|
function transfer(address _to, uint256 _value) public returns (bool);
|
|
function approve(address _spender, uint256 _value) public returns (bool);
|
|
function allowance(address _owner, address _spender) public view returns (uint256);
|
|
function transferFrom(address _from, address _to, uint256 _value) public returns (bool);
|
|
|
|
event Transfer(address indexed _from, address indexed _to, uint256 _value);
|
|
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
|
|
```
|
|
|
|
### Tracking and Transferring
|
|
|
|
**totalSupply**
|
|
|
|
Returns the total number of tokens in the specified `_class`
|
|
|
|
```solidity
|
|
function totalSupply(uint256 _class) public view returns (uint256);
|
|
```
|
|
|
|
**balanceOf**
|
|
|
|
Returns the number of tokens of a specified `_class` that the `_owner` has
|
|
|
|
```solidity
|
|
function balanceOf(address _owner, uint256 _class) public view returns (uint256);
|
|
```
|
|
|
|
**transfer**
|
|
|
|
Transfer `_value` tokens of `_class` to address specified by `_to`, return `true` if successful
|
|
|
|
```solidity
|
|
function transfer(address _to, uint256 _class, uint256 _value) public returns (bool);
|
|
```
|
|
|
|
**approve**
|
|
|
|
Grant `_spender` the right to transfer `_value` tokens of `_class`, return `true` if successful
|
|
|
|
```solidity
|
|
function approve(address _spender, uint256 _class, uint256 _value) public returns (bool);
|
|
```
|
|
|
|
**allowance**
|
|
|
|
Return the number of tokens of `_class` that `_spender` is authorized to transfer on the behalf of `_owner`
|
|
|
|
```solidity
|
|
function allowance(address _owner, address _spender, uint256 _class) public view returns (uint256);
|
|
```
|
|
|
|
**transferFrom**
|
|
|
|
Transfer `_value` tokens of `_class` from address specified by `_from` to address specified by `_to` as previously approved, return `true` if successful
|
|
|
|
```solidity
|
|
function transferFrom(address _from, address _to, uint256 _class, uint256 _value) public returns (bool);
|
|
```
|
|
|
|
**Transfer**
|
|
|
|
Triggered when tokens are transferred or created, including zero value transfers
|
|
|
|
```solidity
|
|
event Transfer(address indexed _from, address indexed _to, uint256 _class, uint256 _value);
|
|
```
|
|
|
|
**Approval**
|
|
|
|
Triggered on successful `approve`
|
|
|
|
```solidity
|
|
event Approval(address indexed _owner, address indexed _spender, uint256 _class, uint256 _value);
|
|
```
|
|
|
|
### Conversion and Dilution
|
|
|
|
**fullyDilutedTotalSupply**
|
|
|
|
Return the total token supply as if all converted to the lowest common denominator class
|
|
|
|
```solidity
|
|
function fullyDilutedTotalSupply() public view returns (uint256);
|
|
```
|
|
|
|
**fullyDilutedBalanceOf**
|
|
|
|
Return the total token owned by `_owner` as if all converted to the lowest common denominator class
|
|
|
|
```solidity
|
|
function fullyDilutedBalanceOf(address _owner) public view returns (uint256);
|
|
```
|
|
|
|
**fullyDilutedAllowance**
|
|
|
|
Return the total token `_spender` is authorized to transfer on behalf of `_owner` as if all converted to the lowest common denominator class
|
|
|
|
```solidity
|
|
function fullyDilutedAllowance(address _owner, address _spender) public view returns (uint256);
|
|
```
|
|
|
|
**convert**
|
|
|
|
Convert `_value` of `_fromClass` to `_toClass`, return `true` if successful
|
|
|
|
```solidity
|
|
function convert(uint256 _fromClass, uint256 _toClass, uint256 _value) public returns (bool);
|
|
```
|
|
|
|
**Conversion**
|
|
|
|
Triggered on successful `convert`
|
|
|
|
```solidity
|
|
event Conversion(uint256 indexed _fromClass, uint256 indexed _toClass, uint256 _value);
|
|
```
|
|
|
|
## Rationale
|
|
This standard purposely extends ERC-20 Token Standard so that new MCTs following or existing ERC-20 tokens extending this standard are fully compatible with current wallets and exchanges. In addition, new methods and events are kept as closely to ERC-20 conventions as possible for ease of adoption.
|
|
|
|
We have considered alternative implementations to support the multi-class structure, as discussed below, and we found current token standards incapable or inefficient in deal with such structures.
|
|
|
|
**Using multiple ERC-20 tokens**
|
|
|
|
It is certainly possible to create an ERC-20 token for each class, and a separate contract to coordinate potential conversions, but the short coming in this approach is clearly evident. The rationale behind this standard is to have a single contract to manage multiple classes of tokens.
|
|
|
|
**Shoehorning ERC-721 token**
|
|
|
|
Treating each token as unique, the non-fungible token standard offers maximum representational flexibility arguably at the expense of convenience. The main challenge of using ERC-721 to represent multi-class token is that separate logic is required to keep track of which tokens belongs to which class, a hacky and unnecessary endeavor.
|
|
|
|
**Using ERC-1178 token**
|
|
|
|
We came across ERC-1178 as we were putting final touches on our own proposal. The two ERCs look very similar on the surface but we believe there're a few key advantages this one has over ERC-1178.
|
|
|
|
- ERC-1178 offers no backward compatibility whereas this proposal is an extension of ERC-20 and therefore fully compatible with all existing wallets and exchanges
|
|
- By the same token, existing ERC-20 contracts can extend themselves to adopt this standard and support additional classes without affecting their current behaviors
|
|
- This proposal introduces the concept of cross class conversion and dilution, making each token class integral part of a whole system rather than many silos
|
|
|
|
## Backwards Compatibility
|
|
This EIP is fully compatible with the mandatory methods of ERC20 Token Standard so long as the implementation includes a "lowest common denominator" class, which may be class B common/gold coin/money in the abstract/virtual/physical examples above respectively. Where it is not possible to implement such class, then the implementation should specify a default class for tracking or transferring unless otherwise specified, e.g. US dollar is transferred unless other currency is explicitly specified.
|
|
|
|
We find it contrived to require the optional methods of ERC20 Token Standard, `name()`, `symbol()`, and `decimals()`, but developers are certainly free to implement these as they wish.
|
|
|
|
## Test Cases
|
|
The repository at [jeffishjeff/ERC-1203](https://github.com/jeffishjeff/ERC-1203) contains the [sample test cases](https://github.com/jeffishjeff/ERC-1203/blob/master/token.test.js).
|
|
|
|
## Implementation
|
|
The repository at [jeffishjeff/ERC-1203](https://github.com/jeffishjeff/ERC-1203) contains the [sample implementation](https://github.com/jeffishjeff/ERC-1203/blob/master/token.sol).
|
|
|
|
## References
|
|
- ERC-20 Token Standard. ./eip-20.md
|
|
- ERC-721 Non-Fungible Token Standard. ./eip-721.md
|
|
- ERC-1178 Multi-class Token Standard. ./eip-1178.md
|
|
|
|
## Copyright
|
|
Copyright and related rights waived via [CC0](../LICENSE.md).
|