Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
jeffishjeff opened this issue Jul 9, 2018 · 7 comments
Closed

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

jeffishjeff opened this issue Jul 9, 2018 · 7 comments

Comments

@jeffishjeff
Copy link
Contributor

jeffishjeff commented Jul 9, 2018

eip: 1203
title: ERC-1203 Multi-Class Token Standard (ERC-20 Extension)
author: Jeff Huang <[email protected]>, Min Zu <[email protected]>
discussions-to: https://github.com/ethereum/EIPs/issues/1203
status: Draft
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

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 for detailed specifications. Do note that these methods and events only work on the "default" class of an MCT.

    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

    function totalSupply(uint256 _class) public view returns (uint256);

balanceOf

Returns the number of tokens of a specified _class that the _owner has

    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

    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

    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

    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

    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

    event Transfer(address indexed _from, address indexed _to, uint256 _class, uint256 _value);

Approval

Triggered on successful approve

    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

    function fullyDilutedTotalSupply() public view returns (uint256);

fullyDilutedBalanceOf

Return the total token owned by _owner as if all converted to the lowest common denominator class

    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

    function fullyDilutedAllowance(address _owner, address _spender) public view returns (uint256);

convert

Convert _value of _fromClass to _toClass, return true if successful

    function convert(uint256 _fromClass, uint256 _toClass, uint256 _value) public returns (bool);

Conversion

Triggered on successful convert

    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 contains the sample test cases.

Implementation

The repository at jeffishjeff/ERC-1203 contains the sample implementation.

References

Copyright

Copyright and related rights waived via CC0.

@jeffishjeff jeffishjeff changed the title Multi-Class Token Standard (ERC-20 Extension) ERC-1203 Multi-Class Token Standard (ERC-20 Extension) Jul 9, 2018
@xinbenlv
Copy link
Contributor

xinbenlv commented Jul 9, 2018

So if I read it correctly, this is a competing proposal against #1178, right?

@jeffishjeff
Copy link
Contributor Author

@xinbenlv that wasn't our original intent but, yes, looks like we're independently trying to address the same issue.

We only became aware of ERC-1178 when doing a final sync before creating the new pull request today. And after studying ERC-1178 in detail, we felt that our proposal still contains enough merits and differences (as described in the Rationale section) that warranted community consideration.

Love to hear your thoughts on either or both of the ERCs :)

@xinbenlv
Copy link
Contributor

xinbenlv commented Jul 9, 2018

Well, coming from a "traditional" Internet background, I can see how important it's for a latter protocol/standard to be backward compatible to a widely accepted existing standard(ERC-20 in this case), so I think that's a very strong advantage of ERC-1203
@jeffishjeff great idea~

@PhABC
Copy link
Contributor

PhABC commented Jul 27, 2018

Hello!

This sounds very similar to #1155 and #888 as well. Would it be possible for you to chime in there so we can all collaborate on a single standard?

@jeffishjeff
Copy link
Contributor Author

Thanks @PhABC for the heads up. #1155 seem to have evolved a lot since I last visited it and I agree it's becoming a superset of what I wanted to do with this proposal. Yes, I'd be happy to join the discussion there

@HassanFahmy
Copy link

Why not add a safe transfer function?

@jeffishjeff
Copy link
Contributor Author

@HassanFahmy I agree, safe transfer together with token fallback/received is becoming expected features in token standards. I would definitely in favor of adding them. But as stated above, I've been working more with #1155 as I believe that standard provides all features of this one and more.

Closing the issue for now. Thanks everyone for chiming in, and anyone who wishes to re-open or take the proposal further is certainly free to do so. Cheers!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants