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

ERC995 Token Standard #995

Open
ProphetDaniel opened this issue Apr 13, 2018 · 4 comments

Comments

Projects
None yet
2 participants
@ProphetDaniel
Copy link

commented Apr 13, 2018

EIP: 995
Title: ERC995 Token Standard (ERC20 Extension)
Author: Prophet Daniel <prophetdaniel@ethereumclassic.org>
Type: Token Standard
Category: ERC
Created: 2018-04-12

Simple Summary

An extension of the standard interface ERC #20 for tokens with methods that allows the execution of calls inside transfer and approvals based on ERC #827.

Abstract

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.

Motivation

This extension of the ERC20 interface allows any tokens on Ethereum to be re-used by other applications: from wallets to decentralized exchanges. The ERC20 token standard is widely accepted but it only allows the transfer of value, Ethereum users are available to transfer value and data on transactions, with this extension of the ERC20 token standard they will be able to do the same with ERC20 tokens.

There are a lot of new standards being proposed in the community. The natural evolution of ERC20 standard starts with compatibility with the original standard and also add new methods, but keeping it simple at the same time, the new functions proposed are still less than 100 lines of code taking in count the documentation.

When to use each function

  • approve: Probably the one that you will need, maybe the only one since it allows the receiver contract to use authenticated/approved balance. The best practice is to check the allowance of the sender and then do your stuff using the transferFrom method.

  • transfer: There is no way to check that the balance that will be transferred is the correct one, this function is useful when a function doesn't need to check any transfer of value.

  • transferFrom: Same as transfer, only useful when there is no need to check the transferred amount of tokens and caller wants to spend approved balance.

Specification

Token

Methods

NOTE: Callers MUST handle false from returns (bool success). Callers MUST NOT assume that false is never returned!

name - ERC20

Returns the name of the token - e.g. "MyToken".

OPTIONAL - This method can be used to improve usability,
but interfaces and other contracts MUST NOT expect these values to be present.

function name() constant returns (string name)

symbol - ERC20

Returns the symbol of the token. E.g. "HIX".

OPTIONAL - This method can be used to improve usability,
but interfaces and other contracts MUST NOT expect these values to be present.

function symbol() constant returns (string symbol)

decimals - ERC20

Returns the number of decimals the token uses - e.g. 8, means to divide the token amount by 100000000 to get its user representation.

OPTIONAL - This method can be used to improve usability,
but interfaces and other contracts MUST NOT expect these values to be present.

function decimals() constant returns (uint8 decimals)

totalSupply - ERC20

Returns the total token supply.

function totalSupply() constant returns (uint256 totalSupply)

balanceOf - ERC20

Returns the account balance of another account with address _owner.

function balanceOf(address _owner) constant returns (uint256 balance)

transfer - ERC20

Transfers _value amount of tokens to address _to, and MUST fire the Transfer event.
The function SHOULD revert if the _from account balance does not have enough tokens to spend.

A token contract which creates new tokens SHOULD trigger a Transfer event with the _from address set to 0x0 when tokens are created.

Note Transfers of 0 values MUST be treated as normal transfers and fire the Transfer event.

function transfer(address _to, uint256 _value) returns (bool success)

transferFrom - ERC20

Transfers _value amount of tokens from address _from to address _to, and MUST fire the Transfer event.

The transferFrom method is used for a withdraw workflow, allowing contracts to transfer tokens on your behalf.
This can be used for example to allow a contract to transfer tokens on your behalf and/or to charge fees in sub-currencies.
The function SHOULD revert unless the _from account has deliberately authorized the sender of the message via some mechanism.

Note Transfers of 0 values MUST be treated as normal transfers and fire the Transfer event.

function transferFrom(address _from, address _to, uint256 _value) returns (bool success)

approve - ERC20

Allows _spender to withdraw from your account multiple times, up to the _value amount. If this function is called again it overwrites the current allowance with _value.

Users SHOULD make sure to create user interfaces in such a way that they set the allowance first to 0 before setting it to another value for the same spender.
THOUGH The contract itself shouldn't enforce it, to allow backward compatibility with contracts deployed before

function approve(address _spender, uint256 _value) returns (bool success)

allowance - ERC20

Returns the amount which _spender is still allowed to withdraw from _owner.

function allowance(address _owner, address _spender) constant returns (uint256 remaining)

ERC995 methods

transfer - ERC995

Execute two functions on _dataContract with the _preData and _posData parameters respectively one before and one after the transfer. If both functions end successfully execute the transfer of _value amount of tokens to address _to and MUST fire the Transfer event.

The function SHOULD revert if any of the two calls to _dataContract address fails or if _from account balance does not have enough tokens to spend.
The ERC20 transfer method is called after _dataContract.call(_preData) and before the _dataContract.call(_posData).

Note: The _to address cant be the token address itself.
Note: Transfers of 0 values MUST be treated as normal transfers and fire the Transfer event.

Important Note: Do not use this method with fallback functions that receive the value transferred as a parameter, there is no way to verify how much value was really transferred.

  function transfer(
    address _to,
    address _dataContract,
    uint256 _value,
    bytes _preData,
    bytes _posData
  )
    public onlyAnotherAddress(_to) returns (bool)
  {
    require(_dataContract.call(_preData));
    super.transfer(_to, _value);
    require(_dataContract.call(_posData));
    return true;
  }

transferFrom - ERC995

