0xjac / erc777 Goto Github PK
View Code? Open in Web Editor NEWNew Standard for Ethereum Token
License: Mozilla Public License 2.0
New Standard for Ethereum Token
License: Mozilla Public License 2.0
The compiled solidity code is not included in the npm package.
This must be fixed by including the build
folder in the npm packages using the files
attributes in package.json
This repository has a number of references to EIP 820, when I believe it should be referencing 1820 everywhere.
https://github.com/jacquesd/eip777/blob/master/contracts/ReferenceToken.sol#L140
function mint(address _tokenHolder, uint256 _amount, bytes _operatorData) public onlyOwner {
requireMultiple(_amount);
mTotalSupply = mTotalSupply.add(_amount);
mBalances[_tokenHolder] = mBalances[_tokenHolder].add(_amount);
callRecipient(msg.sender, 0x0, _tokenHolder, _amount, "", _operatorData, true);
Minted(msg.sender, _tokenHolder, _amount, _operatorData);
if (mErc20compatible) { Transfer(0x0, _tokenHolder, _amount); }
}
burn:
function burn(address _tokenHolder, uint256 _amount, bytes _userData, bytes _operatorData) public onlyOwner {
requireMultiple(_amount);
require(balanceOf(_tokenHolder) >= _amount);
mBalances[_tokenHolder] = mBalances[_tokenHolder].sub(_amount);
mTotalSupply = mTotalSupply.sub(_amount);
Burned(msg.sender, _tokenHolder, _amount, _userData, _operatorData);
if (mErc20compatible) { Transfer(_tokenHolder, 0x0, _amount); }
}
callRecipient
if _operatorData is provided?I believe mint/burn function has to provide 2 methods with different params(overloaded function):
Traditional way without bytes _data
and new way with bytes _data
(overloaded function)
Setting up a mock migration in truffle suite to deploy the ReferenceToken (on 0.4.24) results in a Deployment Failed error.
Deploying 'ReferenceToken'
--------------------------
Error: *** Deployment Failed ***
"ReferenceToken" hit a require or revert statement somewhere in its constructor. Try:
* Verifying that your constructor params satisfy all require conditions.
* Adding reason strings to your require statements.
This is due to the doMint
function in the constructor which calls the following line
callRecipient(msg.sender, 0x0, _tokenHolder, _amount, "", _operatorData, true);
As preventLocking
is set to true here, only contracts who have implemented ERC777TokensRecipient
(on 820 client) can receive the tokens.
doMint
from the constructor to tell it to set preventLocking == false
ERC777TokensRecipient
Code coverage must be added for the reference implementation, probably using sc-forks/solidity-coverage either with solcpiler or truffle.
Be more precise in the spec about ERC20 Compatibility and define the use of the erc20compatible
boolean
A delegate is an address which has been authorized to send the tokens of a principal address. When calling send
on the token contract from the delegate, the tokens will be sent from the principal account not the delegate. In addition, each send involving a delegate will be explicitly authorized by an authorizer contract.
There is a key difference between an operator and a delegate.
To send tokens with an operator, the operator must call operatorSend
on the token contract. This should either be done automatically as a result of some action or by calling a function directly on the operator.
To send tokens with a delegate, the delegate only needs to call send
on the token contract. The token contract will figure out on his own that send was called from a delegate and first call the authorizer contract for authorization, then send from the principal address being represented by the delegate. This allows for checks to be used with wallets which just implement send
.
tokensToSend
tokensToSend
is registered via EIP-820 together with tokensReceived
. This means that the same function is called for all ERC-777 tokens. This is fine for tokensReceived
to notify the recipient and prevent locking because the logic is the same for all tokens.
This is not true for tokensToSend
which is aimed at checking whether a send is authorized or not. In this case the logic may not be the same for all tokens. Maybe a specific tokens should be rate-limited, an other one should be limited to be sent to a particular address and so on. Because there is only a single tokensToSend
function for all tokens, this function must be modified and the contract redeployed for every new tokens which must be handled.
Authorizers on the other hand are registered directly on the token contract and are only applied for the specific token. This keeps the logic simple and prevent constant modification and redeployment of the contract.
Another advantage of delegates is that they use a separate account than the principal account. In the case of tokensToSend
, since it is deployed for the account via EIP-820, the same key used to send tokens can also unregister the tokensToSend
, essentially making the check a self-imposed voluntary check which can be bypassed at any time.
Delegate is a separate address, tied to an authorizer; but only the principal account key has the power to change the authorizer. This means that the delegate can never bypass the checks.
Consider a principal account holding a large amount of tokens. The owner of the account must carry the private key with him at all time to use his tokens which may be dangerous.
A delegate with a daily quota could be authorized to send some of the tokens. The owner could carry this delegate on his phone and use his phone for limited transactions on a daily basis, the same way a debit card works. And when the owner needs to do an occasional large transaction, he can use the principal private key which is stored securely somewhere less practical to access (for example on a hardware wallet in a safe.).
Consider a cold wallet holding a large amount of tokens and a second hot wallet used for daily transactions.
The cold wallet can have a delegate which is only authorized to send to the hot wallet. The key of the cold wallet is stored securely and almost never used. The delegate is used to replenish the hot wallet from the cold wallet.
In addition backups of the delegate key can be given to trusted entities for safe keeping. This way even if the cold wallet key is lost, the delegate key can be used to recover the funds.
And if the delegate key is compromised the only thing an attacker can do is send the tokens from the cold to the hot wallet. This is a bit safer than entrusting the key of the cold wallet directly.
The authorizer must be a contract implementing the following interface:
interface IAuthorizer {
function authorizeSend(address to, uint256 value, bytes userData) public;
}
function authorizeSend(address to, uint256 value, bytes userData) public
Authorizes a send for the from address being represented by the delegate.
To prevent the send, the function MUST throw.
parameters
to
: tokens recipientvalue
: amount of tokens transferreduserData
: information attached to the transaction by the sender
In addition, the Ierc777
interface must be extended to add the following methods and events:
function authorizeDelegate(address delegate, address authorizer) public;
function revokeDelegate(address delegate) public;
function delegateFor(address delegate) public constant returns (address);
function authorizerOf(address delegate) public constant returns (address);
event AuthorizedDelegate(address indexed delegate, address indexed authorizer, address indexed tokenHolder);
event RevokedDelegate(address indexed delegate, address indexed authorizer, address indexed tokenHolder);
function authorizeDelegate(address delegate, address authorizer) public
Authorize a third party delegate
to send msg.sender
's tokens upon authorization of authorizer
.
The function MUST throw if:
delegate
is msg.sender
delegate
is already a delegate for another principaldelegate
holds tokens (non-zero balance)authorizer
is an operatorauthorizer
is already an authorizer for some delegateNOTE: While authorizer
MUST be a contract, there is no requirement to check it when authorizing the delegate and authorizer. When sending tokens however the authorizeSend
function of the authorizer MUST be called, which will result in a throw if authorizer
is not a contract or does not implement Authorizer
.
parameters
delegate
: Address that will to be authorized to sendmsg.sender
's tokens.authorizer
: Contract which will authorize_delegate
to send tokens.
function revokeDelegate(address delegate) public
Revoke a third party _delegate
's rights to send msg.sender
's tokens.
The function MUST throw if:
delegate
is not the delegate of msg.sender
.NOTE: While the authorizer does not need to be specified when revoking, internally the authorizer MUST also be revoked (i.e. not marked as the authorizer for delegate
).
parameters
delegate
: Address of the delegate formsg.sender
.
TODO Improvement: Since, there can be only one delegate per account, a two-way mapping of the delegate could be kept such that msg.sender
does not need to specify the delegate when revoking
function delegateFor(address delegate) public constant returns (address)
Get the address for which delegate
is authorized to send tokens or 0x0
if delegate
is not a delegate.
parameters
delegate
: Address for which to return the principal address.returns: Address for which
_delegate
is authorized to send tokens or0x0
if_delegate
is not a delegate.
function authorizerOf(address _delegate) public constant returns (address)
Get the address for which delegate
is authorized to send tokens or 0x0
if delegate
is not a delegate.
parameters
delegate
: Delegate address for which to return the authorizer contract address.returns: Authorizer contract address of
_delegate
or0x0
if_delegate
is not a delegate.
event AuthorizedDelegate(address indexed delegate, address indexed authorizer, address indexed tokenHolder)
Indicate that the delegate
address is representing tokenHolder
and send its token (i.e. is a delegate for tokenHolder
).
This event MUST be fired on a successful call to authorizeDelegate
.
parameters
delegate
: Address which is now representingtokenHolder
.authorizer
: Contract which will authorize_delegate
to send tokens.tokenHolder
: address being represented bydelegate
.
event RevokedDelegate(address indexed delegate, address indexed authorizer, address indexed tokenHolder)
Indicate that the delegate
address is not representing tokenHolder
anymore and cannot send its tokens (i.e. is not delegate for tokenHolder
).
This event MUST be fired on a successful call to revokeDelegate
.
parameters
delegate
: Address which is not representingtokenHolder
anymore.authorizer
: Contract which will authorize_delegate
to send tokens.tokenHolder
: address not being represented bydelegate
anymore.
Furthermore the send', 'operatorSend', 'transfer' and 'transferFrom
method specification as well as the Burned
event specification must be extended with the following constraint:
If
from
is a delegate, thenfrom.authorize
MUST be called and pass the correct values forto
,value
anduserData
.NOTE: While intuitively the
authorize
call happens before sending the tokens, in the implementation, this call SHOULD be after the update of balances and before the call totokensReceived
to respect the Checks-Effects-Interactions (CEI) pattern and prevent potential reentry attacks.When
from
is a delegate, thetokensReceived
,Sent
andBurnt
must be called with the truefrom
(i.e. the token holder being represented by the delegate) not the delegate itself. Delegates are transparent from the point of view of the recipient and MUST NOT be communicated.
how i can compile this project?
please provide detailed instructions
All tests are located in a single file (test/ReferenceToken-test.js) which is growing. It is becoming hard to read each test case.
The tests should be split in different files, for example:
name
, symbol
, ...)In https://github.com/jacquesd/EIPs/blob/master/EIPS/eip-777.md,
event Minted(address indexed operator, address indexed to, uint256 amount, bytes data, bytes operatorData)
reference implementation:
https://github.com/jacquesd/ERC777/blob/896d077eb4b1beb0fc2258f9d4dff4b60478a479/contracts/ERC777Token.sol#L38
interface ERC777TokensSender {
function tokensToSend(
address operator,
address from,
address to,
uint value,
bytes userData,
bytes operatorData
) public;
}
This proposal adds the above interface which must be registered via EIP-820, similar to tokensReceived
.
The difference from tokensReceived
is that tokensToSend
is called for the from
address before sending the tokens. This allows the token holder to perform a a final check, logging or some other action before sending the tokens.
The contracts cannot currently compile when using a derived contract with pragma solidity ^0.4.24 because of the version difference and lack of the ^ in a few base contracts.
I see you are updating to solidity 0.4.24 in the cleanup branch which is very much welcome.
However, in that branch there are a few files that specify "pragma solidity 0.4.24" without the ^ carrot. Shouldn't these be "pragma solidity ^0.4.24" so that derived contracts can compile ERC777 these on future solidity versions after 0.4.24 when they come out?
I like operator, but some native english speaker should decide it.
There is a discrepancy between the standard and the reference implementation regarding the burn
and operatorBurn
functions:
The current standard (https://github.com/ethereum/EIPs/blob/b41669ede219b9599a6a1c637e578b8a444ad6b1/EIPS/eip-777.md) says:
The data field of the tokensToSend hook MUST be empty.
But, the current reference implementation doesn't check (or enforce) the emptiness (of _holderData
):
Current truffle that is referenced in dependencies has vulnerabilites:
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ Critical │ Command Injection │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package │ growl │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Patched in │ >=1.10.2 │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ erc777 │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path │ erc777 > truffle > mocha > growl │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info │ https://nodesecurity.io/advisories/146 │
└───────────────┴──────────────────────────────────────────────────────────────┘
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ Low │ Regular Expression Denial of Service │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package │ debug │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Patched in │ >= 2.6.9 < 3.0.0 || >= 3.1.0 │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ erc777 │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path │ erc777 > truffle > mocha > debug │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info │ https://nodesecurity.io/advisories/534 │
└───────────────┴──────────────────────────────────────────────────────────────┘
This leads to false positives while auditing projects which are using erc777 as dependency in npm even if their own truffle is updated.
hi
777 gets roughly 27 static warnings in remix.
you can remove 12 of them by defining a boundry on bytes (at line 252 of this contract: https://gist.github.com/lrgeoemtry/df096412147a1859bae07cc31f51b267) of "bytes32"
doing this though makes it so i cannot deploy the contract getting this error:
"This contract does not implement all functions and thus cannot be created."
I'm going to keep hacking away at it, but im hopeful the community can help.
the other 15 static analysis warnings are 2 reentrancy issues which we modified with mutex (492-505 & 528-509)
and "similar variable names" which is readability deprecation but w/e
any help with this is much appreciated as currently sending a 777 token is like .1 rEth and as expensive as hell.
For convenience and security reasons, a new function should be added:
function revokeAllOperators() public;
This method revokes all the operators for msg.sender
.
If it is, how to avoid it?
The documentation in the ReferenceToken
should be generated into a nice HTML page for devs to more easily understand the code.
The Open Zeppelin team would like to include standard implementations of ERC-777 and ERC-820 in our repository https://github.com/OpenZeppelin/openzeppelin-solidity/. We are seeking permission to release a modified version of the implementation of the standards found in this ERC777 repo as well as the ERC820 repo https://github.com/jacquesd/eip820.
Could we get your permission to do this?
There is a discrepancy between the standard and the reference implementation regarding the operatorSend
and operatorBurn
functions:
The current standard (https://github.com/ethereum/EIPs/blob/b41669ede219b9599a6a1c637e578b8a444ad6b1/EIPS/eip-777.md):
The value of from MAY be 0x0, then the from (token holder) used for the send MUST be msg.sender (the operator).
The current reference implementation of both operatorSend
and operatorBurn
:
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.