Execute two functions on _dataContract with the _preData and _posData parameters respectively one before and one after the transferFrom, If both functions end successfully execute the transfer of _value amount of tokens from address _from to address _to, and MUST fire the Transfer event.

The transferFrom method is used for a withdraw workflow, allowing contracts to transfer tokens on your behalf after executing a function.
The ERC20 transferFrom method is called after _dataContract.call(_preData) and before the _dataContract.call(_posData).
This can be used for example to allow a contract to transfer tokens on your behalf and/or to charge fees in sub-currencies.
The function SHOULD revert if any of the two calls to _dataContract address fails or if the _from approved balance by _from to msg.sender is not enough to execute the transfer.

Note: The _to address cant be the token address itself.
Note: Transfers of 0 values MUST be treated as normal transfers and fire the Transfer event.

Important Note: Do not use this method with fallback functions that receive the value transferred as a parameter, there is no way to verify how much value was really transferred.

  function transferFrom(
    address _from,
    address _to,
    address _dataContract,
    uint256 _value,
    bytes _preData,
    bytes _posData
  )
    public onlyAnotherAddress(_to) returns (bool)
  {
    require(_dataContract.call(_preData));
    super.transferFrom(_from, _to, _value);
    require(_dataContract.call(_posData));
    return true;
  }

approve - ERC995

Execute a function on _dataContract with the _preData and _posData parameters respectively one before and one after the approve, if both two calls to _dataContract address end successfully, _spender is allowed to withdraw from owner's account multiple times, up to the _value amount. If this function is called again it overwrites the current allowance with _value.

Clients SHOULD make sure to create user interfaces in such a way that they set the allowance first to 0 before setting it to another value for the same spender.
The ERC20 approve method is called after _dataContract.call(_preData) and before the _dataContract.call(_posData).
The function SHOULD revert if any of the two calls to _dataContract address fails.
THOUGH The contract itself shouldn't enforce it, to allow backward compatibility with contracts deployed before

Note: The _spender address cant be the token address itself.

function approve(
    address _spender,
    address _dataContract,
    uint256 _value,
    bytes _preData,
    bytes _posData
  )
    public onlyAnotherAddress(_spender) returns (bool)
  {
    require(_dataContract.call(_preData));
    super.approve(_spender, _value);
    require(_dataContract.call(_posData));
    return true;
  }

Events

Transfer - ERC20

MUST trigger when tokens are transferred, including zero value transfers.

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

Approval - ERC20

MUST trigger on any successful call to approve(address _spender, uint256 _value).

event Approval(address indexed _owner, address indexed _spender, uint256 _value)

Revisions

2018/02/04: Initial Draft

Implementation

Copyright

Copy left, copy down, copy right: sonic boom

@ProphetDaniel ProphetDaniel changed the title ERCxxx Token Standard ERC995 Token Standard Apr 13, 2018

@k06a

This comment has been minimized.

Copy link

commented Apr 13, 2018

Why _dataContract argument appears is before _value in every function? I think it is better to add new arguments after existing ones.

@k06a

This comment has been minimized.

Copy link

commented Apr 13, 2018

What do you think about making these methods payble to transfer value to _dataContract? In which of 2 calls value should be passed? I am working on adding payable to ERC827 implementation: OpenZeppelin/openzeppelin-solidity#838

@ProphetDaniel

This comment has been minimized.

Copy link
Author

commented Apr 14, 2018

Why _dataContract argument appears is before _value in every function? I think it is better to add new arguments after existing ones.

Because if you try, for example, to reorder existing parameters for transfer method the following test fails:

  it('should return correct balances after transfer', async function () {
    await token.transfer(accounts[1], 100);
    let balance0 = await token.balanceOf(accounts[0]);
    assert.equal(balance0, 0);

    let balance1 = await token.balanceOf(accounts[1]);
    assert.equal(balance1, 100);
  });

with the additional info:

  1) Contract: ERC995 Token should return correct balances after transfer:
     Error: Invalid number of arguments to Solidity function
      at Object.InvalidNumberOfSolidityArgs (C:\Users\ProphetDaniel\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\web3\lib\web3\errors.js:25:1)
      at SolidityFunction.validateArgs (C:\Users\ProphetDaniel\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\web3\lib\web3\function.js:74:1)
      at SolidityFunction.toPayload (C:\Users\ProphetDaniel\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\web3\lib\web3\function.js:90:1)
      at SolidityFunction.sendTransaction (C:\Users\ProphetDaniel\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\web3\lib\web3\function.js:163:1)
      at SolidityFunction.execute (C:\Users\ProphetDaniel\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\web3\lib\web3\function.js:256:1)
      at C:\Users\ProphetDaniel\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\truffle-contract\contract.js:204:1
      at new Promise (<anonymous>)
      at C:\Users\ProphetDaniel\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\truffle-contract\contract.js:155:1
      at <anonymous>
      at process._tickCallback (internal/process/next_tick.js:118:7)

It is a weird situation were the signature of the function with extra parameters is influencing on the function with less parameters, in this case the ERC20 transfer function.

@ProphetDaniel

This comment has been minimized.

Copy link
Author

commented Apr 14, 2018

What do you think about making these methods payble to transfer value to _dataContract? In which of 2 calls value should be passed? I am working on adding payable to ERC827 implementation: OpenZeppelin/openzeppelin-solidity#838

@k06a , it looks a great functionality to be added later on after the implementation is merged on Open Zeppelin. Right now I believe we should await their review of the current implementation. Later on I suggest you to open a pull request as well for ERC995.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.