From fe15d144d4735fd4e0918b56ffd74f8e77392209 Mon Sep 17 00:00:00 2001 From: etsvigun Date: Sun, 7 Oct 2018 13:46:36 +0300 Subject: [PATCH 01/64] IERC777 from specs, constants returned, up to defaultOperators. (#1159) --- contracts/token/ERC777/ERC777.sol | 74 ++++++++++++++++++++++++++++++ contracts/token/ERC777/IERC777.sol | 46 +++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 contracts/token/ERC777/ERC777.sol create mode 100644 contracts/token/ERC777/IERC777.sol diff --git a/contracts/token/ERC777/ERC777.sol b/contracts/token/ERC777/ERC777.sol new file mode 100644 index 00000000000..fbe862532c2 --- /dev/null +++ b/contracts/token/ERC777/ERC777.sol @@ -0,0 +1,74 @@ +pragma solidity ^0.4.24; + +import "./IERC777.sol"; +import "../../math/SafeMath.sol"; + +contract ERC777 is IERC777 { + using SafeMath for uint256; + + string private _name; + + string private _symbol; + + mapping(address => uint256) private _balances; + + uint256 private _totalSupply; + + uint256 private _granularity; + + address[] private _defaultOperatorsArray; + + constructor(string name, string symbol, uint256 granularity, address[] defaultOperators) public { + require(granularity > 0); + _name = name; + _symbol = symbol; + _defaultOperatorsArray = defaultOperators; + } + + /** + * @return the name of the token. + */ + function name() public view returns (string) { + return _name; + } + + /** + * @return the symbol of the token. + */ + function symbol() public view returns (string) { + return _symbol; + } + + /** + * @dev Total number of tokens in existence + */ + function totalSupply() public view returns (uint256) { + return _totalSupply; + } + + /** + * @dev Gets the balance of the specified address. + * @param tokenHolder The address to query the balance of. + * @return uint256 representing the amount owned by the specified address. + */ + function balanceOf(address tokenHolder) public view returns (uint256) { + return _balances[tokenHolder]; + } + + /** + * @dev Gets the token's granularity, + * i.e. the smallest number of tokens (in the basic unit) which may be minted, sent or burned at any time + * @return uint256 granularity + */ + function granularity() public view returns (uint256) { + return _granularity; + } + + /** + * @dev Get the list of default operators as defined by the token contract. + * @return address[] default operators + */ + function defaultOperators() public view returns (address[]) { + return _defaultOperatorsArray; + } +} diff --git a/contracts/token/ERC777/IERC777.sol b/contracts/token/ERC777/IERC777.sol new file mode 100644 index 00000000000..ee5998d2720 --- /dev/null +++ b/contracts/token/ERC777/IERC777.sol @@ -0,0 +1,46 @@ +pragma solidity ^0.4.24; + +/** + * @title ERC777 interface + * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-777.md + */ +interface IERC777 { + function name() external view returns (string); + + function symbol() external view returns (string); + + function totalSupply() external view returns (uint256); + + function balanceOf(address owner) external view returns (uint256); + + function granularity() external view returns (uint256); + + function defaultOperators() external view returns (address[]); + + function authorizeOperator(address operator) external; + + function revokeOperator(address operator) external; + + function isOperatorFor(address operator, address tokenHolder) external view returns (bool); + + function send(address to, uint256 amount, bytes data) external; + + function operatorSend(address from, address to, uint256 amount, bytes data, bytes operatorData) external; + + function burn(uint256 amount, bytes data) external; + + function operatorBurn(address from, uint256 amount, bytes data, bytes operatorData) external; + + event Sent( + address indexed operator, + address indexed from, + address indexed to, + uint256 amount, + bytes data, + bytes operatorData + ); + event Minted(address indexed operator, address indexed to, uint256 amount, bytes data, bytes operatorData); + event Burned(address indexed operator, address indexed from, uint256 amount, bytes operatorData); + event AuthorizedOperator(address indexed operator, address indexed tokenHolder); + event RevokedOperator(address indexed operator, address indexed tokenHolder); +} From 1d26da31ea8fc6c228d152659f396081acbd7db6 Mon Sep 17 00:00:00 2001 From: etsvigun Date: Sun, 7 Oct 2018 16:55:56 +0300 Subject: [PATCH 02/64] IERC777 oprarator approvals (#1159) --- contracts/token/ERC777/ERC777.sol | 111 ++++++++++++++++++++++++++++-- test/token/ERC777/ERC777.test.js | 97 ++++++++++++++++++++++++++ 2 files changed, 203 insertions(+), 5 deletions(-) create mode 100644 test/token/ERC777/ERC777.test.js diff --git a/contracts/token/ERC777/ERC777.sol b/contracts/token/ERC777/ERC777.sol index fbe862532c2..5c5afde3e92 100644 --- a/contracts/token/ERC777/ERC777.sol +++ b/contracts/token/ERC777/ERC777.sol @@ -3,6 +3,7 @@ pragma solidity ^0.4.24; import "./IERC777.sol"; import "../../math/SafeMath.sol"; + contract ERC777 is IERC777 { using SafeMath for uint256; @@ -16,13 +17,25 @@ contract ERC777 is IERC777 { uint256 private _granularity; - address[] private _defaultOperatorsArray; + address[] private _defaultOpsArray; + mapping(address => bool) _defaultOps; + mapping(address => mapping(address => bool)) _revokedDefaultOps; + mapping(address => mapping(address => bool)) _ops; - constructor(string name, string symbol, uint256 granularity, address[] defaultOperators) public { + constructor( + string name, + string symbol, + uint256 granularity, + address[] defaultOperators + ) public { require(granularity > 0); _name = name; _symbol = symbol; - _defaultOperatorsArray = defaultOperators; + _granularity = granularity; + _defaultOpsArray = defaultOperators; + for (uint i = 0; i < defaultOperators.length; i++) { + _defaultOps[defaultOperators[i]] = true; + } } /** @@ -57,7 +70,8 @@ contract ERC777 is IERC777 { /** * @dev Gets the token's granularity, - * i.e. the smallest number of tokens (in the basic unit) which may be minted, sent or burned at any time + * i.e. the smallest number of tokens (in the basic unit) + * which may be minted, sent or burned at any time * @return uint256 granularity */ function granularity() public view returns (uint256) { @@ -69,6 +83,93 @@ contract ERC777 is IERC777 { * @return address[] default operators */ function defaultOperators() public view returns (address[]) { - return _defaultOperatorsArray; + return _defaultOpsArray; + } + + /** + * @dev Authorize an operator for the sender + * @param operator address to be authorized as operator + */ + function authorizeOperator(address operator) public { + require(!isOperatorFor(operator, msg.sender)); + if (_defaultOps[operator]) { + _reAuthorizeDefaultOperator(operator); + } else _authorizeOperator(operator); + } + + /** + * @dev Revoke operator rights from one of the default operators + * @param operator address to revoke operator rights from + */ + function revokeOperator(address operator) public { + require(operator != msg.sender); + require(isOperatorFor(operator, msg.sender)); + + if (_defaultOps[operator]) { + _authorizeOperator(operator); + } else _reAuthorizeDefaultOperator(operator); + } + + /** + * @dev Indicate whether an address + * is an operator of the tokenHolder address + * @param operator address which may be an operator of tokenHolder + * @param tokenHolder address of a token holder which may have the operator + * address as an operator. + */ + function isOperatorFor( + address operator, + address tokenHolder + ) public view returns (bool) { + return + operator == tokenHolder || + _defaultOps[operator] && !_revokedDefaultOps[tokenHolder][operator] || + _ops[tokenHolder][operator]; + } + + + + /** + * @dev Authorize an operator for the sender + * @param operator address to be authorized as operator + */ + function _authorizeOperator(address operator) internal { + _ops[msg.sender][operator] = true; + emit AuthorizedOperator(operator, msg.sender); + } + + /** + * @dev Re-authorize a previously revoked default operator + * @param operator address to be re-authorized as operator + */ + function _reAuthorizeDefaultOperator(address operator) internal { + delete _revokedDefaultOps[msg.sender][operator]; + emit AuthorizedOperator(operator, msg.sender); + } + + /** + * @dev Revoke operator rights from one of the default operators + * @param operator address to revoke operator rights from + */ + function _revokeDefaultOperator(address operator) internal { + _revokedDefaultOps[msg.sender][operator]; + emit RevokedOperator(operator, msg.sender); + } + + /** + * @dev Revoke an operator for the sender + * @param operator address to revoke operator rights from + */ + function _revokeOperator(address operator) internal { + delete _ops[msg.sender][operator]; + emit RevokedOperator(operator, msg.sender); } + + function send(address to, uint256 amount, bytes data) external {} //TODO + + function operatorSend(address from, address to, uint256 amount, bytes data, bytes operatorData) external {} //TODO + + function burn(uint256 amount, bytes data) external {} //TODO + + function operatorBurn(address from, uint256 amount, bytes data, bytes operatorData) external {} //TODO } diff --git a/test/token/ERC777/ERC777.test.js b/test/token/ERC777/ERC777.test.js new file mode 100644 index 00000000000..50c31349e68 --- /dev/null +++ b/test/token/ERC777/ERC777.test.js @@ -0,0 +1,97 @@ +const {assertRevert} = require('../../helpers/assertRevert'); +const expectEvent = require('../../helpers/expectEvent'); + +const ERC777 = artifacts.require('ERC777'); + +const BigNumber = web3.BigNumber; + +require('chai') + .use(require('chai-bignumber')(BigNumber)) + .should(); + +contract('ERC777', function ([_, owner, recipient, anotherAccount]) { + const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; + + beforeEach(async function () { + this.token = await ERC777.new("Test777", "T77", 1, []); + }); + + describe('total supply', function () { + it('returns the total amount of tokens', async function () { + (await this.token.totalSupply()).should.be.bignumber.equal(0); //TODO update when minting is immplemented + }); + }); + + describe('balanceOf', function () { + describe('when the requested account has no tokens', function () { + it('returns zero', async function () { + (await this.token.balanceOf(anotherAccount)).should.be.bignumber.equal(0); + }); + }); + + describe('when the requested account has some tokens', function () { + it('returns the total amount of tokens', async function () { + (await this.token.balanceOf(owner)).should.be.bignumber.equal(0); //TODO update when minting is immplemented + }); + }); + }); + + describe('granularity', function () { + it('returns granularity amount of the token', async function () { + (await this.token.granularity()).should.be.bignumber.equal(1); //TODO update when minting is immplemented + }); + + it('value is set at creation time', async function () { + let token = await ERC777.new("Test777", "T77", 10, []); + let granularity = await token.granularity(); + granularity.should.be.bignumber.equal(10); + }); + + it('value is checked to be greater or equal to 1', async function () { + await assertRevert(ERC777.new("Test777", "T77", 0, [])); + }); + }); + + describe('defaultOperators', function () { + it('returns default operators of the token', async function () { + (await this.token.defaultOperators()).should.be.an('array').that.is.empty; //TODO update when minting is immplemented + }); + + it('value is set at creation time', async function () { + let token = await ERC777.new("Test777", "T77", 1, [recipient, anotherAccount]); + let defaultOps = await token.defaultOperators(); + defaultOps.should.be.an('array').that.has.all.members([recipient, anotherAccount]); + }); + }); + + describe('authorizeOperator', function () { + it('authorizes operators for holders', async function () { + let op = recipient; + let holder = owner; + + const {logs} = await this.token.authorizeOperator(op, {from: holder}); + console.log(logs); + expectEvent.inLogs(logs, 'AuthorizedOperator', { + operator: op, + tokenHolder: holder + }); + }); + + it('authorizes operators only when they are not already authorised', async function () { + let op = recipient; + let holder = owner; + + await this.token.authorizeOperator(op, {from: holder}); + await assertRevert(this.token.authorizeOperator(op, {from: holder})); + }); + + it('authorizes operators only when they are not pre-authorised by default', async function () { + let op = recipient; + let holder = owner; + let token = await ERC777.new("Test777", "T77", 1, [op]); + + await assertRevert(token.authorizeOperator(op, {from: holder})); + }); + //TODO more operator auth related tests + }); +}); From ebb4fad022ca80b9c3567d37e6cb7c04aaf5e822 Mon Sep 17 00:00:00 2001 From: etsvigun Date: Tue, 9 Oct 2018 21:20:56 +0300 Subject: [PATCH 03/64] ERC777 oprarator approvals fixes and tests --- contracts/token/ERC777/ERC777.sol | 6 +-- test/token/ERC777/ERC777.test.js | 77 +++++++++++++++++++++++++++++-- 2 files changed, 76 insertions(+), 7 deletions(-) diff --git a/contracts/token/ERC777/ERC777.sol b/contracts/token/ERC777/ERC777.sol index 5c5afde3e92..cd6ae7acb6d 100644 --- a/contracts/token/ERC777/ERC777.sol +++ b/contracts/token/ERC777/ERC777.sol @@ -106,8 +106,8 @@ contract ERC777 is IERC777 { require(isOperatorFor(operator, msg.sender)); if (_defaultOps[operator]) { - _authorizeOperator(operator); - } else _reAuthorizeDefaultOperator(operator); + _revokeDefaultOperator(operator); + } else _revokeOperator(operator); } /** @@ -152,7 +152,7 @@ contract ERC777 is IERC777 { * @param operator address to revoke operator rights from */ function _revokeDefaultOperator(address operator) internal { - _revokedDefaultOps[msg.sender][operator]; + _revokedDefaultOps[msg.sender][operator] = true; emit RevokedOperator(operator, msg.sender); } diff --git a/test/token/ERC777/ERC777.test.js b/test/token/ERC777/ERC777.test.js index 50c31349e68..565b644c798 100644 --- a/test/token/ERC777/ERC777.test.js +++ b/test/token/ERC777/ERC777.test.js @@ -65,12 +65,16 @@ contract('ERC777', function ([_, owner, recipient, anotherAccount]) { }); describe('authorizeOperator', function () { + beforeEach(async function () { + let op = recipient; + this.defaultOpsToken = await ERC777.new("Test777", "T77", 1, [op]) + }); + it('authorizes operators for holders', async function () { let op = recipient; let holder = owner; const {logs} = await this.token.authorizeOperator(op, {from: holder}); - console.log(logs); expectEvent.inLogs(logs, 'AuthorizedOperator', { operator: op, tokenHolder: holder @@ -88,10 +92,75 @@ contract('ERC777', function ([_, owner, recipient, anotherAccount]) { it('authorizes operators only when they are not pre-authorised by default', async function () { let op = recipient; let holder = owner; - let token = await ERC777.new("Test777", "T77", 1, [op]); - await assertRevert(token.authorizeOperator(op, {from: holder})); + await assertRevert(this.defaultOpsToken.authorizeOperator(op, {from: holder})); + }); + + it('re-authorizes previously revoked default operators', async function () { + let op = recipient; + let holder = owner; + + await assertRevert(this.defaultOpsToken.authorizeOperator(op, {from: holder})); + }); + + it('authorizes operators only when they are not pre-authorised by default', async function () { + let op = recipient; + let holder = owner; + + await this.defaultOpsToken.revokeOperator(op, {from: holder}); + + const {logs} = await this.defaultOpsToken.authorizeOperator(op, {from: holder}); + expectEvent.inLogs(logs, 'AuthorizedOperator', { + operator: op, + tokenHolder: holder + }); + }); + }); + + describe('revokeOperator', function () { + beforeEach(async function () { + let op = recipient; + this.defaultOpsToken = await ERC777.new("Test777", "T77", 1, [op]) + }); + + it('revokes operators for holders', async function () { + let op = recipient; + let holder = owner; + + await this.token.authorizeOperator(op, {from: holder}); + + const {logs} = await this.token.revokeOperator(op, {from: holder}); + expectEvent.inLogs(logs, 'RevokedOperator', { + operator: op, + tokenHolder: holder + }); + }); + + it('revokes operators only when they are authorised', async function () { + let op = recipient; + let holder = owner; + + await assertRevert(this.token.revokeOperator(op, {from: holder})); + }); + + it('revokes pre-authorised default operators', async function () { + let op = recipient; + let holder = owner; + + const {logs} = await this.defaultOpsToken.revokeOperator(op, {from: holder}); + expectEvent.inLogs(logs, 'RevokedOperator', { + operator: op, + tokenHolder: holder + }); + }); + + it('revokes pre-authorised default operators only when they were not previously revoked', async function () { + let op = recipient; + let holder = owner; + + await this.defaultOpsToken.revokeOperator(op, {from: holder}); + + await assertRevert(this.defaultOpsToken.revokeOperator(op, {from: holder})); }); - //TODO more operator auth related tests }); }); From 73ac6af94fe3efe242b97f8f00a1cb686a3a7cdc Mon Sep 17 00:00:00 2001 From: Bertrand Masius Date: Wed, 24 Oct 2018 06:47:55 +0200 Subject: [PATCH 04/64] IERC777 send and receive with ERC820 (#1159) --- contracts/introspection/IERC820.sol | 12 +++ contracts/token/ERC777/ERC777.sol | 96 ++++++++++++++++++- .../token/ERC777/IERC777TokensRecipient.sol | 16 ++++ .../token/ERC777/IERC777TokensSender.sol | 16 ++++ 4 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 contracts/introspection/IERC820.sol create mode 100644 contracts/token/ERC777/IERC777TokensRecipient.sol create mode 100644 contracts/token/ERC777/IERC777TokensSender.sol diff --git a/contracts/introspection/IERC820.sol b/contracts/introspection/IERC820.sol new file mode 100644 index 00000000000..db0f775317f --- /dev/null +++ b/contracts/introspection/IERC820.sol @@ -0,0 +1,12 @@ +pragma solidity ^0.4.24; + +/** + * @title IERC820 + * @dev https://eips.ethereum.org/EIPS/eip-820 + */ +interface IERC820 { + function setInterfaceImplementer(address _addr, bytes32 _interfaceHash, address _implementer) external; + function getInterfaceImplementer(address _addr, bytes32 _interfaceHash) external view returns (address); + function setManager(address _addr, address _newManager) external; + function getManager(address _addr) external view returns(address); +} diff --git a/contracts/token/ERC777/ERC777.sol b/contracts/token/ERC777/ERC777.sol index cd6ae7acb6d..32bded64b32 100644 --- a/contracts/token/ERC777/ERC777.sol +++ b/contracts/token/ERC777/ERC777.sol @@ -1,7 +1,10 @@ pragma solidity ^0.4.24; import "./IERC777.sol"; +import "./IERC777TokensRecipient.sol"; +import "./IERC777TokensSender.sol"; import "../../math/SafeMath.sol"; +import "../../introspection/IERC820.sol"; contract ERC777 is IERC777 { @@ -18,6 +21,11 @@ contract ERC777 is IERC777 { uint256 private _granularity; address[] private _defaultOpsArray; + + IERC820 constant ERC820Registry = IERC820(0x820A8Cfd018b159837d50656c49d28983f18f33c); + bytes32 constant sendHash = keccak256(abi.encodePacked('tokensToSend')); + bytes32 constant receivedHash = keccak256(abi.encodePacked('tokensReceived')); + mapping(address => bool) _defaultOps; mapping(address => mapping(address => bool)) _revokedDefaultOps; mapping(address => mapping(address => bool)) _ops; @@ -165,9 +173,93 @@ contract ERC777 is IERC777 { emit RevokedOperator(operator, msg.sender); } - function send(address to, uint256 amount, bytes data) external {} //TODO + /** + * @dev Send tokens without checking operator authorization + * @param operator address operator requesting the transfer + * @param from address token holder address + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param userData bytes extra information provided by the token holder (if any) + * @param operatorData bytes extra information provided by the operator (if any) + */ + function _send( + address operator, + address from, + address to, + uint256 amount, + bytes userData, + bytes operatorData + ) + private + { + require((amount % _granularity) == 0); + + // Call from.tokensToSend(...) if it is registered + address implementer = ERC820Registry.getInterfaceImplementer(from, sendHash); + if (implementer != address(0)) { + IERC777TokensSender(implementer).tokensToSend( + operator, + from, + to, + amount, + userData, + operatorData + ); + } + + // Update state variables + _balances[from] = _balances[from].sub(amount); + _balances[to] = _balances[to].add(amount); + + // Call to.tokensReceived(...) if it is registered + implementer = ERC820Registry.getInterfaceImplementer(to, receivedHash); + if (implementer != address(0)) { + IERC777TokensRecipient(implementer).tokensReceived( + operator, + from, + to, + amount, + userData, + operatorData + ); + } - function operatorSend(address from, address to, uint256 amount, bytes data, bytes operatorData) external {} //TODO + emit Sent(msg.sender, from, to, amount, userData, operatorData); + } + + /** + * @dev Send the amount of tokens from the address msg.sender to the address to + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param data bytes information attached to the send, and intended for the recipient (to) + */ + function send(address to, uint256 amount, bytes data) external { + require(to != address(0)); + _send(msg.sender, msg.sender, to, amount, data, ""); + } + + /** + * @dev Send the amount of tokens on behalf of the address from to the address to + * @param from address token holder address. Set to 0x0 to use msg.sender as token holder + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param data bytes information attached to the send, and intended for the recipient (to) + * @param operatorData bytes extra information provided by the operator (if any) + */ + function operatorSend( + address from, + address to, + uint256 amount, + bytes data, + bytes operatorData + ) + external + { + require(to != address(0)); + address holder = from == address(0) ? msg.sender : from; + require(isOperatorFor(msg.sender, holder)); + _send(msg.sender, holder, to, amount, data, operatorData); + } function burn(uint256 amount, bytes data) external {} //TODO diff --git a/contracts/token/ERC777/IERC777TokensRecipient.sol b/contracts/token/ERC777/IERC777TokensRecipient.sol new file mode 100644 index 00000000000..ce7e11d3e34 --- /dev/null +++ b/contracts/token/ERC777/IERC777TokensRecipient.sol @@ -0,0 +1,16 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +// solhint-disable-next-line compiler-fixed +pragma solidity ^0.4.24; + +interface IERC777TokensRecipient { + function tokensReceived( + address operator, + address from, + address to, + uint amount, + bytes userData, + bytes operatorData + ) external; +} diff --git a/contracts/token/ERC777/IERC777TokensSender.sol b/contracts/token/ERC777/IERC777TokensSender.sol new file mode 100644 index 00000000000..54570a81932 --- /dev/null +++ b/contracts/token/ERC777/IERC777TokensSender.sol @@ -0,0 +1,16 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +// solhint-disable-next-line compiler-fixed +pragma solidity ^0.4.24; + +interface IERC777TokensSender { + function tokensToSend( + address operator, + address from, + address to, + uint amount, + bytes userData, + bytes operatorData + ) external; +} From 9a6ed299ab7b1139bfc05c79da28a9f48964357c Mon Sep 17 00:00:00 2001 From: Bertrand Masius Date: Sat, 27 Oct 2018 12:41:51 +0200 Subject: [PATCH 05/64] ERC777 Add burn functions and fix send functions (#1159) --- contracts/token/ERC777/ERC777.sol | 118 ++++++++++++++-------- contracts/token/ERC777/ERC777Burnable.sol | 29 ++++++ contracts/token/ERC777/IERC777.sol | 4 - 3 files changed, 106 insertions(+), 45 deletions(-) create mode 100644 contracts/token/ERC777/ERC777Burnable.sol diff --git a/contracts/token/ERC777/ERC777.sol b/contracts/token/ERC777/ERC777.sol index 32bded64b32..62b36f09953 100644 --- a/contracts/token/ERC777/ERC777.sol +++ b/contracts/token/ERC777/ERC777.sol @@ -7,6 +7,9 @@ import "../../math/SafeMath.sol"; import "../../introspection/IERC820.sol"; +@title ERC777 token implementation +@author etsvigun , Bertrand Masius +@dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-777.md contract ERC777 is IERC777 { using SafeMath for uint256; @@ -22,7 +25,7 @@ contract ERC777 is IERC777 { address[] private _defaultOpsArray; - IERC820 constant ERC820Registry = IERC820(0x820A8Cfd018b159837d50656c49d28983f18f33c); + IERC820 constant ERC820Registry = IERC820(0x820A8Cfd018b159837d50656c49d28983f18f33c); //TODO: move to other contract bytes32 constant sendHash = keccak256(abi.encodePacked('tokensToSend')); bytes32 constant receivedHash = keccak256(abi.encodePacked('tokensReceived')); @@ -135,7 +138,36 @@ contract ERC777 is IERC777 { _ops[tokenHolder][operator]; } + /** + * @dev Send the amount of tokens from the address msg.sender to the address to + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param data bytes information attached to the send, and intended for the recipient (to) + */ + function send(address to, uint256 amount, bytes data) external { + _send(msg.sender, msg.sender, to, amount, data, ""); + } + /** + * @dev Send the amount of tokens on behalf of the address from to the address to + * @param from address token holder address. Set to 0x0 to use msg.sender as token holder + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param data bytes information attached to the send, and intended for the recipient (to) + * @param operatorData bytes extra information provided by the operator (if any) + */ + function operatorSend( + address from, + address to, + uint256 amount, + bytes data, + bytes operatorData + ) + external + { + address holder = from == address(0) ? msg.sender : from; + _send(msg.sender, holder, to, amount, data, operatorData); + } /** * @dev Authorize an operator for the sender @@ -173,8 +205,46 @@ contract ERC777 is IERC777 { emit RevokedOperator(operator, msg.sender); } + /** + * @dev Burn tokens + * @param operator address operator requesting the operation + * @param from address token holder address + * @param amount uint256 amount of tokens to burn + * @param operatorData bytes extra information provided by the operator (if any) + */ + function _burn( + address operator, + address from, + uint256 amount, + bytes operatorData + ) + internal + { + require(from != address(0)); + require(isOperatorFor(msg.sender, from)); + + // Call from.tokensToSend(...) if it is registered + address implementer = ERC820Registry.getInterfaceImplementer(from, sendHash); + if (implementer != address(0)) { + IERC777TokensSender(implementer).tokensToSend( + operator, + from, + address(0), + amount, + "", + operatorData + ); + } + + // Update state variables + _balances[from] = _balances[from].sub(amount); + require((_balances[from] % _granularity) == 0); + + emit Burned(msg.sender, from, amount, operatorData); + } + /** - * @dev Send tokens without checking operator authorization + * @dev Send tokens * @param operator address operator requesting the transfer * @param from address token holder address * @param to address recipient address @@ -192,7 +262,9 @@ contract ERC777 is IERC777 { ) private { - require((amount % _granularity) == 0); + require(from != address(0)); + require(to != address(0)); + require(isOperatorFor(msg.sender, from)); // Call from.tokensToSend(...) if it is registered address implementer = ERC820Registry.getInterfaceImplementer(from, sendHash); @@ -210,6 +282,8 @@ contract ERC777 is IERC777 { // Update state variables _balances[from] = _balances[from].sub(amount); _balances[to] = _balances[to].add(amount); + require((_balances[from] % _granularity) == 0); + require((_balances[to] % _granularity) == 0); // Call to.tokensReceived(...) if it is registered implementer = ERC820Registry.getInterfaceImplementer(to, receivedHash); @@ -226,42 +300,4 @@ contract ERC777 is IERC777 { emit Sent(msg.sender, from, to, amount, userData, operatorData); } - - /** - * @dev Send the amount of tokens from the address msg.sender to the address to - * @param to address recipient address - * @param amount uint256 amount of tokens to transfer - * @param data bytes information attached to the send, and intended for the recipient (to) - */ - function send(address to, uint256 amount, bytes data) external { - require(to != address(0)); - _send(msg.sender, msg.sender, to, amount, data, ""); - } - - /** - * @dev Send the amount of tokens on behalf of the address from to the address to - * @param from address token holder address. Set to 0x0 to use msg.sender as token holder - * @param to address recipient address - * @param amount uint256 amount of tokens to transfer - * @param data bytes information attached to the send, and intended for the recipient (to) - * @param operatorData bytes extra information provided by the operator (if any) - */ - function operatorSend( - address from, - address to, - uint256 amount, - bytes data, - bytes operatorData - ) - external - { - require(to != address(0)); - address holder = from == address(0) ? msg.sender : from; - require(isOperatorFor(msg.sender, holder)); - _send(msg.sender, holder, to, amount, data, operatorData); - } - - function burn(uint256 amount, bytes data) external {} //TODO - - function operatorBurn(address from, uint256 amount, bytes data, bytes operatorData) external {} //TODO } diff --git a/contracts/token/ERC777/ERC777Burnable.sol b/contracts/token/ERC777/ERC777Burnable.sol new file mode 100644 index 00000000000..dd7163a02b8 --- /dev/null +++ b/contracts/token/ERC777/ERC777Burnable.sol @@ -0,0 +1,29 @@ +pragma solidity ^0.4.24; + +import "./ERC777.sol"; + + +@title ERC777 burnable token implementation +@author Bertrand Masius +@dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-777.md +contract ERC777Burnable is ERC777 { + + /** + * @dev Burn the amount of tokens from the address msg.sender + * @param amount uint256 amount of tokens to transfer + */ + function burn(uint256 amount) external { + _burn(msg.sender, msg.sender, amount, ""); + } + + /** + * @dev Burn the amount of tokens on behalf of the address from + * @param from address token holder address. Set to 0x0 to use msg.sender as token holder + * @param amount uint256 amount of tokens to transfer + * @param operatorData bytes extra information provided by the operator (if any) + */ + function operatorBurn(address from, uint256 amount, bytes operatorData) external { + address holder = from == address(0) ? msg.sender : from; + _burn(msg.sender, holder, amount, operatorData); + } +} diff --git a/contracts/token/ERC777/IERC777.sol b/contracts/token/ERC777/IERC777.sol index ee5998d2720..939392f8b88 100644 --- a/contracts/token/ERC777/IERC777.sol +++ b/contracts/token/ERC777/IERC777.sol @@ -27,10 +27,6 @@ interface IERC777 { function operatorSend(address from, address to, uint256 amount, bytes data, bytes operatorData) external; - function burn(uint256 amount, bytes data) external; - - function operatorBurn(address from, uint256 amount, bytes data, bytes operatorData) external; - event Sent( address indexed operator, address indexed from, From 2fc7b4d5662c627cd06f75b1f2ec1a5c236775f5 Mon Sep 17 00:00:00 2001 From: Bertrand Masius Date: Sat, 3 Nov 2018 22:50:00 +0100 Subject: [PATCH 06/64] ERC777 Make expectEvent compatible with web3.js 1.0 (#1159) --- test/helpers/expectEvent.js | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/test/helpers/expectEvent.js b/test/helpers/expectEvent.js index b857b6636bf..81eea675225 100644 --- a/test/helpers/expectEvent.js +++ b/test/helpers/expectEvent.js @@ -1,8 +1,21 @@ -const BigNumber = web3.BigNumber; +const BigNumber = web3.utils.BN; const should = require('chai') .use(require('chai-bignumber')(BigNumber)) .should(); +function inEvents (events, eventName, eventArgs = {}) { + event = Object.values(events).find(function (e) { + if (e.event === eventName) { + for (const [k, v] of Object.entries(eventArgs)) { + contains(e.returnValues, k, v); + } + return true; + } + }); + should.exist(event); + return event; +} + function inLogs (logs, eventName, eventArgs = {}) { const event = logs.find(function (e) { if (e.event === eventName) { @@ -22,8 +35,11 @@ async function inTransaction (tx, eventName, eventArgs = {}) { } function contains (args, key, value) { - if (isBigNumber(args[key])) { - args[key].should.be.bignumber.equal(value); + if (args[key] == null) { + value.should.be.equal("0x00"); + } + else if (isBigNumber(args[key])) { + args[key].toString().should.be.equal(value); } else { args[key].should.be.equal(value); } @@ -36,6 +52,7 @@ function isBigNumber (object) { } module.exports = { + inEvents, inLogs, inTransaction, }; From 5920482fa8eb28442e97d97ac92eea7789b16bc3 Mon Sep 17 00:00:00 2001 From: Bertrand Masius Date: Sat, 3 Nov 2018 22:53:08 +0100 Subject: [PATCH 07/64] ERC777 Add ERC820 deploy script (#1159) --- contracts/introspection/ERC820Client.sol | 25 ++++++++++++++++++++++++ test/introspection/ERC820Deploy.js | 17 ++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 contracts/introspection/ERC820Client.sol create mode 100644 test/introspection/ERC820Deploy.js diff --git a/contracts/introspection/ERC820Client.sol b/contracts/introspection/ERC820Client.sol new file mode 100644 index 00000000000..c25685cd9c5 --- /dev/null +++ b/contracts/introspection/ERC820Client.sol @@ -0,0 +1,25 @@ +pragma solidity ^0.4.24; + +import "./IERC820.sol"; + +/** + * @title ERC820 client implementation + * @dev https://eips.ethereum.org/EIPS/eip-820 + * @author Bertrand Masius + */ +contract ERC820Client { + + IERC820 private _erc820 = IERC820(0x820A8Cfd018b159837d50656c49d28983f18f33c); + + function getInterfaceImplementer(address addr, bytes32 hash) internal view returns(address) { + return _erc820.getInterfaceImplementer(addr, hash); + } + + function setInterfaceImplementer(address addr, bytes32 hash, address implementer) internal { + _erc820.setInterfaceImplementer(addr, hash, implementer); + } + + function getERC820Registry() public view returns(address) { + return address(_erc820); + } +} diff --git a/test/introspection/ERC820Deploy.js b/test/introspection/ERC820Deploy.js new file mode 100644 index 00000000000..10c9cb7ee2f --- /dev/null +++ b/test/introspection/ERC820Deploy.js @@ -0,0 +1,17 @@ +const BN = web3.utils.BN; +const { sendEther } = require('../helpers/sendTransaction'); + +const ERC820Deploy = async function (owner) { + const deployAccount = "0xd80816570aD09e44339042b36d9A068Aba0D340F"; + const deployTx = "0xf90a2a8085174876e800830c35008080b909d7608060405234801561001057600080fd5b506109b7806100206000396000f30060806040526004361061008d5763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166329965a1d81146100925780633d584063146100bf5780635df8122f146100fc57806365ba36c114610123578063a41e7d5114610155578063aabbb8ca14610183578063b7056765146101a7578063f712f3e8146101e9575b600080fd5b34801561009e57600080fd5b506100bd600160a060020a036004358116906024359060443516610217565b005b3480156100cb57600080fd5b506100e0600160a060020a0360043516610512565b60408051600160a060020a039092168252519081900360200190f35b34801561010857600080fd5b506100bd600160a060020a036004358116906024351661055e565b34801561012f57600080fd5b506101436004803560248101910135610655565b60408051918252519081900360200190f35b34801561016157600080fd5b506100bd600160a060020a0360043516600160e060020a0319602435166106e3565b34801561018f57600080fd5b506100e0600160a060020a036004351660243561076d565b3480156101b357600080fd5b506101d5600160a060020a0360043516600160e060020a0319602435166107e7565b604080519115158252519081900360200190f35b3480156101f557600080fd5b506101d5600160a060020a0360043516600160e060020a03196024351661089c565b6000600160a060020a0384161561022e5783610230565b335b90503361023c82610512565b600160a060020a03161461029a576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b6102a38361091c565b156102f8576040805160e560020a62461bcd02815260206004820152601960248201527f4d757374206e6f74206265206120455243313635206861736800000000000000604482015290519081900360640190fd5b600160a060020a038216158015906103195750600160a060020a0382163314155b156104a15760405160200180807f4552433832305f4143434550545f4d414749430000000000000000000000000081525060130190506040516020818303038152906040526040518082805190602001908083835b6020831061038d5780518252601f19909201916020918201910161036e565b51815160209384036101000a6000190180199092169116179052604080519290940182900382207f249cb3fa000000000000000000000000000000000000000000000000000000008352600483018a9052600160a060020a0388811660248501529451909650938816945063249cb3fa936044808401945091929091908290030181600087803b15801561042057600080fd5b505af1158015610434573d6000803e3d6000fd5b505050506040513d602081101561044a57600080fd5b5051146104a1576040805160e560020a62461bcd02815260206004820181905260248201527f446f6573206e6f7420696d706c656d656e742074686520696e74657266616365604482015290519081900360640190fd5b600160a060020a03818116600081815260208181526040808320888452909152808220805473ffffffffffffffffffffffffffffffffffffffff19169487169485179055518692917f93baa6efbd2244243bfee6ce4cfdd1d04fc4c0e9a786abd3a41313bd352db15391a450505050565b600160a060020a03808216600090815260016020526040812054909116151561053c575080610559565b50600160a060020a03808216600090815260016020526040902054165b919050565b3361056883610512565b600160a060020a0316146105c6576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b81600160a060020a031681600160a060020a0316146105e557806105e8565b60005b600160a060020a03838116600081815260016020526040808220805473ffffffffffffffffffffffffffffffffffffffff19169585169590951790945592519184169290917f605c2dbf762e5f7d60a546d42e7205dcb1b011ebc62a61736a57c9089d3a43509190a35050565b60008282604051602001808383808284378201915050925050506040516020818303038152906040526040518082805190602001908083835b602083106106ad5780518252601f19909201916020918201910161068e565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902090505b92915050565b6106ed82826107e7565b6106f85760006106fa565b815b600160a060020a03928316600081815260208181526040808320600160e060020a031996909616808452958252808320805473ffffffffffffffffffffffffffffffffffffffff19169590971694909417909555908152600284528181209281529190925220805460ff19166001179055565b60008080600160a060020a038516156107865784610788565b335b91506107938461091c565b156107b85750826107a4828261089c565b6107af5760006107b1565b815b92506107df565b600160a060020a038083166000908152602081815260408083208884529091529020541692505b505092915050565b60008080610815857f01ffc9a70000000000000000000000000000000000000000000000000000000061093e565b9092509050811580610825575080155b1561083357600092506107df565b61084585600160e060020a031961093e565b909250905081158061085657508015155b1561086457600092506107df565b61086e858561093e565b90925090506001821480156108835750806001145b1561089157600192506107df565b506000949350505050565b600160a060020a0382166000908152600260209081526040808320600160e060020a03198516845290915281205460ff1615156108e4576108dd83836107e7565b90506106dd565b50600160a060020a03808316600081815260208181526040808320600160e060020a0319871684529091529020549091161492915050565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff161590565b6040517f01ffc9a7000000000000000000000000000000000000000000000000000000008082526004820183905260009182919060208160088189617530fa9051909690955093505050505600a165627a7a72305820566272f4bea75dbff631713d256c984d562f55a646afc8bc1c01f2d919a038f100291ba08208208208208208208208208208208208208208208208208208208208208200a00820820820820820820820820820820820820820820820820820820820820820"; + + // send 0.08 ether to deployment account + sendEther(owner, deployAccount, web3.utils.toWei("0.08",'ether')); + // create ERC820 contract + let address = (await web3.eth.sendSignedTransaction(deployTx)).contractAddress; + return address; +}; + +module.exports = { + ERC820Deploy, +}; From fc63684ebd7996c8f5367827234d380396752733 Mon Sep 17 00:00:00 2001 From: Bertrand Masius Date: Sat, 3 Nov 2018 22:54:44 +0100 Subject: [PATCH 08/64] ERC777 Complete implementation of ERC777 (#1159) This implementation conforms to the current EIP --- contracts/mocks/ERC777ReceiverMock.sol | 57 ++ contracts/mocks/ERC777SenderMock.sol | 87 +++ contracts/token/ERC777/ERC777.sol | 321 +-------- contracts/token/ERC777/ERC777Base.sol | 429 ++++++++++++ contracts/token/ERC777/ERC777Burnable.sol | 12 +- contracts/token/ERC777/IERC777.sol | 4 + test/token/ERC777/ERC777.test.js | 803 +++++++++++++++++++--- 7 files changed, 1336 insertions(+), 377 deletions(-) create mode 100644 contracts/mocks/ERC777ReceiverMock.sol create mode 100644 contracts/mocks/ERC777SenderMock.sol create mode 100644 contracts/token/ERC777/ERC777Base.sol diff --git a/contracts/mocks/ERC777ReceiverMock.sol b/contracts/mocks/ERC777ReceiverMock.sol new file mode 100644 index 00000000000..f1e8ebe4dcc --- /dev/null +++ b/contracts/mocks/ERC777ReceiverMock.sol @@ -0,0 +1,57 @@ +pragma solidity ^0.4.24; + +import "../token/ERC777/IERC777TokensRecipient.sol"; +import "../introspection/ERC820Client.sol"; + +/** + * @title ERC777TokensRecipientMock a contract that implements tokensReceived() hook + * @author Bertrand Masius + * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-777.md + */ +contract ERC777ReceiverMock is IERC777TokensRecipient, ERC820Client { + + event TokensReceived( + address indexed operator, + address indexed from, + address indexed to, + uint256 amount, + bytes data, + bytes operatorData + ); + + constructor(bool setInterface) public { + // register interface + if (setInterface) { + setInterfaceImplementer(address(this), keccak256("ERC777TokensRecipient"), address(this)); + } + } + + /** + * @dev tokensReceived() hook + * @param operator address operator requesting the transfer + * @param from address token holder address + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param userData bytes extra information provided by the token holder (if any) + * @param operatorData bytes extra information provided by the operator (if any) + */ + function tokensReceived( + address operator, + address from, + address to, + uint256 amount, + bytes userData, + bytes operatorData + ) + external + { + emit TokensReceived( + operator, + from, + to, + amount, + userData, + operatorData + ); + } +} diff --git a/contracts/mocks/ERC777SenderMock.sol b/contracts/mocks/ERC777SenderMock.sol new file mode 100644 index 00000000000..7745974325b --- /dev/null +++ b/contracts/mocks/ERC777SenderMock.sol @@ -0,0 +1,87 @@ +pragma solidity ^0.4.24; + +import "../token/ERC777/IERC777.sol"; +import "../token/ERC777/IERC777TokensSender.sol"; +import "../introspection/ERC820Client.sol"; + +/** + * @title ERC777TokensSenderMock a contract that implements tokensToSend() hook + * @author Bertrand Masius + * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-777.md + */ +contract ERC777SenderMock is IERC777TokensSender, ERC820Client { + + address private _erc777; + + event TokensToSend( + address indexed operator, + address indexed from, + address indexed to, + uint256 amount, + bytes data, + bytes operatorData + ); + + constructor(bool setInterface, address erc777) public { + _erc777 = erc777; + // register interface + if (setInterface) { + setInterfaceImplementer(address(this), keccak256("ERC777TokensSender"), address(this)); + } + } + + /** + * @dev Send an amount of tokens from this contract to recipient + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param data bytes extra information provided by the token holder (if any) + */ + function sendTokens(address to, uint amount, bytes data) public { + IERC777(_erc777).send(to, amount, data); + } + + /** + * @dev Burn an amount of tokens from this contract + * @param amount uint256 amount of tokens to transfer + */ + function burnTokens(uint amount) public { + IERC777(_erc777).burn(amount); + } + + /** + * @dev Authorize an operator + * @param operator address of operator + */ + function authorizeOperator(address operator) public { + IERC777(_erc777).authorizeOperator(operator); + } + + /** + * @dev tokensSender() hook + * @param operator address operator requesting the transfer + * @param from address token holder address + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param userData bytes extra information provided by the token holder (if any) + * @param operatorData bytes extra information provided by the operator (if any) + */ + function tokensToSend( + address operator, + address from, + address to, + uint256 amount, + bytes userData, + bytes operatorData + ) + external + { + emit TokensToSend( + operator, + from, + to, + amount, + userData, + operatorData + ); + } +} diff --git a/contracts/token/ERC777/ERC777.sol b/contracts/token/ERC777/ERC777.sol index 62b36f09953..15c4fac04b9 100644 --- a/contracts/token/ERC777/ERC777.sol +++ b/contracts/token/ERC777/ERC777.sol @@ -1,303 +1,40 @@ pragma solidity ^0.4.24; -import "./IERC777.sol"; -import "./IERC777TokensRecipient.sol"; -import "./IERC777TokensSender.sol"; -import "../../math/SafeMath.sol"; -import "../../introspection/IERC820.sol"; - - -@title ERC777 token implementation -@author etsvigun , Bertrand Masius -@dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-777.md -contract ERC777 is IERC777 { - using SafeMath for uint256; - - string private _name; - - string private _symbol; - - mapping(address => uint256) private _balances; - - uint256 private _totalSupply; - - uint256 private _granularity; - - address[] private _defaultOpsArray; - - IERC820 constant ERC820Registry = IERC820(0x820A8Cfd018b159837d50656c49d28983f18f33c); //TODO: move to other contract - bytes32 constant sendHash = keccak256(abi.encodePacked('tokensToSend')); - bytes32 constant receivedHash = keccak256(abi.encodePacked('tokensReceived')); - - mapping(address => bool) _defaultOps; - mapping(address => mapping(address => bool)) _revokedDefaultOps; - mapping(address => mapping(address => bool)) _ops; - +import "./ERC777Base.sol"; + + +/** + * @title ERC777 token implementation + * @notice mint an amount of tokens given to msg.sender + * @author Bertrand Masius + * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-777.md + */ +contract ERC777 is ERC777Base { +/* + * @dev constructor + * @param name name of the token + * @param symbol symbol of the token + * @param granularity granularity of token + * @param defaultOperators array of default operators address + * @param initialSupply amount of tokens given to msg.sender + * @param data bytes information attached to the send, and intended for the recipient (to) + * @param operatorData bytes extra information provided by the operator (if any) + */ constructor( string name, string symbol, uint256 granularity, - address[] defaultOperators - ) public { - require(granularity > 0); - _name = name; - _symbol = symbol; - _granularity = granularity; - _defaultOpsArray = defaultOperators; - for (uint i = 0; i < defaultOperators.length; i++) { - _defaultOps[defaultOperators[i]] = true; - } - } - - /** - * @return the name of the token. - */ - function name() public view returns (string) { - return _name; - } - - /** - * @return the symbol of the token. - */ - function symbol() public view returns (string) { - return _symbol; - } - - /** - * @dev Total number of tokens in existence - */ - function totalSupply() public view returns (uint256) { - return _totalSupply; - } - - /** - * @dev Gets the balance of the specified address. - * @param tokenHolder The address to query the balance of. - * @return uint256 representing the amount owned by the specified address. - */ - function balanceOf(address tokenHolder) public view returns (uint256) { - return _balances[tokenHolder]; - } - - /** - * @dev Gets the token's granularity, - * i.e. the smallest number of tokens (in the basic unit) - * which may be minted, sent or burned at any time - * @return uint256 granularity - */ - function granularity() public view returns (uint256) { - return _granularity; - } - - /** - * @dev Get the list of default operators as defined by the token contract. - * @return address[] default operators - */ - function defaultOperators() public view returns (address[]) { - return _defaultOpsArray; - } - - /** - * @dev Authorize an operator for the sender - * @param operator address to be authorized as operator - */ - function authorizeOperator(address operator) public { - require(!isOperatorFor(operator, msg.sender)); - if (_defaultOps[operator]) { - _reAuthorizeDefaultOperator(operator); - } else _authorizeOperator(operator); - } - - /** - * @dev Revoke operator rights from one of the default operators - * @param operator address to revoke operator rights from - */ - function revokeOperator(address operator) public { - require(operator != msg.sender); - require(isOperatorFor(operator, msg.sender)); - - if (_defaultOps[operator]) { - _revokeDefaultOperator(operator); - } else _revokeOperator(operator); - } - - /** - * @dev Indicate whether an address - * is an operator of the tokenHolder address - * @param operator address which may be an operator of tokenHolder - * @param tokenHolder address of a token holder which may have the operator - * address as an operator. - */ - function isOperatorFor( - address operator, - address tokenHolder - ) public view returns (bool) { - return - operator == tokenHolder || - _defaultOps[operator] && !_revokedDefaultOps[tokenHolder][operator] || - _ops[tokenHolder][operator]; - } - - /** - * @dev Send the amount of tokens from the address msg.sender to the address to - * @param to address recipient address - * @param amount uint256 amount of tokens to transfer - * @param data bytes information attached to the send, and intended for the recipient (to) - */ - function send(address to, uint256 amount, bytes data) external { - _send(msg.sender, msg.sender, to, amount, data, ""); - } - - /** - * @dev Send the amount of tokens on behalf of the address from to the address to - * @param from address token holder address. Set to 0x0 to use msg.sender as token holder - * @param to address recipient address - * @param amount uint256 amount of tokens to transfer - * @param data bytes information attached to the send, and intended for the recipient (to) - * @param operatorData bytes extra information provided by the operator (if any) - */ - function operatorSend( - address from, - address to, - uint256 amount, + address[] defaultOperators, + uint256 initialSupply, bytes data, bytes operatorData ) - external - { - address holder = from == address(0) ? msg.sender : from; - _send(msg.sender, holder, to, amount, data, operatorData); - } - - /** - * @dev Authorize an operator for the sender - * @param operator address to be authorized as operator - */ - function _authorizeOperator(address operator) internal { - _ops[msg.sender][operator] = true; - emit AuthorizedOperator(operator, msg.sender); - } - - /** - * @dev Re-authorize a previously revoked default operator - * @param operator address to be re-authorized as operator - */ - function _reAuthorizeDefaultOperator(address operator) internal { - delete _revokedDefaultOps[msg.sender][operator]; - emit AuthorizedOperator(operator, msg.sender); - } - - /** - * @dev Revoke operator rights from one of the default operators - * @param operator address to revoke operator rights from - */ - function _revokeDefaultOperator(address operator) internal { - _revokedDefaultOps[msg.sender][operator] = true; - emit RevokedOperator(operator, msg.sender); - } - - /** - * @dev Revoke an operator for the sender - * @param operator address to revoke operator rights from - */ - function _revokeOperator(address operator) internal { - delete _ops[msg.sender][operator]; - emit RevokedOperator(operator, msg.sender); - } - - /** - * @dev Burn tokens - * @param operator address operator requesting the operation - * @param from address token holder address - * @param amount uint256 amount of tokens to burn - * @param operatorData bytes extra information provided by the operator (if any) - */ - function _burn( - address operator, - address from, - uint256 amount, - bytes operatorData - ) - internal - { - require(from != address(0)); - require(isOperatorFor(msg.sender, from)); - - // Call from.tokensToSend(...) if it is registered - address implementer = ERC820Registry.getInterfaceImplementer(from, sendHash); - if (implementer != address(0)) { - IERC777TokensSender(implementer).tokensToSend( - operator, - from, - address(0), - amount, - "", - operatorData - ); - } - - // Update state variables - _balances[from] = _balances[from].sub(amount); - require((_balances[from] % _granularity) == 0); - - emit Burned(msg.sender, from, amount, operatorData); - } - - /** - * @dev Send tokens - * @param operator address operator requesting the transfer - * @param from address token holder address - * @param to address recipient address - * @param amount uint256 amount of tokens to transfer - * @param userData bytes extra information provided by the token holder (if any) - * @param operatorData bytes extra information provided by the operator (if any) - */ - function _send( - address operator, - address from, - address to, - uint256 amount, - bytes userData, - bytes operatorData - ) - private - { - require(from != address(0)); - require(to != address(0)); - require(isOperatorFor(msg.sender, from)); - - // Call from.tokensToSend(...) if it is registered - address implementer = ERC820Registry.getInterfaceImplementer(from, sendHash); - if (implementer != address(0)) { - IERC777TokensSender(implementer).tokensToSend( - operator, - from, - to, - amount, - userData, - operatorData - ); - } - - // Update state variables - _balances[from] = _balances[from].sub(amount); - _balances[to] = _balances[to].add(amount); - require((_balances[from] % _granularity) == 0); - require((_balances[to] % _granularity) == 0); - - // Call to.tokensReceived(...) if it is registered - implementer = ERC820Registry.getInterfaceImplementer(to, receivedHash); - if (implementer != address(0)) { - IERC777TokensRecipient(implementer).tokensReceived( - operator, - from, - to, - amount, - userData, - operatorData - ); - } - - emit Sent(msg.sender, from, to, amount, userData, operatorData); + ERC777Base( + name, + symbol, + granularity, + defaultOperators + ) public { + _mint(msg.sender, msg.sender, initialSupply, data, operatorData); } } diff --git a/contracts/token/ERC777/ERC777Base.sol b/contracts/token/ERC777/ERC777Base.sol new file mode 100644 index 00000000000..c7bb49a8b60 --- /dev/null +++ b/contracts/token/ERC777/ERC777Base.sol @@ -0,0 +1,429 @@ +pragma solidity ^0.4.24; + +import "./IERC777.sol"; +import "./IERC777TokensRecipient.sol"; +import "./IERC777TokensSender.sol"; +import "../../math/SafeMath.sol"; +import "../../utils/Address.sol"; +import "../../introspection/ERC820Client.sol"; + +/** + * @title ERC777 token implementation to inherit from + * @author etsvigun , Bertrand Masius + * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-777.md + * @dev inherit from this contract, do not use directly + */ +contract ERC777Base is IERC777, ERC820Client { + using SafeMath for uint256; + using Address for address; + + string private _name; + + string private _symbol; + + mapping(address => uint256) private _balances; + + uint256 private _totalSupply; + + uint256 private _granularity; + + address[] private _defaultOpsArray; + + bytes32 constant sendHash = keccak256('ERC777TokensSender'); + bytes32 constant receivedHash = keccak256('ERC777TokensRecipient'); + + mapping(address => bool) private _defaultOps; + mapping(address => mapping(address => bool)) private _revokedDefaultOps; + mapping(address => mapping(address => bool)) private _ops; + + constructor( + string name, + string symbol, + uint256 granularity, + address[] defaultOperators + ) internal { + require(granularity > 0); + _name = name; + _symbol = symbol; + _granularity = granularity; + _defaultOpsArray = defaultOperators; + for (uint i = 0; i < defaultOperators.length; i++) { + _defaultOps[defaultOperators[i]] = true; + } + // register interface + setInterfaceImplementer(address(this), keccak256("ERC777Token"), address(this)); + } + + /** + * @return the name of the token. + */ + function name() public view returns (string) { + return _name; + } + + /** + * @return the symbol of the token. + */ + function symbol() public view returns (string) { + return _symbol; + } + + /** + * @dev Total number of tokens in existence + */ + function totalSupply() public view returns (uint256) { + return _totalSupply; + } + + /** + * @dev Gets the balance of the specified address. + * @param tokenHolder The address to query the balance of. + * @return uint256 representing the amount owned by the specified address. + */ + function balanceOf(address tokenHolder) public view returns (uint256) { + return _balances[tokenHolder]; + } + + /** + * @dev Gets the token's granularity, + * i.e. the smallest number of tokens (in the basic unit) + * which may be minted, sent or burned at any time + * @return uint256 granularity + */ + function granularity() public view returns (uint256) { + return _granularity; + } + + /** + * @dev Get the list of default operators as defined by the token contract. + * @return address[] default operators + */ + function defaultOperators() public view returns (address[]) { + return _defaultOpsArray; + } + + /** + * @dev Authorize an operator for the sender + * @param operator address to be authorized as operator + */ + function authorizeOperator(address operator) public { + require(msg.sender != operator); + if (_defaultOps[operator]) { + _reAuthorizeDefaultOperator(operator); + } else _authorizeOperator(operator); + } + + /** + * @dev Revoke operator rights from one of the default operators + * @param operator address to revoke operator rights from + */ + function revokeOperator(address operator) public { + require(operator != msg.sender); + if (_defaultOps[operator]) { + _revokeDefaultOperator(operator); + } else _revokeOperator(operator); + } + + /** + * @dev Indicate whether an address + * is an operator of the tokenHolder address + * @param operator address which may be an operator of tokenHolder + * @param tokenHolder address of a token holder which may have the operator + * address as an operator. + */ + function isOperatorFor( + address operator, + address tokenHolder + ) public view returns (bool) { + return + operator == tokenHolder || + _defaultOps[operator] && !_revokedDefaultOps[tokenHolder][operator] || + _ops[tokenHolder][operator]; + } + + /** + * @dev Send the amount of tokens from the address msg.sender to the address to + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param data bytes information attached to the send, and intended for the recipient (to) + */ + function send(address to, uint256 amount, bytes data) external { + _send(msg.sender, msg.sender, to, amount, data, ""); + } + + /** + * @dev Send the amount of tokens on behalf of the address from to the address to + * @param from address token holder address. Set to 0x0 to use msg.sender as token holder + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param data bytes information attached to the send, and intended for the recipient (to) + * @param operatorData bytes extra information provided by the operator (if any) + */ + function operatorSend( + address from, + address to, + uint256 amount, + bytes data, + bytes operatorData + ) + external + { + address holder = from == address(0) ? msg.sender : from; + _send(msg.sender, holder, to, amount, data, operatorData); + } + + /** + * @dev Burn the amount of tokens from the address msg.sender + * @param amount uint256 amount of tokens to transfer + */ + function burn(uint256 amount) external { + _burn(msg.sender, msg.sender, amount, ""); + } + + /** + * @dev Burn the amount of tokens on behalf of the address from + * @param from address token holder address. Set to 0x0 to use msg.sender as token holder + * @param amount uint256 amount of tokens to transfer + * @param operatorData bytes extra information provided by the operator (if any) + */ + function operatorBurn( + address from, + uint256 amount, + bytes operatorData + ) + external + { + address holder = from == address(0) ? msg.sender : from; + _burn(msg.sender, holder, amount, operatorData); + } + + /** + * @dev Authorize an operator for the sender + * @param operator address to be authorized as operator + */ + function _authorizeOperator(address operator) private { + _ops[msg.sender][operator] = true; + emit AuthorizedOperator(operator, msg.sender); + } + + /** + * @dev Re-authorize a previously revoked default operator + * @param operator address to be re-authorized as operator + */ + function _reAuthorizeDefaultOperator(address operator) private { + delete _revokedDefaultOps[msg.sender][operator]; + emit AuthorizedOperator(operator, msg.sender); + } + + /** + * @dev Revoke operator rights from one of the default operators + * @param operator address to revoke operator rights from + */ + function _revokeDefaultOperator(address operator) private { + _revokedDefaultOps[msg.sender][operator] = true; + emit RevokedOperator(operator, msg.sender); + } + + /** + * @dev Revoke an operator for the sender + * @param operator address to revoke operator rights from + */ + function _revokeOperator(address operator) private { + delete _ops[msg.sender][operator]; + emit RevokedOperator(operator, msg.sender); + } + + /** + * @dev Burn tokens + * @param operator address operator requesting the operation + * @param from address token holder address + * @param amount uint256 amount of tokens to burn + * @param operatorData bytes extra information provided by the operator (if any) + */ + function _burn( + address operator, + address from, + uint256 amount, + bytes operatorData + ) + internal + { + require(from != address(0)); + require(isOperatorFor(msg.sender, from)); + + _callTokensToSend( + operator, + from, + address(0), + amount, + "", + operatorData + ); + + // Update state variables + _totalSupply = _totalSupply.sub(amount); + _balances[from] = _balances[from].sub(amount); + require((_balances[from] % _granularity) == 0); + + emit Burned(operator, from, amount, operatorData); + } + + /** + * @dev Mint tokens. Does not check authorization of operator + * @dev the caller may ckeck that operator is authorized before calling + * @param operator address operator requesting the operation + * @param to address token recipient address + * @param amount uint256 amount of tokens to mint + * @param userData bytes extra information defined by the token recipient (if any) + * @param operatorData bytes extra information provided by the operator (if any) + */ + function _mint( + address operator, + address to, + uint256 amount, + bytes userData, + bytes operatorData + ) + internal + { + require(to != address(0)); + + // revert if 'to' is a contract not implementing tokensReceived() + require( + _callTokensReceived( + operator, + address(0), + to, + amount, + userData, + operatorData + ) + ); + + // Update state variables + _totalSupply = _totalSupply.add(amount); + _balances[to] = _balances[to].add(amount); + require((_balances[to] % _granularity) == 0); + + emit Minted(operator, to, amount, userData, operatorData); + } + + /** + * @dev Send tokens + * @param operator address operator requesting the transfer + * @param from address token holder address + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param userData bytes extra information provided by the token holder (if any) + * @param operatorData bytes extra information provided by the operator (if any) + */ + function _send( + address operator, + address from, + address to, + uint256 amount, + bytes userData, + bytes operatorData + ) + private + { + require(from != address(0)); + require(to != address(0)); + require(isOperatorFor(msg.sender, from)); + + _callTokensToSend( + operator, + from, + to, + amount, + userData, + operatorData + ); + + // Update state variables + _balances[from] = _balances[from].sub(amount); + _balances[to] = _balances[to].add(amount); + require((_balances[from] % _granularity) == 0); + require((_balances[to] % _granularity) == 0); + + _callTokensReceived( + operator, + from, + to, + amount, + userData, + operatorData + ); + + emit Sent(msg.sender, from, to, amount, userData, operatorData); + } + + /** + * @dev Call from.tokensToSend() if the interface is registered + * @param operator address operator requesting the transfer + * @param from address token holder address + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param userData bytes extra information provided by the token holder (if any) + * @param operatorData bytes extra information provided by the operator (if any) + */ + function _callTokensToSend( + address operator, + address from, + address to, + uint256 amount, + bytes userData, + bytes operatorData + ) + private + { + address implementer = getInterfaceImplementer(from, sendHash); + if (implementer != address(0)) { + IERC777TokensSender(implementer).tokensToSend( + operator, + from, + to, + amount, + userData, + operatorData + ); + } + } + + /** + * @dev Call to.tokensReceived() if the interface is registered + * @param operator address operator requesting the transfer + * @param from address token holder address + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param userData bytes extra information provided by the token holder (if any) + * @param operatorData bytes extra information provided by the operator (if any) + * @return false if the recipient is a contract but tokensReceived() was not + * registered for the recipient + */ + function _callTokensReceived( + address operator, + address from, + address to, + uint256 amount, + bytes userData, + bytes operatorData + ) + private + returns(bool) + { + address implementer = getInterfaceImplementer(to, receivedHash); + if (implementer == address(0)) { + return(! to.isContract()); + } + IERC777TokensRecipient(implementer).tokensReceived( + operator, + from, + to, + amount, + userData, + operatorData + ); + return true; + } +} diff --git a/contracts/token/ERC777/ERC777Burnable.sol b/contracts/token/ERC777/ERC777Burnable.sol index dd7163a02b8..c85734f634d 100644 --- a/contracts/token/ERC777/ERC777Burnable.sol +++ b/contracts/token/ERC777/ERC777Burnable.sol @@ -1,12 +1,14 @@ pragma solidity ^0.4.24; -import "./ERC777.sol"; +import "./ERC777Base.sol"; -@title ERC777 burnable token implementation -@author Bertrand Masius -@dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-777.md -contract ERC777Burnable is ERC777 { +/** + * @title ERC777 burnable token implementation + * @author Bertrand Masius + * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-777.md + */ +contract ERC777Burnable is ERC777Base { /** * @dev Burn the amount of tokens from the address msg.sender diff --git a/contracts/token/ERC777/IERC777.sol b/contracts/token/ERC777/IERC777.sol index 939392f8b88..f88bd08baab 100644 --- a/contracts/token/ERC777/IERC777.sol +++ b/contracts/token/ERC777/IERC777.sol @@ -27,6 +27,10 @@ interface IERC777 { function operatorSend(address from, address to, uint256 amount, bytes data, bytes operatorData) external; + function burn(uint256 amount) external; + + function operatorBurn(address from, uint256 amount, bytes operatorData) external; + event Sent( address indexed operator, address indexed from, diff --git a/test/token/ERC777/ERC777.test.js b/test/token/ERC777/ERC777.test.js index 565b644c798..620de3219e7 100644 --- a/test/token/ERC777/ERC777.test.js +++ b/test/token/ERC777/ERC777.test.js @@ -1,166 +1,809 @@ const {assertRevert} = require('../../helpers/assertRevert'); const expectEvent = require('../../helpers/expectEvent'); +const {ERC820Deploy} = require('../../introspection/ERC820Deploy'); const ERC777 = artifacts.require('ERC777'); +const ERC820 = artifacts.require('IERC820'); +const ERC777TokensRecipient = artifacts.require('ERC777ReceiverMock'); +const ERC777TokensSender = artifacts.require('ERC777SenderMock'); -const BigNumber = web3.BigNumber; +const BigNumber = web3.utils.BN; require('chai') .use(require('chai-bignumber')(BigNumber)) .should(); -contract('ERC777', function ([_, owner, recipient, anotherAccount]) { +contract('ERC777', function ([_, holder, operator, anotherAccount]) { const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; + const ERC820_ADDRESS = "0x820A8Cfd018b159837d50656c49d28983f18f33c"; + const INITIAL_SUPPLY = "10000"; + const USER_DATA = "0xabcd"; + const OPERATOR_DATA = "0x0a0b0c0d"; + const GRANULARITY = "1"; + + before('Deploy ERC820', async function () { + try { + this.ERC820Registry = await ERC820.at(ERC820_ADDRESS); + } catch(error) { + let address = await ERC820Deploy(holder); + this.ERC820Registry = await ERC820.at(address); + } + }); + + it('Minted event is emitted', async function () { + // use web3 deployment to get the receipt + let web3Contract = new web3.eth.Contract(ERC777.abi); + web3Contract.options.data = ERC777.binary; + let tx = web3Contract.deploy({arguments: ["Test777", "T77", GRANULARITY, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA]}); + + let instance = await tx + .send({from: holder, gas: '6000000', data: tx}) + .on('receipt', receipt => { + expectEvent.inEvents(receipt.events, 'Minted',{ + operator: holder, + to: holder, + amount: INITIAL_SUPPLY, + data: USER_DATA, + operatorData: OPERATOR_DATA + }); + }); + this.token = await ERC777.at(instance.options.address); + }); - beforeEach(async function () { - this.token = await ERC777.new("Test777", "T77", 1, []); + describe('ERC820 Registry', function () { + it('hardcoded address in ERC777 contract is correct', async function () { + let erc820 = await this.token.getERC820Registry(); + erc820.should.be.equal(this.ERC820Registry.address); + }); }); describe('total supply', function () { it('returns the total amount of tokens', async function () { - (await this.token.totalSupply()).should.be.bignumber.equal(0); //TODO update when minting is immplemented + (await this.token.totalSupply()).toString().should.be.equal(INITIAL_SUPPLY); }); }); describe('balanceOf', function () { describe('when the requested account has no tokens', function () { it('returns zero', async function () { - (await this.token.balanceOf(anotherAccount)).should.be.bignumber.equal(0); + (await this.token.balanceOf(anotherAccount)).toString().should.be.equal("0"); }); }); describe('when the requested account has some tokens', function () { it('returns the total amount of tokens', async function () { - (await this.token.balanceOf(owner)).should.be.bignumber.equal(0); //TODO update when minting is immplemented + (await this.token.balanceOf(holder)).toString().should.be.equal(INITIAL_SUPPLY); }); }); }); describe('granularity', function () { it('returns granularity amount of the token', async function () { - (await this.token.granularity()).should.be.bignumber.equal(1); //TODO update when minting is immplemented + (await this.token.granularity()).toString().should.be.equal(GRANULARITY); }); it('value is set at creation time', async function () { - let token = await ERC777.new("Test777", "T77", 10, []); - let granularity = await token.granularity(); - granularity.should.be.bignumber.equal(10); + let tempToken = await ERC777.new("Test777", "T77", 10, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA); + let granularity = await tempToken.granularity(); + granularity.toString().should.be.equal("10"); }); it('value is checked to be greater or equal to 1', async function () { - await assertRevert(ERC777.new("Test777", "T77", 0, [])); + await assertRevert(ERC777.new("Test777", "T77", 0, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA)); + }); + + it('initialSupply is a multiple of granularity', async function () { + await assertRevert(ERC777.new("Test777", "T77", "7", [], "11", USER_DATA, OPERATOR_DATA)); }); }); - describe('defaultOperators', function () { - it('returns default operators of the token', async function () { - (await this.token.defaultOperators()).should.be.an('array').that.is.empty; //TODO update when minting is immplemented + describe('non-default operator', async function () { + + before('Deploy ERC777 with no default operator', async function () { + this.token = await ERC777.new("Test777", "T77", 1, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA); }); - it('value is set at creation time', async function () { - let token = await ERC777.new("Test777", "T77", 1, [recipient, anotherAccount]); - let defaultOps = await token.defaultOperators(); - defaultOps.should.be.an('array').that.has.all.members([recipient, anotherAccount]); + it('holder is an operator for itself', function () { + assert(this.token.contract.methods.isOperatorFor(holder, holder)); }); - }); - describe('authorizeOperator', function () { - beforeEach(async function () { - let op = recipient; - this.defaultOpsToken = await ERC777.new("Test777", "T77", 1, [op]) + describe('authorize operator', function () { + + it('AuthorizedOperator event is emitted', async function () { + const {logs} = await this.token.authorizeOperator(anotherAccount, {from: holder}); + expectEvent.inLogs(logs, 'AuthorizedOperator', { + operator: anotherAccount, + tokenHolder: holder + }); + }); + + it('operator is authorized', function () { + assert(this.token.contract.methods.isOperatorFor(anotherAccount, holder)); + }); + + it('AuthorizedOperator event is emitted even if operator is already authorized', async function () { + const {logs} = await this.token.authorizeOperator(anotherAccount, {from: holder}); + expectEvent.inLogs(logs, 'AuthorizedOperator', { + operator: anotherAccount, + tokenHolder: holder + }); + }); + + it('revert when token holder authorizes itself as operator', async function () { + await assertRevert(this.token.authorizeOperator(holder, {from: holder})); + }); + }); - it('authorizes operators for holders', async function () { - let op = recipient; - let holder = owner; + describe('revoke operator', function () { + + it('RevokedOperator event is emitted', async function () { + const {logs} = await this.token.revokeOperator(anotherAccount, {from: holder}); + expectEvent.inLogs(logs, 'RevokedOperator', { + operator: anotherAccount, + tokenHolder: holder + }); + }); + + it('operator is revoked', async function () { + let iopf = await this.token.contract.methods.isOperatorFor(anotherAccount, holder).call(); + assert(! iopf); + }); + + it('RevokedOperator event is emitted even if operator is already revoked', async function () { + const {logs} = await this.token.revokeOperator(anotherAccount, {from: holder}); + expectEvent.inLogs(logs, 'RevokedOperator', { + operator: anotherAccount, + tokenHolder: holder + }); + }); - const {logs} = await this.token.authorizeOperator(op, {from: holder}); - expectEvent.inLogs(logs, 'AuthorizedOperator', { - operator: op, - tokenHolder: holder + it('revert when token holder revoke itself as operator', async function () { + await assertRevert(this.token.revokeOperator(holder, {from: holder})); }); + }); + }); - it('authorizes operators only when they are not already authorised', async function () { - let op = recipient; - let holder = owner; + describe('default operator', async function () { - await this.token.authorizeOperator(op, {from: holder}); - await assertRevert(this.token.authorizeOperator(op, {from: holder})); + before('Deploy ERC777 with one default operator', async function () { + this.token = await ERC777.new("Test777", "T77", 1, [operator], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA); }); - it('authorizes operators only when they are not pre-authorised by default', async function () { - let op = recipient; - let holder = owner; + it('returns empty array when no default operator has been declared', async function () { + let tempToken = await ERC777.new("Test777", "T77", 1, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA); + (await tempToken.defaultOperators()).should.be.an('array').that.is.empty; + }); - await assertRevert(this.defaultOpsToken.authorizeOperator(op, {from: holder})); + it('array of operators is set at creation time', async function () { + let tempToken = await ERC777.new("Test777", "T77", 1, [operator, anotherAccount], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA); + let defaultOps = await tempToken.defaultOperators(); + defaultOps.should.be.an('array').that.has.all.members([operator, anotherAccount]); }); - it('re-authorizes previously revoked default operators', async function () { - let op = recipient; - let holder = owner; + it('operator is an authorized operator for any holder', function () { + assert(this.token.contract.methods.isOperatorFor(operator, holder)); + }); + + describe('revoke operator', function () { + + it('RevokedOperator event is emitted', async function () { + const {logs} = await this.token.revokeOperator(operator, {from: holder}); + expectEvent.inLogs(logs, 'RevokedOperator', { + operator: operator, + tokenHolder: holder + }); + }); + + it('operator is revoked', async function () { + let iopf = await this.token.contract.methods.isOperatorFor(operator, holder).call(); + assert(! iopf); + }); + + it('RevokedOperator event is emitted even if operator is already revoked', async function () { + const {logs} = await this.token.revokeOperator(operator, {from: holder}); + expectEvent.inLogs(logs, 'RevokedOperator', { + operator: operator, + tokenHolder: holder + }); + }); - await assertRevert(this.defaultOpsToken.authorizeOperator(op, {from: holder})); }); - it('authorizes operators only when they are not pre-authorised by default', async function () { - let op = recipient; - let holder = owner; + describe('re-authorize operator', function () { + + it('AuthorizedOperator event is emitted', async function () { + const {logs} = await this.token.authorizeOperator(operator, {from: holder}); + expectEvent.inLogs(logs, 'AuthorizedOperator', { + operator: operator, + tokenHolder: holder + }); + }); - await this.defaultOpsToken.revokeOperator(op, {from: holder}); + it('operator is authorized', async function () { + let iopf = await this.token.contract.methods.isOperatorFor(operator, holder).call(); + assert(iopf); + }); - const {logs} = await this.defaultOpsToken.authorizeOperator(op, {from: holder}); - expectEvent.inLogs(logs, 'AuthorizedOperator', { - operator: op, - tokenHolder: holder + it('AuthorizedOperator is emitted even if operator is already authorized', async function () { + const {logs} = await this.token.authorizeOperator(operator, {from: holder}); + expectEvent.inLogs(logs, 'AuthorizedOperator', { + operator: operator, + tokenHolder: holder + }); }); + }); }); - describe('revokeOperator', function () { - beforeEach(async function () { - let op = recipient; - this.defaultOpsToken = await ERC777.new("Test777", "T77", 1, [op]) + describe('send()',function () { + + before('Deploy ERC777', async function () { + this.token = await ERC777.new("Test777", "T77", 1, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA, {from: holder}); }); - it('revokes operators for holders', async function () { - let op = recipient; - let holder = owner; + it('Sent event is emitted when sending 0 token', async function () { + let userData = "0xdeadbeef"; - await this.token.authorizeOperator(op, {from: holder}); + const {events} = await this.token.contract.methods.send(operator, "0", userData).send({from: holder}); + expectEvent.inEvents(events, 'Sent', { + operator: holder, + from: holder, + to: operator, + amount: "0", + data: userData, + }); + }); + + it('revert when sending an amount of token from an account with insufficient balance', async function () { + let amount = parseInt(INITIAL_SUPPLY, 10) + 100; + let userData = "0xdeadbeef"; + await assertRevert(this.token.contract.methods.send(operator, amount.toString(), userData).send({from: holder})); + }); + + describe('sending an amount of token from an account with sufficient balance', function () { + it('Sent event is emitted', async function () { + let userData = "0xdeadbeef"; + + const {events} = await this.token.contract.methods.send(operator, "100", userData).send({from: holder}); + expectEvent.inEvents(events, 'Sent', { + operator: holder, + from: holder, + to: operator, + amount: "100", + data: userData, + }); + }); + + it('sender balance is decreased', async function () { + let balance = parseInt(INITIAL_SUPPLY, 10) - 100; + (await this.token.balanceOf(holder)).toString().should.be.equal(balance.toString()); + }); + + it('recipient balance is increased', async function () { + (await this.token.balanceOf(operator)).toString().should.be.equal("100"); + }); - const {logs} = await this.token.revokeOperator(op, {from: holder}); - expectEvent.inLogs(logs, 'RevokedOperator', { - operator: op, - tokenHolder: holder + describe('hooks', function () { + it('tokensToSend() hook is called when declared', async function () { + let userData = "0xdeadbeef"; + + // deploy sender contract and give tokens + let sender = await ERC777TokensSender.new(true, this.token.address); + await this.token.contract.methods.send(sender.address, "100", userData).send({from: holder}); + + const {events} = await sender.contract.methods.sendTokens(operator, "100", userData).send({from: holder}); + expectEvent.inEvents(events, 'TokensToSend', { + operator: sender.address, + from: sender.address, + to: operator, + amount: "100", + data: userData, + }); + }); + + it('tokensToSend() hook is not called when not declared', async function () { + let userData = "0xdeadbeef"; + + // deploy sender contract and give tokens + let sender = await ERC777TokensSender.new(false, this.token.address); + await this.token.contract.methods.send(sender.address, "100", userData).send({from: holder}); + + const {events} = await sender.contract.methods.sendTokens(operator, "100", userData).send({from: holder}); + expect(events["tokensToSend"]).to.not.exist; + }); + + it('tokensReceived() hook is called when declared', async function () { + let userData = "0xdeadbeef"; + + let receiver = await ERC777TokensRecipient.new(true); + await this.token.contract.methods.send(receiver.address, "100", userData).send({from: holder}); + let events = await receiver.getPastEvents("TokensReceived"); + events.length.should.be.not.equal(0); + let event = events[0].returnValues; + event.operator.should.be.equal(holder); + event.from.should.be.equal(holder); + event.to.should.be.equal(receiver.address); + event.amount.toString().should.be.equal("100"); + event.data.should.be.equal(userData); + }); + + it('tokensReceived() hook is not called when not declared', async function () { + let userData = "0xdeadbeef"; + + let receiver = await ERC777TokensRecipient.new(false); + await this.token.contract.methods.send(receiver.address, "100", userData).send({from: holder}); + let events = await receiver.getPastEvents("TokensReceived"); + events.length.should.be.equal(0); + }); + }); + + it('revert when sending an amount of token to address(0)', async function () { + let userData = "0xdeadbeef"; + await assertRevert(this.token.contract.methods.send(ZERO_ADDRESS, "100", userData).send({from: holder})); + }); + + it('revert when sending an amount which is not a multiple of granularity', async function () { + let userData = "0xdeadbeef"; + let tempToken = await ERC777.new("Test777", "T77", 10, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA, {from: holder}); + await assertRevert(tempToken.contract.methods.send(anotherAccount, "15", userData).send({from: holder})); }); }); - it('revokes operators only when they are authorised', async function () { - let op = recipient; - let holder = owner; + }); - await assertRevert(this.token.revokeOperator(op, {from: holder})); + describe('operatorSend()',function () { + let operatorTests = { + defaultOperatorTest: + { + name: "default operator", + deploy_fn: async function (holder, operator) { + this.token = + await ERC777.new( + "Test777", + "T77", + 1, + [operator], + INITIAL_SUPPLY, + USER_DATA, + OPERATOR_DATA, + {from: holder} + ); + }, + deploy_sender: async function (holder, operator, declareInterface) { + // deploy sender contract and give tokens + this.sender = await ERC777TokensSender.new(declareInterface, this.token.address); + await this.token.contract.methods.send(this.sender.address, "100", web3.utils.asciiToHex("")).send({from: holder}); + } + }, + nonDefaultOperatorTest: + { + name: "non-default operator", + deploy_fn: async function (holder, operator) { + this.token = + await ERC777.new( + "Test777", + "T77", + 1, + [], + INITIAL_SUPPLY, + USER_DATA, + OPERATOR_DATA, + {from: holder} + ); + await this.token.authorizeOperator(operator, {from: holder}); + }, + deploy_sender: async function (holder, operator, declareInterface) { + // deploy sender contract and give tokens + this.sender = await ERC777TokensSender.new(declareInterface, this.token.address); + await this.token.contract.methods.send(this.sender.address, "100", web3.utils.asciiToHex("")).send({from: holder}); + // declare operator + await this.sender.contract.methods.authorizeOperator(operator).send({from: holder}); + } + } + }; + + it('revert when msg.sender is not an operator', async function () { + let tempToken = await ERC777.new("Test777", "T77", 1, [operator], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA, {from: holder}); + let userData = "0xdeadbeef"; + let opData = "0xbabecafe"; + await assertRevert(tempToken.contract.methods.operatorSend(holder, anotherAccount, "100", userData, opData).send({from: anotherAccount})); }); - it('revokes pre-authorised default operators', async function () { - let op = recipient; - let holder = owner; + for (let test in operatorTests) { + + describe('when operator is a ' + operatorTests[test].name, function () { + + before('Deploy ERC777', async function() { + await operatorTests[test].deploy_fn.call(this, holder, operator); + }); + + it('Sent event is emitted when sending 0 token', async function () { + let userData = "0xdeadbeef"; + let opData = "0xbabecafe"; + + const {events} = await this.token.contract.methods.operatorSend(holder, anotherAccount, "0", userData, opData).send({from: operator}); + expectEvent.inEvents(events, 'Sent', { + operator: operator, + from: holder, + to: anotherAccount, + amount: "0", + data: userData, + operatorData: opData, + }); + }); + + it('revert when sending an amount of token from an account with insufficient balance', async function () { + let amount = parseInt(INITIAL_SUPPLY, 10) + 100; + let userData = "0xdeadbeef"; + let opData = "0xbabecafe"; + await assertRevert(this.token.contract.methods.operatorSend(holder, anotherAccount, amount.toString(), userData, opData).send({from: operator})); + }); + + describe('sending an amount of token from an account with sufficient balance', function () { + it('Sent event is emitted', async function () { + let userData = "0xdeadbeef"; + let opData = "0xbabecafe"; + + const {events} = await this.token.contract.methods.operatorSend(holder, anotherAccount, "100", userData, opData).send({from: operator}); + expectEvent.inEvents(events, 'Sent', { + operator: operator, + from: holder, + to: anotherAccount, + amount: "100", + data: userData, + operatorData: opData, + }); + }); + + it('sender balance is decreased', async function () { + let balance = parseInt(INITIAL_SUPPLY, 10) - 100; + (await this.token.balanceOf(holder)).toString().should.be.equal(balance.toString()); + }); + + it('recipient balance is increased', async function () { + (await this.token.balanceOf(anotherAccount)).toString().should.be.equal("100"); + }); + + it('revert when recipient is address(0)', async function () { + let userData = "0xdeadbeef"; + let opData = "0xbabecafe"; + await assertRevert(this.token.contract.methods.operatorSend(holder, ZERO_ADDRESS, "100", userData, opData).send({from: operator})); + }); + + it('revert when sending an amount which is not a multiple of granularity', async function () { + let userData = "0xdeadbeef"; + let opData = "0xbabecafe"; + let tempToken = await ERC777.new("Test777", "T77", 10, [operator], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA, {from: holder}); + await assertRevert(tempToken.contract.methods.operatorSend(holder, anotherAccount, "15", userData, opData).send({from: operator})); + }); + + it('operator is the holder when from is address(0)', async function () { + let userData = "0xdeadbeef"; + let opData = "0xbabecafe"; + + this.token.contract.methods.send(operator, "100", userData).send({from: holder}).then(async () => { + const {events} = await this.token.contract.methods.operatorSend(ZERO_ADDRESS, anotherAccount, "100", userData, opData).send({from: operator}); + expectEvent.inEvents(events, 'Sent', { + operator: operator, + from: operator, + to: anotherAccount, + amount: "100", + data: userData, + operatorData: opData, + }); + }); + }); + + describe('hooks', function () { + + it('tokensToSend() hook is called when declared', async function () { + let userData = "0xdeadbeef"; + let opData = "0xbabecafe"; + + // deploy sender contract, declare operator and give tokens + await operatorTests[test].deploy_sender.call(this, holder, operator, true); + + await this.token.contract.methods.operatorSend(this.sender.address, anotherAccount, "100", userData, opData).send({from: operator}); + let events = await this.sender.getPastEvents("TokensToSend"); + events.length.should.be.not.equal(0); + let event = events[0].returnValues; + event.operator.should.be.equal(operator); + event.from.should.be.equal(this.sender.address); + event.to.should.be.equal(anotherAccount); + event.amount.toString().should.be.equal("100"); + event.data.should.be.equal(userData); + event.operatorData.should.be.equal(opData); + }); + + it('tokensToSend() hook is not called when not declared', async function () { + + let userData = "0xdeadbeef"; + let opData = "0xbabecafe"; + + // deploy sender contract, declare operator and give tokens + await operatorTests[test].deploy_sender.call(this, holder, operator, false); + + await this.token.contract.methods.operatorSend(this.sender.address, anotherAccount, "100", userData, opData).send({from: operator}); + let events = await this.sender.getPastEvents("TokensToSend"); + expect(events["tokensToSend"]).to.not.exist; + }); + + it('tokensReceived() hook is called when declared', async function () { + let userData = "0xdeadbeef"; + let opData = "0xbabecafe"; + + let receiver = await ERC777TokensRecipient.new(true); + await this.token.contract.methods.operatorSend(holder, receiver.address, "100", userData, opData).send({from: operator}); + let events = await receiver.getPastEvents("TokensReceived"); + events.length.should.be.not.equal(0); + let event = events[0].returnValues; + event.operator.should.be.equal(operator); + event.from.should.be.equal(holder); + event.to.should.be.equal(receiver.address); + event.amount.toString().should.be.equal("100"); + event.data.should.be.equal(userData); + event.operatorData.should.be.equal(opData); + }); + + it('tokensReceived() hook is not called when not declared', async function () { + let userData = "0xdeadbeef"; + let opData = "0xbabecafe"; + + let receiver = await ERC777TokensRecipient.new(false); + await this.token.contract.methods.operatorSend(holder, receiver.address, "100", userData, opData).send({from: operator}); + let events = await receiver.getPastEvents("TokensReceived"); + expect(events["tokensReceived"]).to.not.exist; + }); + }); + + }); + }); + } + }); + + describe('burn()',function () { + + before('Deploy ERC777', async function () { + this.token = await ERC777.new("Test777", "T77", 1, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA, {from: holder}); + }); - const {logs} = await this.defaultOpsToken.revokeOperator(op, {from: holder}); - expectEvent.inLogs(logs, 'RevokedOperator', { - operator: op, - tokenHolder: holder + it('Burned event is emitted when burning 0 token', async function () { + const {events} = await this.token.contract.methods.burn("0").send({from: holder}); + expectEvent.inEvents(events, 'Burned', { + operator: holder, + from: holder, + amount: "0", }); }); - it('revokes pre-authorised default operators only when they were not previously revoked', async function () { - let op = recipient; - let holder = owner; + it('revert when burning an amount of token from an account with insufficient balance', async function () { + let amount = parseInt(INITIAL_SUPPLY, 10) + 100; + await assertRevert(this.token.contract.methods.burn(amount.toString()).send({from: holder})); + }); + + describe('burning an amount of token from an account with sufficient balance', function () { + it('Burned event is emitted', async function () { + + const {events} = await this.token.contract.methods.burn("100").send({from: holder}); + expectEvent.inEvents(events, 'Burned', { + operator: holder, + from: holder, + amount: "100", + }); + }); + + it('holder balance is decreased', async function () { + let balance = parseInt(INITIAL_SUPPLY, 10) - 100; + (await this.token.balanceOf(holder)).toString().should.be.equal(balance.toString()); + }); + + it('balance of 0x0 is not increased', async function () { + (await this.token.balanceOf(ZERO_ADDRESS)).toString().should.be.equal("0"); + }); + + it('totalSupply is decreased', async function () { + let supply = parseInt(INITIAL_SUPPLY, 10) - 100; + (await this.token.totalSupply()).toString().should.be.equal(supply.toString()); + }); - await this.defaultOpsToken.revokeOperator(op, {from: holder}); + describe('hooks', function () { + it('tokensToSend() hook is called when declared, and data is 0x00', async function () { + // deploy sender contract and give tokens + let sender = await ERC777TokensSender.new(true, this.token.address); + await this.token.contract.methods.send(sender.address, "100", web3.utils.asciiToHex("")).send({from: holder}); + + const {events} = await sender.contract.methods.burnTokens("100").send({from: holder}); + expectEvent.inEvents(events, 'TokensToSend', { + operator: sender.address, + from: sender.address, + to: ZERO_ADDRESS, + amount: "100", + data: "0x00", + }); + }); + + it('tokensToSend() hook is not called when not declared', async function () { + // deploy sender contract and give tokens + let sender = await ERC777TokensSender.new(false, this.token.address); + await this.token.contract.methods.send(sender.address, "100", web3.utils.asciiToHex("")).send({from: holder}); + + const {events} = await sender.contract.methods.burnTokens("100").send({from: holder}); + expect(events["tokensToSend"]).to.not.exist; + }); + }); - await assertRevert(this.defaultOpsToken.revokeOperator(op, {from: holder})); + it('revert when sending an amount which is not a multiple of granularity', async function () { + let tempToken = await ERC777.new("Test777", "T77", 10, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA, {from: holder}); + await assertRevert(tempToken.contract.methods.burn("15").send({from: holder})); + }); }); }); + + describe('operatorBurn()',function () { + let operatorTests = { + defaultOperatorTest: + { + name: "default operator", + deploy_fn: async function (holder, operator) { + this.token = + await ERC777.new( + "Test777", + "T77", + 1, + [operator], + INITIAL_SUPPLY, + USER_DATA, + OPERATOR_DATA, + {from: holder} + ); + }, + deploy_sender: async function (holder, operator, declareInterface) { + // deploy sender contract and give tokens + this.sender = await ERC777TokensSender.new(declareInterface, this.token.address); + await this.token.contract.methods.send(this.sender.address, "100", web3.utils.asciiToHex("")).send({from: holder}); + } + }, + nonDefaultOperatorTest: + { + name: "non-default operator", + deploy_fn: async function (holder, operator) { + this.token = + await ERC777.new( + "Test777", + "T77", + 1, + [], + INITIAL_SUPPLY, + USER_DATA, + OPERATOR_DATA, + {from: holder} + ); + await this.token.authorizeOperator(operator, {from: holder}); + }, + deploy_sender: async function (holder, operator, declareInterface) { + // deploy sender contract and give tokens + this.sender = await ERC777TokensSender.new(declareInterface, this.token.address); + await this.token.contract.methods.send(this.sender.address, "100", web3.utils.asciiToHex("")).send({from: holder}); + // declare operator + await this.sender.contract.methods.authorizeOperator(operator).send({from: holder}); + } + } + }; + + it('revert when msg.sender is not an operator', async function () { + let tempToken = await ERC777.new("Test777", "T77", 1, [operator], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA, {from: holder}); + let opData = "0xbabecafe"; + await assertRevert(tempToken.contract.methods.operatorBurn(holder, "100", opData).send({from: anotherAccount})); + }); + + for (let test in operatorTests) { + + describe('when operator is a ' + operatorTests[test].name, function () { + + before('Deploy ERC777', async function() { + await operatorTests[test].deploy_fn.call(this, holder, operator); + }); + + it('Burned event is emitted when burning 0 token', async function () { + let opData = "0xbabecafe"; + + const {events} = await this.token.contract.methods.operatorBurn(holder, "0", opData).send({from: operator}); + expectEvent.inEvents(events, 'Burned', { + operator: operator, + from: holder, + amount: "0", + operatorData: opData, + }); + }); + + it('revert when burning an amount of token from an account with insufficient balance', async function () { + let amount = parseInt(INITIAL_SUPPLY, 10) + 100; + let opData = "0xbabecafe"; + await assertRevert(this.token.contract.methods.operatorBurn(holder, amount.toString(), opData).send({from: operator})); + }); + + describe('burning an amount of token from an account with sufficient balance', function () { + it('Burned event is emitted', async function () { + let opData = "0xbabecafe"; + + const {events} = await this.token.contract.methods.operatorBurn(holder, "100", opData).send({from: operator}); + expectEvent.inEvents(events, 'Burned', { + operator: operator, + from: holder, + amount: "100", + operatorData: opData, + }); + }); + + it('holder balance is decreased', async function () { + let balance = parseInt(INITIAL_SUPPLY, 10) - 100; + (await this.token.balanceOf(holder)).toString().should.be.equal(balance.toString()); + }); + + it('balance of 0x0 is not increased', async function () { + (await this.token.balanceOf(ZERO_ADDRESS)).toString().should.be.equal("0"); + }); + + it('totalSupply is decreased', async function () { + let supply = parseInt(INITIAL_SUPPLY, 10) - 100; + (await this.token.totalSupply()).toString().should.be.equal(supply.toString()); + }); + + it('revert when burning an amount which is not a multiple of granularity', async function () { + let opData = "0xbabecafe"; + let tempToken = await ERC777.new("Test777", "T77", 10, [operator], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA, {from: holder}); + await assertRevert(tempToken.contract.methods.operatorBurn(holder, "15", opData).send({from: operator})); + }); + + it('operator is the holder when from is address(0)', async function () { + let opData = "0xbabecafe"; + + await this.token.contract.methods.send(operator, "100", web3.utils.asciiToHex("")).send({from: holder}); + const {events} = await this.token.contract.methods.operatorBurn(ZERO_ADDRESS, "100", opData).send({from: operator}); + expectEvent.inEvents(events, 'Burned', { + operator: operator, + from: operator, + amount: "100", + operatorData: opData, + }); + }); + + describe('hooks', function () { + + it('tokensToSend() hook is called when declared', async function () { + let opData = "0xbabecafe"; + + // deploy sender contract, declare operator and give tokens + await operatorTests[test].deploy_sender.call(this, holder, operator, true); + + await this.token.contract.methods.operatorBurn(this.sender.address, "100", opData).send({from: operator}); + let events = await this.sender.getPastEvents("TokensToSend"); + events.length.should.be.not.equal(0); + let event = events[0].returnValues; + event.operator.should.be.equal(operator); + event.from.should.be.equal(this.sender.address); + event.amount.toString().should.be.equal("100"); + expect(event.data).to.not.exist; + event.operatorData.should.be.equal(opData); + }); + + it('tokensToSend() hook is not called when not declared', async function () { + + let opData = "0xbabecafe"; + + // deploy sender contract, declare operator and give tokens + await operatorTests[test].deploy_sender.call(this, holder, operator, false); + + await this.token.contract.methods.operatorBurn(this.sender.address, "100", opData).send({from: operator}); + let events = await this.sender.getPastEvents("TokensToSend"); + expect(events["tokensToSend"]).to.not.exist; + }); + }); + }); + }); + } + }); + }); From be6fcd190fad24769d0a8ff010b3414dd0ed7c0f Mon Sep 17 00:00:00 2001 From: Bertrand Masius Date: Thu, 31 Jan 2019 06:12:59 +0100 Subject: [PATCH 09/64] ERC777 Update ERC820 Registry contract to final version (#1159) --- contracts/introspection/ERC820Client.sol | 2 +- test/introspection/ERC820Deploy.js | 4 ++-- test/token/ERC777/ERC777.test.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/contracts/introspection/ERC820Client.sol b/contracts/introspection/ERC820Client.sol index c25685cd9c5..18a9c48adef 100644 --- a/contracts/introspection/ERC820Client.sol +++ b/contracts/introspection/ERC820Client.sol @@ -9,7 +9,7 @@ import "./IERC820.sol"; */ contract ERC820Client { - IERC820 private _erc820 = IERC820(0x820A8Cfd018b159837d50656c49d28983f18f33c); + IERC820 private _erc820 = IERC820(0x820b586C8C28125366C998641B09DCbE7d4cBF06); function getInterfaceImplementer(address addr, bytes32 hash) internal view returns(address) { return _erc820.getInterfaceImplementer(addr, hash); diff --git a/test/introspection/ERC820Deploy.js b/test/introspection/ERC820Deploy.js index 10c9cb7ee2f..da7bd3d15ea 100644 --- a/test/introspection/ERC820Deploy.js +++ b/test/introspection/ERC820Deploy.js @@ -2,8 +2,8 @@ const BN = web3.utils.BN; const { sendEther } = require('../helpers/sendTransaction'); const ERC820Deploy = async function (owner) { - const deployAccount = "0xd80816570aD09e44339042b36d9A068Aba0D340F"; - const deployTx = "0xf90a2a8085174876e800830c35008080b909d7608060405234801561001057600080fd5b506109b7806100206000396000f30060806040526004361061008d5763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166329965a1d81146100925780633d584063146100bf5780635df8122f146100fc57806365ba36c114610123578063a41e7d5114610155578063aabbb8ca14610183578063b7056765146101a7578063f712f3e8146101e9575b600080fd5b34801561009e57600080fd5b506100bd600160a060020a036004358116906024359060443516610217565b005b3480156100cb57600080fd5b506100e0600160a060020a0360043516610512565b60408051600160a060020a039092168252519081900360200190f35b34801561010857600080fd5b506100bd600160a060020a036004358116906024351661055e565b34801561012f57600080fd5b506101436004803560248101910135610655565b60408051918252519081900360200190f35b34801561016157600080fd5b506100bd600160a060020a0360043516600160e060020a0319602435166106e3565b34801561018f57600080fd5b506100e0600160a060020a036004351660243561076d565b3480156101b357600080fd5b506101d5600160a060020a0360043516600160e060020a0319602435166107e7565b604080519115158252519081900360200190f35b3480156101f557600080fd5b506101d5600160a060020a0360043516600160e060020a03196024351661089c565b6000600160a060020a0384161561022e5783610230565b335b90503361023c82610512565b600160a060020a03161461029a576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b6102a38361091c565b156102f8576040805160e560020a62461bcd02815260206004820152601960248201527f4d757374206e6f74206265206120455243313635206861736800000000000000604482015290519081900360640190fd5b600160a060020a038216158015906103195750600160a060020a0382163314155b156104a15760405160200180807f4552433832305f4143434550545f4d414749430000000000000000000000000081525060130190506040516020818303038152906040526040518082805190602001908083835b6020831061038d5780518252601f19909201916020918201910161036e565b51815160209384036101000a6000190180199092169116179052604080519290940182900382207f249cb3fa000000000000000000000000000000000000000000000000000000008352600483018a9052600160a060020a0388811660248501529451909650938816945063249cb3fa936044808401945091929091908290030181600087803b15801561042057600080fd5b505af1158015610434573d6000803e3d6000fd5b505050506040513d602081101561044a57600080fd5b5051146104a1576040805160e560020a62461bcd02815260206004820181905260248201527f446f6573206e6f7420696d706c656d656e742074686520696e74657266616365604482015290519081900360640190fd5b600160a060020a03818116600081815260208181526040808320888452909152808220805473ffffffffffffffffffffffffffffffffffffffff19169487169485179055518692917f93baa6efbd2244243bfee6ce4cfdd1d04fc4c0e9a786abd3a41313bd352db15391a450505050565b600160a060020a03808216600090815260016020526040812054909116151561053c575080610559565b50600160a060020a03808216600090815260016020526040902054165b919050565b3361056883610512565b600160a060020a0316146105c6576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b81600160a060020a031681600160a060020a0316146105e557806105e8565b60005b600160a060020a03838116600081815260016020526040808220805473ffffffffffffffffffffffffffffffffffffffff19169585169590951790945592519184169290917f605c2dbf762e5f7d60a546d42e7205dcb1b011ebc62a61736a57c9089d3a43509190a35050565b60008282604051602001808383808284378201915050925050506040516020818303038152906040526040518082805190602001908083835b602083106106ad5780518252601f19909201916020918201910161068e565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902090505b92915050565b6106ed82826107e7565b6106f85760006106fa565b815b600160a060020a03928316600081815260208181526040808320600160e060020a031996909616808452958252808320805473ffffffffffffffffffffffffffffffffffffffff19169590971694909417909555908152600284528181209281529190925220805460ff19166001179055565b60008080600160a060020a038516156107865784610788565b335b91506107938461091c565b156107b85750826107a4828261089c565b6107af5760006107b1565b815b92506107df565b600160a060020a038083166000908152602081815260408083208884529091529020541692505b505092915050565b60008080610815857f01ffc9a70000000000000000000000000000000000000000000000000000000061093e565b9092509050811580610825575080155b1561083357600092506107df565b61084585600160e060020a031961093e565b909250905081158061085657508015155b1561086457600092506107df565b61086e858561093e565b90925090506001821480156108835750806001145b1561089157600192506107df565b506000949350505050565b600160a060020a0382166000908152600260209081526040808320600160e060020a03198516845290915281205460ff1615156108e4576108dd83836107e7565b90506106dd565b50600160a060020a03808316600081815260208181526040808320600160e060020a0319871684529091529020549091161492915050565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff161590565b6040517f01ffc9a7000000000000000000000000000000000000000000000000000000008082526004820183905260009182919060208160088189617530fa9051909690955093505050505600a165627a7a72305820566272f4bea75dbff631713d256c984d562f55a646afc8bc1c01f2d919a038f100291ba08208208208208208208208208208208208208208208208208208208208208200a00820820820820820820820820820820820820820820820820820820820820820"; + const deployAccount = "0xE6C244a1C10Aa0085b0cf92f04cdaD947C2988b8"; + const deployTx = "0xf90a2a8085174876e800830c35008080b909d7608060405234801561001057600080fd5b506109b7806100206000396000f30060806040526004361061008d5763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166329965a1d81146100925780633d584063146100bf5780635df8122f146100fc57806365ba36c114610123578063a41e7d5114610155578063aabbb8ca14610183578063b7056765146101a7578063f712f3e8146101e9575b600080fd5b34801561009e57600080fd5b506100bd600160a060020a036004358116906024359060443516610217565b005b3480156100cb57600080fd5b506100e0600160a060020a0360043516610512565b60408051600160a060020a039092168252519081900360200190f35b34801561010857600080fd5b506100bd600160a060020a036004358116906024351661055e565b34801561012f57600080fd5b506101436004803560248101910135610655565b60408051918252519081900360200190f35b34801561016157600080fd5b506100bd600160a060020a0360043516600160e060020a0319602435166106e3565b34801561018f57600080fd5b506100e0600160a060020a036004351660243561076d565b3480156101b357600080fd5b506101d5600160a060020a0360043516600160e060020a0319602435166107e7565b604080519115158252519081900360200190f35b3480156101f557600080fd5b506101d5600160a060020a0360043516600160e060020a03196024351661089c565b6000600160a060020a0384161561022e5783610230565b335b90503361023c82610512565b600160a060020a03161461029a576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b6102a38361091c565b156102f8576040805160e560020a62461bcd02815260206004820152601960248201527f4d757374206e6f74206265206120455243313635206861736800000000000000604482015290519081900360640190fd5b600160a060020a038216158015906103195750600160a060020a0382163314155b156104a15760405160200180807f4552433832305f4143434550545f4d414749430000000000000000000000000081525060130190506040516020818303038152906040526040518082805190602001908083835b6020831061038d5780518252601f19909201916020918201910161036e565b51815160209384036101000a6000190180199092169116179052604080519290940182900382207f249cb3fa000000000000000000000000000000000000000000000000000000008352600483018a9052600160a060020a0388811660248501529451909650938816945063249cb3fa936044808401945091929091908290030181600087803b15801561042057600080fd5b505af1158015610434573d6000803e3d6000fd5b505050506040513d602081101561044a57600080fd5b5051146104a1576040805160e560020a62461bcd02815260206004820181905260248201527f446f6573206e6f7420696d706c656d656e742074686520696e74657266616365604482015290519081900360640190fd5b600160a060020a03818116600081815260208181526040808320888452909152808220805473ffffffffffffffffffffffffffffffffffffffff19169487169485179055518692917f93baa6efbd2244243bfee6ce4cfdd1d04fc4c0e9a786abd3a41313bd352db15391a450505050565b600160a060020a03808216600090815260016020526040812054909116151561053c575080610559565b50600160a060020a03808216600090815260016020526040902054165b919050565b3361056883610512565b600160a060020a0316146105c6576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b81600160a060020a031681600160a060020a0316146105e557806105e8565b60005b600160a060020a03838116600081815260016020526040808220805473ffffffffffffffffffffffffffffffffffffffff19169585169590951790945592519184169290917f605c2dbf762e5f7d60a546d42e7205dcb1b011ebc62a61736a57c9089d3a43509190a35050565b60008282604051602001808383808284378201915050925050506040516020818303038152906040526040518082805190602001908083835b602083106106ad5780518252601f19909201916020918201910161068e565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902090505b92915050565b6106ed82826107e7565b6106f85760006106fa565b815b600160a060020a03928316600081815260208181526040808320600160e060020a031996909616808452958252808320805473ffffffffffffffffffffffffffffffffffffffff19169590971694909417909555908152600284528181209281529190925220805460ff19166001179055565b60008080600160a060020a038516156107865784610788565b335b91506107938461091c565b156107b85750826107a4828261089c565b6107af5760006107b1565b815b92506107df565b600160a060020a038083166000908152602081815260408083208884529091529020541692505b505092915050565b60008080610815857f01ffc9a70000000000000000000000000000000000000000000000000000000061093e565b9092509050811580610825575080155b1561083357600092506107df565b61084585600160e060020a031961093e565b909250905081158061085657508015155b1561086457600092506107df565b61086e858561093e565b90925090506001821480156108835750806001145b1561089157600192506107df565b506000949350505050565b600160a060020a0382166000908152600260209081526040808320600160e060020a03198516845290915281205460ff1615156108e4576108dd83836107e7565b90506106dd565b50600160a060020a03808316600081815260208181526040808320600160e060020a0319871684529091529020549091161492915050565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff161590565b6040517f01ffc9a7000000000000000000000000000000000000000000000000000000008082526004820183905260009182919060208160088189617530fa9051909690955093505050505600a165627a7a723058204fc4461c9d5a247b0eafe0f9c508057bc0ad72bc24668cb2a35ea65850e10d3100291ba08208208208208208208208208208208208208208208208208208208208208200a00820820820820820820820820820820820820820820820820820820820820820"; // send 0.08 ether to deployment account sendEther(owner, deployAccount, web3.utils.toWei("0.08",'ether')); diff --git a/test/token/ERC777/ERC777.test.js b/test/token/ERC777/ERC777.test.js index 620de3219e7..87782d10d67 100644 --- a/test/token/ERC777/ERC777.test.js +++ b/test/token/ERC777/ERC777.test.js @@ -15,7 +15,7 @@ require('chai') contract('ERC777', function ([_, holder, operator, anotherAccount]) { const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; - const ERC820_ADDRESS = "0x820A8Cfd018b159837d50656c49d28983f18f33c"; + const ERC820_ADDRESS = "0x820b586C8C28125366C998641B09DCbE7d4cBF06"; const INITIAL_SUPPLY = "10000"; const USER_DATA = "0xabcd"; const OPERATOR_DATA = "0x0a0b0c0d"; From 2db4656b7d894d1c26e7e1e693ce929fcc6206cf Mon Sep 17 00:00:00 2001 From: Bertrand Masius Date: Thu, 31 Jan 2019 07:15:24 +0100 Subject: [PATCH 10/64] ERC777 Move contracts to 'drafts' folder (#1159) --- contracts/{token => drafts}/ERC777/ERC777.sol | 0 contracts/{token => drafts}/ERC777/ERC777Base.sol | 0 contracts/{token => drafts}/ERC777/ERC777Burnable.sol | 0 contracts/{token => drafts}/ERC777/IERC777.sol | 0 contracts/{token => drafts}/ERC777/IERC777TokensRecipient.sol | 0 contracts/{token => drafts}/ERC777/IERC777TokensSender.sol | 0 contracts/mocks/ERC777ReceiverMock.sol | 2 +- contracts/mocks/ERC777SenderMock.sol | 4 ++-- test/{token => drafts}/ERC777/ERC777.test.js | 0 9 files changed, 3 insertions(+), 3 deletions(-) rename contracts/{token => drafts}/ERC777/ERC777.sol (100%) rename contracts/{token => drafts}/ERC777/ERC777Base.sol (100%) rename contracts/{token => drafts}/ERC777/ERC777Burnable.sol (100%) rename contracts/{token => drafts}/ERC777/IERC777.sol (100%) rename contracts/{token => drafts}/ERC777/IERC777TokensRecipient.sol (100%) rename contracts/{token => drafts}/ERC777/IERC777TokensSender.sol (100%) rename test/{token => drafts}/ERC777/ERC777.test.js (100%) diff --git a/contracts/token/ERC777/ERC777.sol b/contracts/drafts/ERC777/ERC777.sol similarity index 100% rename from contracts/token/ERC777/ERC777.sol rename to contracts/drafts/ERC777/ERC777.sol diff --git a/contracts/token/ERC777/ERC777Base.sol b/contracts/drafts/ERC777/ERC777Base.sol similarity index 100% rename from contracts/token/ERC777/ERC777Base.sol rename to contracts/drafts/ERC777/ERC777Base.sol diff --git a/contracts/token/ERC777/ERC777Burnable.sol b/contracts/drafts/ERC777/ERC777Burnable.sol similarity index 100% rename from contracts/token/ERC777/ERC777Burnable.sol rename to contracts/drafts/ERC777/ERC777Burnable.sol diff --git a/contracts/token/ERC777/IERC777.sol b/contracts/drafts/ERC777/IERC777.sol similarity index 100% rename from contracts/token/ERC777/IERC777.sol rename to contracts/drafts/ERC777/IERC777.sol diff --git a/contracts/token/ERC777/IERC777TokensRecipient.sol b/contracts/drafts/ERC777/IERC777TokensRecipient.sol similarity index 100% rename from contracts/token/ERC777/IERC777TokensRecipient.sol rename to contracts/drafts/ERC777/IERC777TokensRecipient.sol diff --git a/contracts/token/ERC777/IERC777TokensSender.sol b/contracts/drafts/ERC777/IERC777TokensSender.sol similarity index 100% rename from contracts/token/ERC777/IERC777TokensSender.sol rename to contracts/drafts/ERC777/IERC777TokensSender.sol diff --git a/contracts/mocks/ERC777ReceiverMock.sol b/contracts/mocks/ERC777ReceiverMock.sol index f1e8ebe4dcc..7e1c53fde81 100644 --- a/contracts/mocks/ERC777ReceiverMock.sol +++ b/contracts/mocks/ERC777ReceiverMock.sol @@ -1,6 +1,6 @@ pragma solidity ^0.4.24; -import "../token/ERC777/IERC777TokensRecipient.sol"; +import "../drafts/ERC777/IERC777TokensRecipient.sol"; import "../introspection/ERC820Client.sol"; /** diff --git a/contracts/mocks/ERC777SenderMock.sol b/contracts/mocks/ERC777SenderMock.sol index 7745974325b..c6366061147 100644 --- a/contracts/mocks/ERC777SenderMock.sol +++ b/contracts/mocks/ERC777SenderMock.sol @@ -1,7 +1,7 @@ pragma solidity ^0.4.24; -import "../token/ERC777/IERC777.sol"; -import "../token/ERC777/IERC777TokensSender.sol"; +import "../drafts/ERC777/IERC777.sol"; +import "../drafts/ERC777/IERC777TokensSender.sol"; import "../introspection/ERC820Client.sol"; /** diff --git a/test/token/ERC777/ERC777.test.js b/test/drafts/ERC777/ERC777.test.js similarity index 100% rename from test/token/ERC777/ERC777.test.js rename to test/drafts/ERC777/ERC777.test.js From d9e53d9ef6dcbc4e4b4d9bfbed5407563e632f42 Mon Sep 17 00:00:00 2001 From: Bertrand Masius Date: Fri, 15 Mar 2019 21:57:36 +0100 Subject: [PATCH 11/64] ERC777: Update to ERC1820 registry and linter error fix (#1159) --- contracts/drafts/ERC777/ERC777.sol | 60 +- contracts/drafts/ERC777/ERC777Base.sol | 824 +++++++++++---------- contracts/drafts/ERC777/ERC777Burnable.sol | 38 +- contracts/drafts/ERC777/IERC777.sol | 84 ++- contracts/introspection/ERC1820Client.sol | 44 ++ contracts/introspection/ERC820Client.sol | 25 - contracts/introspection/IERC1820.sol | 39 + contracts/introspection/IERC820.sol | 12 - contracts/mocks/ERC777ReceiverMock.sol | 10 +- contracts/mocks/ERC777SenderMock.sol | 4 +- test/drafts/ERC777/ERC777.test.js | 20 +- test/introspection/ERC1820Deploy.js | 17 + test/introspection/ERC820Deploy.js | 17 - 13 files changed, 660 insertions(+), 534 deletions(-) create mode 100644 contracts/introspection/ERC1820Client.sol delete mode 100644 contracts/introspection/ERC820Client.sol create mode 100644 contracts/introspection/IERC1820.sol delete mode 100644 contracts/introspection/IERC820.sol create mode 100644 test/introspection/ERC1820Deploy.js delete mode 100644 test/introspection/ERC820Deploy.js diff --git a/contracts/drafts/ERC777/ERC777.sol b/contracts/drafts/ERC777/ERC777.sol index 15c4fac04b9..943183a7ca5 100644 --- a/contracts/drafts/ERC777/ERC777.sol +++ b/contracts/drafts/ERC777/ERC777.sol @@ -10,31 +10,37 @@ import "./ERC777Base.sol"; * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-777.md */ contract ERC777 is ERC777Base { -/* - * @dev constructor - * @param name name of the token - * @param symbol symbol of the token - * @param granularity granularity of token - * @param defaultOperators array of default operators address - * @param initialSupply amount of tokens given to msg.sender - * @param data bytes information attached to the send, and intended for the recipient (to) - * @param operatorData bytes extra information provided by the operator (if any) - */ - constructor( - string name, - string symbol, - uint256 granularity, - address[] defaultOperators, - uint256 initialSupply, - bytes data, - bytes operatorData - ) - ERC777Base( - name, - symbol, - granularity, - defaultOperators - ) public { - _mint(msg.sender, msg.sender, initialSupply, data, operatorData); - } + /* + * @dev constructor + * @param name name of the token + * @param symbol symbol of the token + * @param granularity granularity of token + * @param defaultOperators array of default operators address + * @param initialSupply amount of tokens given to msg.sender + * @param data bytes information attached to the send, and intended for the recipient (to) + * @param operatorData bytes extra information provided by the operator (if any) + */ + constructor( + string name, + string symbol, + uint256 granularity, + address[] defaultOperators, + uint256 initialSupply, + bytes data, + bytes operatorData + ) + ERC777Base( + name, + symbol, + granularity, + defaultOperators + ) public { + _mint( + msg.sender, + msg.sender, + initialSupply, + data, + operatorData + ); + } } diff --git a/contracts/drafts/ERC777/ERC777Base.sol b/contracts/drafts/ERC777/ERC777Base.sol index c7bb49a8b60..889162eb912 100644 --- a/contracts/drafts/ERC777/ERC777Base.sol +++ b/contracts/drafts/ERC777/ERC777Base.sol @@ -5,7 +5,7 @@ import "./IERC777TokensRecipient.sol"; import "./IERC777TokensSender.sol"; import "../../math/SafeMath.sol"; import "../../utils/Address.sol"; -import "../../introspection/ERC820Client.sol"; +import "../../introspection/ERC1820Client.sol"; /** * @title ERC777 token implementation to inherit from @@ -13,417 +13,449 @@ import "../../introspection/ERC820Client.sol"; * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-777.md * @dev inherit from this contract, do not use directly */ -contract ERC777Base is IERC777, ERC820Client { - using SafeMath for uint256; - using Address for address; +contract ERC777Base is IERC777, ERC1820Client { + using SafeMath for uint256; + using Address for address; + + string private _name; + + string private _symbol; + + mapping(address => uint256) private _balances; + + uint256 private _totalSupply; + + uint256 private _granularity; + + address[] private _defaultOpsArray; + + bytes32 constant sendHash = keccak256("ERC777TokensSender"); + bytes32 constant receivedHash = keccak256("ERC777TokensRecipient"); + + mapping(address => bool) private _defaultOps; + mapping(address => mapping(address => bool)) private _revokedDefaultOps; + mapping(address => mapping(address => bool)) private _ops; + + constructor( + string name, + string symbol, + uint256 granularity, + address[] defaultOperators + ) internal { + require(granularity > 0); + _name = name; + _symbol = symbol; + _granularity = granularity; + _defaultOpsArray = defaultOperators; + for (uint i = 0; i < defaultOperators.length; i++) { + _defaultOps[defaultOperators[i]] = true; + } + // register interface + setInterfaceImplementer( + address(this), + keccak256("ERC777Token"), + address(this) + ); + } - string private _name; + /** + * @dev Send the amount of tokens from the address msg.sender to the address to + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param data bytes information attached to the send, and intended for the recipient (to) + */ + function send( + address to, + uint256 amount, + bytes data + ) external { + _send( + msg.sender, + msg.sender, + to, + amount, + data, + "" + ); + } - string private _symbol; + /** + * @dev Send the amount of tokens on behalf of the address from to the address to + * @param from address token holder address. Set to 0x0 to use msg.sender as token holder + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param data bytes information attached to the send, and intended for the recipient (to) + * @param operatorData bytes extra information provided by the operator (if any) + */ + function operatorSend( + address from, + address to, + uint256 amount, + bytes data, + bytes operatorData + ) + external + { + address holder = from == address(0) ? msg.sender : from; + _send( + msg.sender, + holder, + to, + amount, + data, + operatorData + ); + } - mapping(address => uint256) private _balances; + /** + * @dev Burn the amount of tokens from the address msg.sender + * @param amount uint256 amount of tokens to transfer + */ + function burn(uint256 amount) external { + _burn( + msg.sender, + msg.sender, + amount, + "" + ); + } - uint256 private _totalSupply; + /** + * @dev Burn the amount of tokens on behalf of the address from + * @param from address token holder address. Set to 0x0 to use msg.sender as token holder + * @param amount uint256 amount of tokens to transfer + * @param operatorData bytes extra information provided by the operator (if any) + */ + function operatorBurn( + address from, + uint256 amount, + bytes operatorData + ) + external + { + address holder = from == address(0) ? msg.sender : from; + _burn( + msg.sender, + holder, + amount, + operatorData + ); + } - uint256 private _granularity; + /** + * @return the name of the token. + */ + function name() public view returns (string) { + return _name; + } - address[] private _defaultOpsArray; + /** + * @return the symbol of the token. + */ + function symbol() public view returns (string) { + return _symbol; + } - bytes32 constant sendHash = keccak256('ERC777TokensSender'); - bytes32 constant receivedHash = keccak256('ERC777TokensRecipient'); + /** + * @dev Total number of tokens in existence + */ + function totalSupply() public view returns (uint256) { + return _totalSupply; + } - mapping(address => bool) private _defaultOps; - mapping(address => mapping(address => bool)) private _revokedDefaultOps; - mapping(address => mapping(address => bool)) private _ops; + /** + * @dev Gets the balance of the specified address. + * @param tokenHolder The address to query the balance of. + * @return uint256 representing the amount owned by the specified address. + */ + function balanceOf(address tokenHolder) public view returns (uint256) { + return _balances[tokenHolder]; + } - constructor( - string name, - string symbol, - uint256 granularity, - address[] defaultOperators - ) internal { - require(granularity > 0); - _name = name; - _symbol = symbol; - _granularity = granularity; - _defaultOpsArray = defaultOperators; - for (uint i = 0; i < defaultOperators.length; i++) { - _defaultOps[defaultOperators[i]] = true; + /** + * @dev Gets the token's granularity, + * i.e. the smallest number of tokens (in the basic unit) + * which may be minted, sent or burned at any time + * @return uint256 granularity + */ + function granularity() public view returns (uint256) { + return _granularity; } - // register interface - setInterfaceImplementer(address(this), keccak256("ERC777Token"), address(this)); - } - - /** - * @return the name of the token. - */ - function name() public view returns (string) { - return _name; - } - - /** - * @return the symbol of the token. - */ - function symbol() public view returns (string) { - return _symbol; - } - - /** - * @dev Total number of tokens in existence - */ - function totalSupply() public view returns (uint256) { - return _totalSupply; - } - - /** - * @dev Gets the balance of the specified address. - * @param tokenHolder The address to query the balance of. - * @return uint256 representing the amount owned by the specified address. - */ - function balanceOf(address tokenHolder) public view returns (uint256) { - return _balances[tokenHolder]; - } - - /** - * @dev Gets the token's granularity, - * i.e. the smallest number of tokens (in the basic unit) - * which may be minted, sent or burned at any time - * @return uint256 granularity - */ - function granularity() public view returns (uint256) { - return _granularity; - } - - /** - * @dev Get the list of default operators as defined by the token contract. - * @return address[] default operators - */ - function defaultOperators() public view returns (address[]) { - return _defaultOpsArray; - } - - /** - * @dev Authorize an operator for the sender - * @param operator address to be authorized as operator - */ - function authorizeOperator(address operator) public { - require(msg.sender != operator); - if (_defaultOps[operator]) { - _reAuthorizeDefaultOperator(operator); - } else _authorizeOperator(operator); - } - - /** - * @dev Revoke operator rights from one of the default operators - * @param operator address to revoke operator rights from - */ - function revokeOperator(address operator) public { - require(operator != msg.sender); - if (_defaultOps[operator]) { - _revokeDefaultOperator(operator); - } else _revokeOperator(operator); - } - - /** - * @dev Indicate whether an address - * is an operator of the tokenHolder address - * @param operator address which may be an operator of tokenHolder - * @param tokenHolder address of a token holder which may have the operator - * address as an operator. - */ - function isOperatorFor( - address operator, - address tokenHolder - ) public view returns (bool) { - return - operator == tokenHolder || - _defaultOps[operator] && !_revokedDefaultOps[tokenHolder][operator] || - _ops[tokenHolder][operator]; - } - - /** - * @dev Send the amount of tokens from the address msg.sender to the address to - * @param to address recipient address - * @param amount uint256 amount of tokens to transfer - * @param data bytes information attached to the send, and intended for the recipient (to) - */ - function send(address to, uint256 amount, bytes data) external { - _send(msg.sender, msg.sender, to, amount, data, ""); - } - - /** - * @dev Send the amount of tokens on behalf of the address from to the address to - * @param from address token holder address. Set to 0x0 to use msg.sender as token holder - * @param to address recipient address - * @param amount uint256 amount of tokens to transfer - * @param data bytes information attached to the send, and intended for the recipient (to) - * @param operatorData bytes extra information provided by the operator (if any) - */ - function operatorSend( - address from, - address to, - uint256 amount, - bytes data, - bytes operatorData - ) - external - { - address holder = from == address(0) ? msg.sender : from; - _send(msg.sender, holder, to, amount, data, operatorData); - } - - /** - * @dev Burn the amount of tokens from the address msg.sender - * @param amount uint256 amount of tokens to transfer - */ - function burn(uint256 amount) external { - _burn(msg.sender, msg.sender, amount, ""); - } - - /** - * @dev Burn the amount of tokens on behalf of the address from - * @param from address token holder address. Set to 0x0 to use msg.sender as token holder - * @param amount uint256 amount of tokens to transfer - * @param operatorData bytes extra information provided by the operator (if any) - */ - function operatorBurn( - address from, - uint256 amount, - bytes operatorData - ) - external - { - address holder = from == address(0) ? msg.sender : from; - _burn(msg.sender, holder, amount, operatorData); - } - - /** - * @dev Authorize an operator for the sender - * @param operator address to be authorized as operator - */ - function _authorizeOperator(address operator) private { - _ops[msg.sender][operator] = true; - emit AuthorizedOperator(operator, msg.sender); - } - - /** - * @dev Re-authorize a previously revoked default operator - * @param operator address to be re-authorized as operator - */ - function _reAuthorizeDefaultOperator(address operator) private { - delete _revokedDefaultOps[msg.sender][operator]; - emit AuthorizedOperator(operator, msg.sender); - } - - /** - * @dev Revoke operator rights from one of the default operators - * @param operator address to revoke operator rights from - */ - function _revokeDefaultOperator(address operator) private { - _revokedDefaultOps[msg.sender][operator] = true; - emit RevokedOperator(operator, msg.sender); - } - - /** - * @dev Revoke an operator for the sender - * @param operator address to revoke operator rights from - */ - function _revokeOperator(address operator) private { - delete _ops[msg.sender][operator]; - emit RevokedOperator(operator, msg.sender); - } - - /** - * @dev Burn tokens - * @param operator address operator requesting the operation - * @param from address token holder address - * @param amount uint256 amount of tokens to burn - * @param operatorData bytes extra information provided by the operator (if any) - */ - function _burn( - address operator, - address from, - uint256 amount, - bytes operatorData - ) + + /** + * @dev Get the list of default operators as defined by the token contract. + * @return address[] default operators + */ + function defaultOperators() public view returns (address[]) { + return _defaultOpsArray; + } + + /** + * @dev Authorize an operator for the sender + * @param operator address to be authorized as operator + */ + function authorizeOperator(address operator) public { + require(msg.sender != operator); + if (_defaultOps[operator]) { + _reAuthorizeDefaultOperator(operator); + } else _authorizeOperator(operator); + } + + /** + * @dev Revoke operator rights from one of the default operators + * @param operator address to revoke operator rights from + */ + function revokeOperator(address operator) public { + require(operator != msg.sender); + if (_defaultOps[operator]) { + _revokeDefaultOperator(operator); + } else _revokeOperator(operator); + } + + /** + * @dev Indicate whether an address + * is an operator of the tokenHolder address + * @param operator address which may be an operator of tokenHolder + * @param tokenHolder address of a token holder which may have the operator + * address as an operator. + */ + function isOperatorFor( + address operator, + address tokenHolder + ) public view returns (bool) { + return + operator == tokenHolder || + _defaultOps[operator] && !_revokedDefaultOps[tokenHolder][operator] || + _ops[tokenHolder][operator]; + } + + /** + * @dev Burn tokens + * @param operator address operator requesting the operation + * @param from address token holder address + * @param amount uint256 amount of tokens to burn + * @param operatorData bytes extra information provided by the operator (if any) + */ + function _burn( + address operator, + address from, + uint256 amount, + bytes operatorData + ) internal - { - require(from != address(0)); - require(isOperatorFor(msg.sender, from)); - - _callTokensToSend( - operator, - from, - address(0), - amount, - "", - operatorData - ); - - // Update state variables - _totalSupply = _totalSupply.sub(amount); - _balances[from] = _balances[from].sub(amount); - require((_balances[from] % _granularity) == 0); - - emit Burned(operator, from, amount, operatorData); - } - - /** - * @dev Mint tokens. Does not check authorization of operator - * @dev the caller may ckeck that operator is authorized before calling - * @param operator address operator requesting the operation - * @param to address token recipient address - * @param amount uint256 amount of tokens to mint - * @param userData bytes extra information defined by the token recipient (if any) - * @param operatorData bytes extra information provided by the operator (if any) - */ - function _mint( - address operator, - address to, - uint256 amount, - bytes userData, - bytes operatorData - ) + { + require(from != address(0)); + require(isOperatorFor(msg.sender, from)); + + _callTokensToSend( + operator, + from, + address(0), + amount, + "", + operatorData + ); + + // Update state variables + _totalSupply = _totalSupply.sub(amount); + _balances[from] = _balances[from].sub(amount); + require((_balances[from] % _granularity) == 0); + + emit Burned(operator, from, amount, operatorData); + } + + /** + * @dev Mint tokens. Does not check authorization of operator + * @dev the caller may ckeck that operator is authorized before calling + * @param operator address operator requesting the operation + * @param to address token recipient address + * @param amount uint256 amount of tokens to mint + * @param userData bytes extra information defined by the token recipient (if any) + * @param operatorData bytes extra information provided by the operator (if any) + */ + function _mint( + address operator, + address to, + uint256 amount, + bytes userData, + bytes operatorData + ) internal - { - require(to != address(0)); - - // revert if 'to' is a contract not implementing tokensReceived() - require( - _callTokensReceived( - operator, - address(0), - to, - amount, - userData, - operatorData - ) - ); - - // Update state variables - _totalSupply = _totalSupply.add(amount); - _balances[to] = _balances[to].add(amount); - require((_balances[to] % _granularity) == 0); - - emit Minted(operator, to, amount, userData, operatorData); - } - - /** - * @dev Send tokens - * @param operator address operator requesting the transfer - * @param from address token holder address - * @param to address recipient address - * @param amount uint256 amount of tokens to transfer - * @param userData bytes extra information provided by the token holder (if any) - * @param operatorData bytes extra information provided by the operator (if any) - */ - function _send( - address operator, - address from, - address to, - uint256 amount, - bytes userData, - bytes operatorData - ) + { + require(to != address(0)); + + // revert if 'to' is a contract not implementing tokensReceived() + require( + _callTokensReceived( + operator, + address(0), + to, + amount, + userData, + operatorData + ) + ); + + // Update state variables + _totalSupply = _totalSupply.add(amount); + _balances[to] = _balances[to].add(amount); + require((_balances[to] % _granularity) == 0); + + emit Minted(operator, to, amount, userData, operatorData); + } + + /** + * @dev Authorize an operator for the sender + * @param operator address to be authorized as operator + */ + function _authorizeOperator(address operator) private { + _ops[msg.sender][operator] = true; + emit AuthorizedOperator(operator, msg.sender); + } + + /** + * @dev Re-authorize a previously revoked default operator + * @param operator address to be re-authorized as operator + */ + function _reAuthorizeDefaultOperator(address operator) private { + delete _revokedDefaultOps[msg.sender][operator]; + emit AuthorizedOperator(operator, msg.sender); + } + + /** + * @dev Revoke operator rights from one of the default operators + * @param operator address to revoke operator rights from + */ + function _revokeDefaultOperator(address operator) private { + _revokedDefaultOps[msg.sender][operator] = true; + emit RevokedOperator(operator, msg.sender); + } + + /** + * @dev Revoke an operator for the sender + * @param operator address to revoke operator rights from + */ + function _revokeOperator(address operator) private { + delete _ops[msg.sender][operator]; + emit RevokedOperator(operator, msg.sender); + } + + /** + * @dev Send tokens + * @param operator address operator requesting the transfer + * @param from address token holder address + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param userData bytes extra information provided by the token holder (if any) + * @param operatorData bytes extra information provided by the operator (if any) + */ + function _send( + address operator, + address from, + address to, + uint256 amount, + bytes userData, + bytes operatorData + ) private - { - require(from != address(0)); - require(to != address(0)); - require(isOperatorFor(msg.sender, from)); - - _callTokensToSend( - operator, - from, - to, - amount, - userData, - operatorData - ); - - // Update state variables - _balances[from] = _balances[from].sub(amount); - _balances[to] = _balances[to].add(amount); - require((_balances[from] % _granularity) == 0); - require((_balances[to] % _granularity) == 0); - - _callTokensReceived( - operator, - from, - to, - amount, - userData, - operatorData - ); - - emit Sent(msg.sender, from, to, amount, userData, operatorData); - } - - /** - * @dev Call from.tokensToSend() if the interface is registered - * @param operator address operator requesting the transfer - * @param from address token holder address - * @param to address recipient address - * @param amount uint256 amount of tokens to transfer - * @param userData bytes extra information provided by the token holder (if any) - * @param operatorData bytes extra information provided by the operator (if any) - */ - function _callTokensToSend( - address operator, - address from, - address to, - uint256 amount, - bytes userData, - bytes operatorData - ) + { + require(from != address(0)); + require(to != address(0)); + require(isOperatorFor(msg.sender, from)); + + _callTokensToSend( + operator, + from, + to, + amount, + userData, + operatorData + ); + + // Update state variables + _balances[from] = _balances[from].sub(amount); + _balances[to] = _balances[to].add(amount); + require((_balances[from] % _granularity) == 0); + require((_balances[to] % _granularity) == 0); + + _callTokensReceived( + operator, + from, + to, + amount, + userData, + operatorData + ); + + emit Sent(msg.sender, from, to, amount, userData, operatorData); + } + + /** + * @dev Call from.tokensToSend() if the interface is registered + * @param operator address operator requesting the transfer + * @param from address token holder address + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param userData bytes extra information provided by the token holder (if any) + * @param operatorData bytes extra information provided by the operator (if any) + */ + function _callTokensToSend( + address operator, + address from, + address to, + uint256 amount, + bytes userData, + bytes operatorData + ) private - { - address implementer = getInterfaceImplementer(from, sendHash); - if (implementer != address(0)) { - IERC777TokensSender(implementer).tokensToSend( - operator, - from, - to, - amount, - userData, - operatorData - ); + { + address implementer = getInterfaceImplementer(from, sendHash); + if (implementer != address(0)) { + IERC777TokensSender(implementer).tokensToSend( + operator, + from, + to, + amount, + userData, + operatorData + ); + } } - } - - /** - * @dev Call to.tokensReceived() if the interface is registered - * @param operator address operator requesting the transfer - * @param from address token holder address - * @param to address recipient address - * @param amount uint256 amount of tokens to transfer - * @param userData bytes extra information provided by the token holder (if any) - * @param operatorData bytes extra information provided by the operator (if any) - * @return false if the recipient is a contract but tokensReceived() was not - * registered for the recipient - */ - function _callTokensReceived( - address operator, - address from, - address to, - uint256 amount, - bytes userData, - bytes operatorData - ) + + /** + * @dev Call to.tokensReceived() if the interface is registered + * @param operator address operator requesting the transfer + * @param from address token holder address + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param userData bytes extra information provided by the token holder (if any) + * @param operatorData bytes extra information provided by the operator (if any) + * @return false if the recipient is a contract but tokensReceived() was not + * registered for the recipient + */ + function _callTokensReceived( + address operator, + address from, + address to, + uint256 amount, + bytes userData, + bytes operatorData + ) private returns(bool) - { - address implementer = getInterfaceImplementer(to, receivedHash); - if (implementer == address(0)) { - return(! to.isContract()); + { + address implementer = getInterfaceImplementer(to, receivedHash); + if (implementer == address(0)) { + return(! to.isContract()); + } + IERC777TokensRecipient(implementer).tokensReceived( + operator, + from, + to, + amount, + userData, + operatorData + ); + return true; } - IERC777TokensRecipient(implementer).tokensReceived( - operator, - from, - to, - amount, - userData, - operatorData - ); - return true; - } } diff --git a/contracts/drafts/ERC777/ERC777Burnable.sol b/contracts/drafts/ERC777/ERC777Burnable.sol index c85734f634d..1794e75bb71 100644 --- a/contracts/drafts/ERC777/ERC777Burnable.sol +++ b/contracts/drafts/ERC777/ERC777Burnable.sol @@ -10,22 +10,26 @@ import "./ERC777Base.sol"; */ contract ERC777Burnable is ERC777Base { - /** - * @dev Burn the amount of tokens from the address msg.sender - * @param amount uint256 amount of tokens to transfer - */ - function burn(uint256 amount) external { - _burn(msg.sender, msg.sender, amount, ""); - } + /** + * @dev Burn the amount of tokens from the address msg.sender + * @param amount uint256 amount of tokens to transfer + */ + function burn(uint256 amount) external { + _burn(msg.sender, msg.sender, amount, ""); + } - /** - * @dev Burn the amount of tokens on behalf of the address from - * @param from address token holder address. Set to 0x0 to use msg.sender as token holder - * @param amount uint256 amount of tokens to transfer - * @param operatorData bytes extra information provided by the operator (if any) - */ - function operatorBurn(address from, uint256 amount, bytes operatorData) external { - address holder = from == address(0) ? msg.sender : from; - _burn(msg.sender, holder, amount, operatorData); - } + /** + * @dev Burn the amount of tokens on behalf of the address from + * @param from address token holder address. Set to 0x0 to use msg.sender as token holder + * @param amount uint256 amount of tokens to transfer + * @param operatorData bytes extra information provided by the operator (if any) + */ + function operatorBurn( + address from, + uint256 amount, + bytes operatorData + ) external { + address holder = from == address(0) ? msg.sender : from; + _burn(msg.sender, holder, amount, operatorData); + } } diff --git a/contracts/drafts/ERC777/IERC777.sol b/contracts/drafts/ERC777/IERC777.sol index f88bd08baab..868b2f6f456 100644 --- a/contracts/drafts/ERC777/IERC777.sol +++ b/contracts/drafts/ERC777/IERC777.sol @@ -5,42 +5,76 @@ pragma solidity ^0.4.24; * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-777.md */ interface IERC777 { - function name() external view returns (string); + function name() external view returns (string); - function symbol() external view returns (string); + function symbol() external view returns (string); - function totalSupply() external view returns (uint256); + function totalSupply() external view returns (uint256); - function balanceOf(address owner) external view returns (uint256); + function balanceOf(address owner) external view returns (uint256); - function granularity() external view returns (uint256); + function granularity() external view returns (uint256); - function defaultOperators() external view returns (address[]); + function defaultOperators() external view returns (address[]); - function authorizeOperator(address operator) external; + function authorizeOperator(address operator) external; - function revokeOperator(address operator) external; + function revokeOperator(address operator) external; - function isOperatorFor(address operator, address tokenHolder) external view returns (bool); + function isOperatorFor( + address operator, + address tokenHolder + ) external view returns (bool); - function send(address to, uint256 amount, bytes data) external; + function send(address to, uint256 amount, bytes data) external; - function operatorSend(address from, address to, uint256 amount, bytes data, bytes operatorData) external; + function operatorSend( + address from, + address to, + uint256 amount, + bytes data, + bytes operatorData + ) external; - function burn(uint256 amount) external; + function burn(uint256 amount) external; - function operatorBurn(address from, uint256 amount, bytes operatorData) external; + function operatorBurn( + address from, + uint256 amount, + bytes operatorData + ) external; - event Sent( - address indexed operator, - address indexed from, - address indexed to, - uint256 amount, - bytes data, - bytes operatorData - ); - event Minted(address indexed operator, address indexed to, uint256 amount, bytes data, bytes operatorData); - event Burned(address indexed operator, address indexed from, uint256 amount, bytes operatorData); - event AuthorizedOperator(address indexed operator, address indexed tokenHolder); - event RevokedOperator(address indexed operator, address indexed tokenHolder); + event Sent( + address indexed operator, + address indexed from, + address indexed to, + uint256 amount, + bytes data, + bytes operatorData + ); + + event Minted( + address indexed operator, + address indexed to, + uint256 amount, + bytes data, + bytes operatorData + ); + + event Burned( + address indexed operator, + address indexed from, + uint256 amount, + bytes operatorData + ); + + event AuthorizedOperator( + address indexed operator, + address indexed tokenHolder + ); + + event RevokedOperator( + address indexed operator, + address indexed tokenHolder + ); } diff --git a/contracts/introspection/ERC1820Client.sol b/contracts/introspection/ERC1820Client.sol new file mode 100644 index 00000000000..1e5ab73b93d --- /dev/null +++ b/contracts/introspection/ERC1820Client.sol @@ -0,0 +1,44 @@ +pragma solidity ^0.4.24; + +import "./IERC1820.sol"; + +/** + * @title ERC1820 client implementation + * @dev https://eips.ethereum.org/EIPS/eip-1820 + * @author Bertrand Masius + */ +contract ERC1820Client { + + IERC1820 private _erc1820 = + IERC1820(0x1820b744B33945482C17Dc37218C01D858EBc714); + + function getInterfaceImplementer( + address addr, + bytes32 hash + ) internal view returns(address) { + return _erc1820.getInterfaceImplementer(addr, hash); + } + + function setInterfaceImplementer( + address addr, + bytes32 hash, + address implementer + ) internal { + _erc1820.setInterfaceImplementer(addr, hash, implementer); + } + + function updateERC165Cache(address _contract, bytes4 _interfaceId) internal { + _erc1820.updateERC165Cache(_contract, _interfaceId); + } + + function implementsERC165Interface( + address _contract, + bytes4 _interfaceId + ) internal view returns (bool) { + return _erc1820.implementsERC165Interface(_contract, _interfaceId); + } + + function getERC1820Registry() public view returns(address) { + return address(_erc1820); + } +} diff --git a/contracts/introspection/ERC820Client.sol b/contracts/introspection/ERC820Client.sol deleted file mode 100644 index 18a9c48adef..00000000000 --- a/contracts/introspection/ERC820Client.sol +++ /dev/null @@ -1,25 +0,0 @@ -pragma solidity ^0.4.24; - -import "./IERC820.sol"; - -/** - * @title ERC820 client implementation - * @dev https://eips.ethereum.org/EIPS/eip-820 - * @author Bertrand Masius - */ -contract ERC820Client { - - IERC820 private _erc820 = IERC820(0x820b586C8C28125366C998641B09DCbE7d4cBF06); - - function getInterfaceImplementer(address addr, bytes32 hash) internal view returns(address) { - return _erc820.getInterfaceImplementer(addr, hash); - } - - function setInterfaceImplementer(address addr, bytes32 hash, address implementer) internal { - _erc820.setInterfaceImplementer(addr, hash, implementer); - } - - function getERC820Registry() public view returns(address) { - return address(_erc820); - } -} diff --git a/contracts/introspection/IERC1820.sol b/contracts/introspection/IERC1820.sol new file mode 100644 index 00000000000..18ea4e1c887 --- /dev/null +++ b/contracts/introspection/IERC1820.sol @@ -0,0 +1,39 @@ +pragma solidity ^0.4.24; + +/** + * @title IERC1820 + * @dev https://eips.ethereum.org/EIPS/eip-1820 + */ +interface IERC1820 { + function setInterfaceImplementer( + address _addr, + bytes32 _interfaceHash, + address _implementer + ) external; + + function getInterfaceImplementer( + address _addr, + bytes32 _interfaceHash + ) external view returns (address); + + function setManager( + address _addr, + address _newManager + ) external; + + function getManager(address _addr) external view returns(address); + + function interfaceHash( + string _interfaceName + ) external pure returns(bytes32); + + function updateERC165Cache( + address _contract, + bytes4 _interfaceId + ) external; + + function implementsERC165Interface( + address _contract, + bytes4 _interfaceId + ) public view returns (bool); +} diff --git a/contracts/introspection/IERC820.sol b/contracts/introspection/IERC820.sol deleted file mode 100644 index db0f775317f..00000000000 --- a/contracts/introspection/IERC820.sol +++ /dev/null @@ -1,12 +0,0 @@ -pragma solidity ^0.4.24; - -/** - * @title IERC820 - * @dev https://eips.ethereum.org/EIPS/eip-820 - */ -interface IERC820 { - function setInterfaceImplementer(address _addr, bytes32 _interfaceHash, address _implementer) external; - function getInterfaceImplementer(address _addr, bytes32 _interfaceHash) external view returns (address); - function setManager(address _addr, address _newManager) external; - function getManager(address _addr) external view returns(address); -} diff --git a/contracts/mocks/ERC777ReceiverMock.sol b/contracts/mocks/ERC777ReceiverMock.sol index 7e1c53fde81..d733045bfd1 100644 --- a/contracts/mocks/ERC777ReceiverMock.sol +++ b/contracts/mocks/ERC777ReceiverMock.sol @@ -1,14 +1,14 @@ pragma solidity ^0.4.24; import "../drafts/ERC777/IERC777TokensRecipient.sol"; -import "../introspection/ERC820Client.sol"; +import "../introspection/ERC1820Client.sol"; /** * @title ERC777TokensRecipientMock a contract that implements tokensReceived() hook * @author Bertrand Masius * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-777.md */ -contract ERC777ReceiverMock is IERC777TokensRecipient, ERC820Client { +contract ERC777ReceiverMock is IERC777TokensRecipient, ERC1820Client { event TokensReceived( address indexed operator, @@ -22,7 +22,11 @@ contract ERC777ReceiverMock is IERC777TokensRecipient, ERC820Client { constructor(bool setInterface) public { // register interface if (setInterface) { - setInterfaceImplementer(address(this), keccak256("ERC777TokensRecipient"), address(this)); + setInterfaceImplementer( + address(this), + keccak256("ERC777TokensRecipient"), + address(this) + ); } } diff --git a/contracts/mocks/ERC777SenderMock.sol b/contracts/mocks/ERC777SenderMock.sol index c6366061147..f2437535efc 100644 --- a/contracts/mocks/ERC777SenderMock.sol +++ b/contracts/mocks/ERC777SenderMock.sol @@ -2,14 +2,14 @@ pragma solidity ^0.4.24; import "../drafts/ERC777/IERC777.sol"; import "../drafts/ERC777/IERC777TokensSender.sol"; -import "../introspection/ERC820Client.sol"; +import "../introspection/ERC1820Client.sol"; /** * @title ERC777TokensSenderMock a contract that implements tokensToSend() hook * @author Bertrand Masius * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-777.md */ -contract ERC777SenderMock is IERC777TokensSender, ERC820Client { +contract ERC777SenderMock is IERC777TokensSender, ERC1820Client { address private _erc777; diff --git a/test/drafts/ERC777/ERC777.test.js b/test/drafts/ERC777/ERC777.test.js index 87782d10d67..6e5eb838132 100644 --- a/test/drafts/ERC777/ERC777.test.js +++ b/test/drafts/ERC777/ERC777.test.js @@ -1,9 +1,9 @@ const {assertRevert} = require('../../helpers/assertRevert'); const expectEvent = require('../../helpers/expectEvent'); -const {ERC820Deploy} = require('../../introspection/ERC820Deploy'); +const {ERC1820Deploy} = require('../../introspection/ERC1820Deploy'); const ERC777 = artifacts.require('ERC777'); -const ERC820 = artifacts.require('IERC820'); +const ERC1820 = artifacts.require('IERC1820'); const ERC777TokensRecipient = artifacts.require('ERC777ReceiverMock'); const ERC777TokensSender = artifacts.require('ERC777SenderMock'); @@ -15,18 +15,18 @@ require('chai') contract('ERC777', function ([_, holder, operator, anotherAccount]) { const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; - const ERC820_ADDRESS = "0x820b586C8C28125366C998641B09DCbE7d4cBF06"; + const ERC1820_ADDRESS = "0x1820b744B33945482C17Dc37218C01D858EBc714"; const INITIAL_SUPPLY = "10000"; const USER_DATA = "0xabcd"; const OPERATOR_DATA = "0x0a0b0c0d"; const GRANULARITY = "1"; - before('Deploy ERC820', async function () { + before('Deploy ERC1820', async function () { try { - this.ERC820Registry = await ERC820.at(ERC820_ADDRESS); + this.ERC1820Registry = await ERC1820.at(ERC1820_ADDRESS); } catch(error) { - let address = await ERC820Deploy(holder); - this.ERC820Registry = await ERC820.at(address); + let address = await ERC1820Deploy(holder); + this.ERC1820Registry = await ERC1820.at(address); } }); @@ -50,10 +50,10 @@ contract('ERC777', function ([_, holder, operator, anotherAccount]) { this.token = await ERC777.at(instance.options.address); }); - describe('ERC820 Registry', function () { + describe('ERC1820 Registry', function () { it('hardcoded address in ERC777 contract is correct', async function () { - let erc820 = await this.token.getERC820Registry(); - erc820.should.be.equal(this.ERC820Registry.address); + let erc1820 = await this.token.getERC1820Registry(); + erc1820.should.be.equal(this.ERC1820Registry.address); }); }); diff --git a/test/introspection/ERC1820Deploy.js b/test/introspection/ERC1820Deploy.js new file mode 100644 index 00000000000..34e7bc0c12b --- /dev/null +++ b/test/introspection/ERC1820Deploy.js @@ -0,0 +1,17 @@ +const BN = web3.utils.BN; +const { sendEther } = require('../helpers/sendTransaction'); + +const ERC1820Deploy = async function (owner) { + const deployAccount = "0x5808bA8E60E0367C9067b328D75C1f3d29de58cf"; + const deployTx = "0xf90a388085174876e800830c35008080b909e5608060405234801561001057600080fd5b506109c5806100206000396000f3fe608060405234801561001057600080fd5b50600436106100a5576000357c010000000000000000000000000000000000000000000000000000000090048063a41e7d5111610078578063a41e7d51146101d4578063aabbb8ca1461020a578063b705676514610236578063f712f3e814610280576100a5565b806329965a1d146100aa5780633d584063146100e25780635df8122f1461012457806365ba36c114610152575b600080fd5b6100e0600480360360608110156100c057600080fd5b50600160a060020a038135811691602081013591604090910135166102b6565b005b610108600480360360208110156100f857600080fd5b5035600160a060020a0316610570565b60408051600160a060020a039092168252519081900360200190f35b6100e06004803603604081101561013a57600080fd5b50600160a060020a03813581169160200135166105bc565b6101c26004803603602081101561016857600080fd5b81019060208101813564010000000081111561018357600080fd5b82018360208201111561019557600080fd5b803590602001918460018302840111640100000000831117156101b757600080fd5b5090925090506106b3565b60408051918252519081900360200190f35b6100e0600480360360408110156101ea57600080fd5b508035600160a060020a03169060200135600160e060020a0319166106ee565b6101086004803603604081101561022057600080fd5b50600160a060020a038135169060200135610778565b61026c6004803603604081101561024c57600080fd5b508035600160a060020a03169060200135600160e060020a0319166107ef565b604080519115158252519081900360200190f35b61026c6004803603604081101561029657600080fd5b508035600160a060020a03169060200135600160e060020a0319166108aa565b6000600160a060020a038416156102cd57836102cf565b335b9050336102db82610570565b600160a060020a031614610339576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b6103428361092a565b15610397576040805160e560020a62461bcd02815260206004820152601a60248201527f4d757374206e6f7420626520616e204552433136352068617368000000000000604482015290519081900360640190fd5b600160a060020a038216158015906103b85750600160a060020a0382163314155b156104ff5760405160200180807f455243313832305f4143434550545f4d4147494300000000000000000000000081525060140190506040516020818303038152906040528051906020012082600160a060020a031663249cb3fa85846040518363ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018083815260200182600160a060020a0316600160a060020a031681526020019250505060206040518083038186803b15801561047e57600080fd5b505afa158015610492573d6000803e3d6000fd5b505050506040513d60208110156104a857600080fd5b5051146104ff576040805160e560020a62461bcd02815260206004820181905260248201527f446f6573206e6f7420696d706c656d656e742074686520696e74657266616365604482015290519081900360640190fd5b600160a060020a03818116600081815260208181526040808320888452909152808220805473ffffffffffffffffffffffffffffffffffffffff19169487169485179055518692917f93baa6efbd2244243bfee6ce4cfdd1d04fc4c0e9a786abd3a41313bd352db15391a450505050565b600160a060020a03818116600090815260016020526040812054909116151561059a5750806105b7565b50600160a060020a03808216600090815260016020526040902054165b919050565b336105c683610570565b600160a060020a031614610624576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b81600160a060020a031681600160a060020a0316146106435780610646565b60005b600160a060020a03838116600081815260016020526040808220805473ffffffffffffffffffffffffffffffffffffffff19169585169590951790945592519184169290917f605c2dbf762e5f7d60a546d42e7205dcb1b011ebc62a61736a57c9089d3a43509190a35050565b600082826040516020018083838082843780830192505050925050506040516020818303038152906040528051906020012090505b92915050565b6106f882826107ef565b610703576000610705565b815b600160a060020a03928316600081815260208181526040808320600160e060020a031996909616808452958252808320805473ffffffffffffffffffffffffffffffffffffffff19169590971694909417909555908152600284528181209281529190925220805460ff19166001179055565b600080600160a060020a038416156107905783610792565b335b905061079d8361092a565b156107c357826107ad82826108aa565b6107b85760006107ba565b815b925050506106e8565b600160a060020a0390811660009081526020818152604080832086845290915290205416905092915050565b6000808061081d857f01ffc9a70000000000000000000000000000000000000000000000000000000061094c565b909250905081158061082d575080155b1561083d576000925050506106e8565b61084f85600160e060020a031961094c565b909250905081158061086057508015155b15610870576000925050506106e8565b61087a858561094c565b909250905060018214801561088f5750806001145b1561089f576001925050506106e8565b506000949350505050565b600160a060020a0382166000908152600260209081526040808320600160e060020a03198516845290915281205460ff1615156108f2576108eb83836107ef565b90506106e8565b50600160a060020a03808316600081815260208181526040808320600160e060020a0319871684529091529020549091161492915050565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff161590565b6040517f01ffc9a7000000000000000000000000000000000000000000000000000000008082526004820183905260009182919060208160248189617530fa90519096909550935050505056fea165627a7a723058207d33f0c34a1016c7fcf5f8547cd8c09a74f837ed2564550f647531f1128056ec00291ba01820182018201820182018201820182018201820182018201820182018201820a01820182018201820182018201820182018201820182018201820182018201820"; + + // send 0.08 ether to deployment account + sendEther(owner, deployAccount, web3.utils.toWei("0.08",'ether')); + // create ERC1820 contract + let address = (await web3.eth.sendSignedTransaction(deployTx)).contractAddress; + return address; +}; + +module.exports = { + ERC1820Deploy, +}; diff --git a/test/introspection/ERC820Deploy.js b/test/introspection/ERC820Deploy.js deleted file mode 100644 index da7bd3d15ea..00000000000 --- a/test/introspection/ERC820Deploy.js +++ /dev/null @@ -1,17 +0,0 @@ -const BN = web3.utils.BN; -const { sendEther } = require('../helpers/sendTransaction'); - -const ERC820Deploy = async function (owner) { - const deployAccount = "0xE6C244a1C10Aa0085b0cf92f04cdaD947C2988b8"; - const deployTx = "0xf90a2a8085174876e800830c35008080b909d7608060405234801561001057600080fd5b506109b7806100206000396000f30060806040526004361061008d5763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166329965a1d81146100925780633d584063146100bf5780635df8122f146100fc57806365ba36c114610123578063a41e7d5114610155578063aabbb8ca14610183578063b7056765146101a7578063f712f3e8146101e9575b600080fd5b34801561009e57600080fd5b506100bd600160a060020a036004358116906024359060443516610217565b005b3480156100cb57600080fd5b506100e0600160a060020a0360043516610512565b60408051600160a060020a039092168252519081900360200190f35b34801561010857600080fd5b506100bd600160a060020a036004358116906024351661055e565b34801561012f57600080fd5b506101436004803560248101910135610655565b60408051918252519081900360200190f35b34801561016157600080fd5b506100bd600160a060020a0360043516600160e060020a0319602435166106e3565b34801561018f57600080fd5b506100e0600160a060020a036004351660243561076d565b3480156101b357600080fd5b506101d5600160a060020a0360043516600160e060020a0319602435166107e7565b604080519115158252519081900360200190f35b3480156101f557600080fd5b506101d5600160a060020a0360043516600160e060020a03196024351661089c565b6000600160a060020a0384161561022e5783610230565b335b90503361023c82610512565b600160a060020a03161461029a576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b6102a38361091c565b156102f8576040805160e560020a62461bcd02815260206004820152601960248201527f4d757374206e6f74206265206120455243313635206861736800000000000000604482015290519081900360640190fd5b600160a060020a038216158015906103195750600160a060020a0382163314155b156104a15760405160200180807f4552433832305f4143434550545f4d414749430000000000000000000000000081525060130190506040516020818303038152906040526040518082805190602001908083835b6020831061038d5780518252601f19909201916020918201910161036e565b51815160209384036101000a6000190180199092169116179052604080519290940182900382207f249cb3fa000000000000000000000000000000000000000000000000000000008352600483018a9052600160a060020a0388811660248501529451909650938816945063249cb3fa936044808401945091929091908290030181600087803b15801561042057600080fd5b505af1158015610434573d6000803e3d6000fd5b505050506040513d602081101561044a57600080fd5b5051146104a1576040805160e560020a62461bcd02815260206004820181905260248201527f446f6573206e6f7420696d706c656d656e742074686520696e74657266616365604482015290519081900360640190fd5b600160a060020a03818116600081815260208181526040808320888452909152808220805473ffffffffffffffffffffffffffffffffffffffff19169487169485179055518692917f93baa6efbd2244243bfee6ce4cfdd1d04fc4c0e9a786abd3a41313bd352db15391a450505050565b600160a060020a03808216600090815260016020526040812054909116151561053c575080610559565b50600160a060020a03808216600090815260016020526040902054165b919050565b3361056883610512565b600160a060020a0316146105c6576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b81600160a060020a031681600160a060020a0316146105e557806105e8565b60005b600160a060020a03838116600081815260016020526040808220805473ffffffffffffffffffffffffffffffffffffffff19169585169590951790945592519184169290917f605c2dbf762e5f7d60a546d42e7205dcb1b011ebc62a61736a57c9089d3a43509190a35050565b60008282604051602001808383808284378201915050925050506040516020818303038152906040526040518082805190602001908083835b602083106106ad5780518252601f19909201916020918201910161068e565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902090505b92915050565b6106ed82826107e7565b6106f85760006106fa565b815b600160a060020a03928316600081815260208181526040808320600160e060020a031996909616808452958252808320805473ffffffffffffffffffffffffffffffffffffffff19169590971694909417909555908152600284528181209281529190925220805460ff19166001179055565b60008080600160a060020a038516156107865784610788565b335b91506107938461091c565b156107b85750826107a4828261089c565b6107af5760006107b1565b815b92506107df565b600160a060020a038083166000908152602081815260408083208884529091529020541692505b505092915050565b60008080610815857f01ffc9a70000000000000000000000000000000000000000000000000000000061093e565b9092509050811580610825575080155b1561083357600092506107df565b61084585600160e060020a031961093e565b909250905081158061085657508015155b1561086457600092506107df565b61086e858561093e565b90925090506001821480156108835750806001145b1561089157600192506107df565b506000949350505050565b600160a060020a0382166000908152600260209081526040808320600160e060020a03198516845290915281205460ff1615156108e4576108dd83836107e7565b90506106dd565b50600160a060020a03808316600081815260208181526040808320600160e060020a0319871684529091529020549091161492915050565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff161590565b6040517f01ffc9a7000000000000000000000000000000000000000000000000000000008082526004820183905260009182919060208160088189617530fa9051909690955093505050505600a165627a7a723058204fc4461c9d5a247b0eafe0f9c508057bc0ad72bc24668cb2a35ea65850e10d3100291ba08208208208208208208208208208208208208208208208208208208208208200a00820820820820820820820820820820820820820820820820820820820820820"; - - // send 0.08 ether to deployment account - sendEther(owner, deployAccount, web3.utils.toWei("0.08",'ether')); - // create ERC820 contract - let address = (await web3.eth.sendSignedTransaction(deployTx)).contractAddress; - return address; -}; - -module.exports = { - ERC820Deploy, -}; From e54490a0cd30747ccef7c11aedb49d35dbac48f4 Mon Sep 17 00:00:00 2001 From: Bertrand Masius Date: Fri, 15 Mar 2019 22:55:20 +0100 Subject: [PATCH 12/64] ERC777: implement recent changes of EIP777 (#1159) --- contracts/drafts/ERC777/ERC777Base.sol | 13 ++++-- contracts/drafts/ERC777/ERC777Burnable.sol | 9 +++-- contracts/drafts/ERC777/IERC777.sol | 4 +- contracts/introspection/IERC1820.sol | 2 +- contracts/mocks/ERC777SenderMock.sol | 5 ++- test/drafts/ERC777/ERC777.test.js | 46 ++++++++++++++-------- 6 files changed, 53 insertions(+), 26 deletions(-) diff --git a/contracts/drafts/ERC777/ERC777Base.sol b/contracts/drafts/ERC777/ERC777Base.sol index 889162eb912..e6b1981e520 100644 --- a/contracts/drafts/ERC777/ERC777Base.sol +++ b/contracts/drafts/ERC777/ERC777Base.sol @@ -110,12 +110,14 @@ contract ERC777Base is IERC777, ERC1820Client { /** * @dev Burn the amount of tokens from the address msg.sender * @param amount uint256 amount of tokens to transfer + * @param data bytes extra information provided by the token holder */ - function burn(uint256 amount) external { + function burn(uint256 amount, bytes data) external { _burn( msg.sender, msg.sender, amount, + data, "" ); } @@ -124,11 +126,13 @@ contract ERC777Base is IERC777, ERC1820Client { * @dev Burn the amount of tokens on behalf of the address from * @param from address token holder address. Set to 0x0 to use msg.sender as token holder * @param amount uint256 amount of tokens to transfer + * @param data bytes extra information provided by the token holder * @param operatorData bytes extra information provided by the operator (if any) */ function operatorBurn( address from, uint256 amount, + bytes data, bytes operatorData ) external @@ -138,6 +142,7 @@ contract ERC777Base is IERC777, ERC1820Client { msg.sender, holder, amount, + data, operatorData ); } @@ -234,12 +239,14 @@ contract ERC777Base is IERC777, ERC1820Client { * @param operator address operator requesting the operation * @param from address token holder address * @param amount uint256 amount of tokens to burn + * @param data bytes extra information provided by the token holder * @param operatorData bytes extra information provided by the operator (if any) */ function _burn( address operator, address from, uint256 amount, + bytes data, bytes operatorData ) internal @@ -252,7 +259,7 @@ contract ERC777Base is IERC777, ERC1820Client { from, address(0), amount, - "", + data, operatorData ); @@ -261,7 +268,7 @@ contract ERC777Base is IERC777, ERC1820Client { _balances[from] = _balances[from].sub(amount); require((_balances[from] % _granularity) == 0); - emit Burned(operator, from, amount, operatorData); + emit Burned(operator, from, amount, data, operatorData); } /** diff --git a/contracts/drafts/ERC777/ERC777Burnable.sol b/contracts/drafts/ERC777/ERC777Burnable.sol index 1794e75bb71..04daaf48282 100644 --- a/contracts/drafts/ERC777/ERC777Burnable.sol +++ b/contracts/drafts/ERC777/ERC777Burnable.sol @@ -13,23 +13,26 @@ contract ERC777Burnable is ERC777Base { /** * @dev Burn the amount of tokens from the address msg.sender * @param amount uint256 amount of tokens to transfer + * @param data bytes data provided by the token holder */ - function burn(uint256 amount) external { - _burn(msg.sender, msg.sender, amount, ""); + function burn(uint256 amount, bytes data) external { + _burn(msg.sender, msg.sender, amount, data, ""); } /** * @dev Burn the amount of tokens on behalf of the address from * @param from address token holder address. Set to 0x0 to use msg.sender as token holder * @param amount uint256 amount of tokens to transfer + * @param data bytes data provided by the token holder * @param operatorData bytes extra information provided by the operator (if any) */ function operatorBurn( address from, uint256 amount, + bytes data, bytes operatorData ) external { address holder = from == address(0) ? msg.sender : from; - _burn(msg.sender, holder, amount, operatorData); + _burn(msg.sender, holder, amount, data, operatorData); } } diff --git a/contracts/drafts/ERC777/IERC777.sol b/contracts/drafts/ERC777/IERC777.sol index 868b2f6f456..8168abe8f8b 100644 --- a/contracts/drafts/ERC777/IERC777.sol +++ b/contracts/drafts/ERC777/IERC777.sol @@ -36,11 +36,12 @@ interface IERC777 { bytes operatorData ) external; - function burn(uint256 amount) external; + function burn(uint256 amount, bytes data) external; function operatorBurn( address from, uint256 amount, + bytes data, bytes operatorData ) external; @@ -65,6 +66,7 @@ interface IERC777 { address indexed operator, address indexed from, uint256 amount, + bytes data, bytes operatorData ); diff --git a/contracts/introspection/IERC1820.sol b/contracts/introspection/IERC1820.sol index 18ea4e1c887..76c4ade9743 100644 --- a/contracts/introspection/IERC1820.sol +++ b/contracts/introspection/IERC1820.sol @@ -35,5 +35,5 @@ interface IERC1820 { function implementsERC165Interface( address _contract, bytes4 _interfaceId - ) public view returns (bool); + ) external view returns (bool); } diff --git a/contracts/mocks/ERC777SenderMock.sol b/contracts/mocks/ERC777SenderMock.sol index f2437535efc..4f58f2d6f8e 100644 --- a/contracts/mocks/ERC777SenderMock.sol +++ b/contracts/mocks/ERC777SenderMock.sol @@ -43,9 +43,10 @@ contract ERC777SenderMock is IERC777TokensSender, ERC1820Client { /** * @dev Burn an amount of tokens from this contract * @param amount uint256 amount of tokens to transfer + * @param data bytes extra information provided by the token holder (if any) */ - function burnTokens(uint amount) public { - IERC777(_erc777).burn(amount); + function burnTokens(uint amount, bytes data) public { + IERC777(_erc777).burn(amount, data); } /** diff --git a/test/drafts/ERC777/ERC777.test.js b/test/drafts/ERC777/ERC777.test.js index 6e5eb838132..62f4e60cf8a 100644 --- a/test/drafts/ERC777/ERC777.test.js +++ b/test/drafts/ERC777/ERC777.test.js @@ -564,33 +564,36 @@ contract('ERC777', function ([_, holder, operator, anotherAccount]) { }); describe('burn()',function () { + let userData = "0xdeadbeef"; before('Deploy ERC777', async function () { this.token = await ERC777.new("Test777", "T77", 1, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA, {from: holder}); }); it('Burned event is emitted when burning 0 token', async function () { - const {events} = await this.token.contract.methods.burn("0").send({from: holder}); + const {events} = await this.token.contract.methods.burn("0", userData).send({from: holder}); expectEvent.inEvents(events, 'Burned', { operator: holder, from: holder, amount: "0", + data: userData }); }); it('revert when burning an amount of token from an account with insufficient balance', async function () { let amount = parseInt(INITIAL_SUPPLY, 10) + 100; - await assertRevert(this.token.contract.methods.burn(amount.toString()).send({from: holder})); + await assertRevert(this.token.contract.methods.burn(amount.toString(), userData).send({from: holder})); }); describe('burning an amount of token from an account with sufficient balance', function () { it('Burned event is emitted', async function () { - const {events} = await this.token.contract.methods.burn("100").send({from: holder}); + const {events} = await this.token.contract.methods.burn("100", userData).send({from: holder}); expectEvent.inEvents(events, 'Burned', { operator: holder, from: holder, amount: "100", + data: userData }); }); @@ -614,13 +617,13 @@ contract('ERC777', function ([_, holder, operator, anotherAccount]) { let sender = await ERC777TokensSender.new(true, this.token.address); await this.token.contract.methods.send(sender.address, "100", web3.utils.asciiToHex("")).send({from: holder}); - const {events} = await sender.contract.methods.burnTokens("100").send({from: holder}); + const {events} = await sender.contract.methods.burnTokens("100", userData).send({from: holder}); expectEvent.inEvents(events, 'TokensToSend', { operator: sender.address, from: sender.address, to: ZERO_ADDRESS, amount: "100", - data: "0x00", + data: userData, }); }); @@ -629,14 +632,14 @@ contract('ERC777', function ([_, holder, operator, anotherAccount]) { let sender = await ERC777TokensSender.new(false, this.token.address); await this.token.contract.methods.send(sender.address, "100", web3.utils.asciiToHex("")).send({from: holder}); - const {events} = await sender.contract.methods.burnTokens("100").send({from: holder}); + const {events} = await sender.contract.methods.burnTokens("100", userData).send({from: holder}); expect(events["tokensToSend"]).to.not.exist; }); }); it('revert when sending an amount which is not a multiple of granularity', async function () { let tempToken = await ERC777.new("Test777", "T77", 10, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA, {from: holder}); - await assertRevert(tempToken.contract.methods.burn("15").send({from: holder})); + await assertRevert(tempToken.contract.methods.burn("15", userData).send({from: holder})); }); }); }); @@ -695,7 +698,8 @@ contract('ERC777', function ([_, holder, operator, anotherAccount]) { it('revert when msg.sender is not an operator', async function () { let tempToken = await ERC777.new("Test777", "T77", 1, [operator], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA, {from: holder}); let opData = "0xbabecafe"; - await assertRevert(tempToken.contract.methods.operatorBurn(holder, "100", opData).send({from: anotherAccount})); + let userData = "0xdeadbeef"; + await assertRevert(tempToken.contract.methods.operatorBurn(holder, "100", userData, opData).send({from: anotherAccount})); }); for (let test in operatorTests) { @@ -708,12 +712,14 @@ contract('ERC777', function ([_, holder, operator, anotherAccount]) { it('Burned event is emitted when burning 0 token', async function () { let opData = "0xbabecafe"; + let userData = "0xdeadbeef"; - const {events} = await this.token.contract.methods.operatorBurn(holder, "0", opData).send({from: operator}); + const {events} = await this.token.contract.methods.operatorBurn(holder, "0", userData, opData).send({from: operator}); expectEvent.inEvents(events, 'Burned', { operator: operator, from: holder, amount: "0", + data: userData, operatorData: opData, }); }); @@ -721,18 +727,21 @@ contract('ERC777', function ([_, holder, operator, anotherAccount]) { it('revert when burning an amount of token from an account with insufficient balance', async function () { let amount = parseInt(INITIAL_SUPPLY, 10) + 100; let opData = "0xbabecafe"; - await assertRevert(this.token.contract.methods.operatorBurn(holder, amount.toString(), opData).send({from: operator})); + let userData = "0xdeadbeef"; + await assertRevert(this.token.contract.methods.operatorBurn(holder, amount.toString(), userData, opData).send({from: operator})); }); describe('burning an amount of token from an account with sufficient balance', function () { it('Burned event is emitted', async function () { let opData = "0xbabecafe"; + let userData = "0xdeadbeef"; - const {events} = await this.token.contract.methods.operatorBurn(holder, "100", opData).send({from: operator}); + const {events} = await this.token.contract.methods.operatorBurn(holder, "100", userData, opData).send({from: operator}); expectEvent.inEvents(events, 'Burned', { operator: operator, from: holder, amount: "100", + data: userData, operatorData: opData, }); }); @@ -753,19 +762,22 @@ contract('ERC777', function ([_, holder, operator, anotherAccount]) { it('revert when burning an amount which is not a multiple of granularity', async function () { let opData = "0xbabecafe"; + let userData = "0xdeadbeef"; let tempToken = await ERC777.new("Test777", "T77", 10, [operator], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA, {from: holder}); - await assertRevert(tempToken.contract.methods.operatorBurn(holder, "15", opData).send({from: operator})); + await assertRevert(tempToken.contract.methods.operatorBurn(holder, "15", userData, opData).send({from: operator})); }); it('operator is the holder when from is address(0)', async function () { let opData = "0xbabecafe"; + let userData = "0xdeadbeef"; await this.token.contract.methods.send(operator, "100", web3.utils.asciiToHex("")).send({from: holder}); - const {events} = await this.token.contract.methods.operatorBurn(ZERO_ADDRESS, "100", opData).send({from: operator}); + const {events} = await this.token.contract.methods.operatorBurn(ZERO_ADDRESS, "100", userData, opData).send({from: operator}); expectEvent.inEvents(events, 'Burned', { operator: operator, from: operator, amount: "100", + data: userData, operatorData: opData, }); }); @@ -774,29 +786,31 @@ contract('ERC777', function ([_, holder, operator, anotherAccount]) { it('tokensToSend() hook is called when declared', async function () { let opData = "0xbabecafe"; + let userData = "0xdeadbeef"; // deploy sender contract, declare operator and give tokens await operatorTests[test].deploy_sender.call(this, holder, operator, true); - await this.token.contract.methods.operatorBurn(this.sender.address, "100", opData).send({from: operator}); + await this.token.contract.methods.operatorBurn(this.sender.address, "100", userData, opData).send({from: operator}); let events = await this.sender.getPastEvents("TokensToSend"); events.length.should.be.not.equal(0); let event = events[0].returnValues; event.operator.should.be.equal(operator); event.from.should.be.equal(this.sender.address); event.amount.toString().should.be.equal("100"); - expect(event.data).to.not.exist; + event.data.should.be.equal(userData); event.operatorData.should.be.equal(opData); }); it('tokensToSend() hook is not called when not declared', async function () { let opData = "0xbabecafe"; + let userData = "0xdeadbeef"; // deploy sender contract, declare operator and give tokens await operatorTests[test].deploy_sender.call(this, holder, operator, false); - await this.token.contract.methods.operatorBurn(this.sender.address, "100", opData).send({from: operator}); + await this.token.contract.methods.operatorBurn(this.sender.address, "100", userData, opData).send({from: operator}); let events = await this.sender.getPastEvents("TokensToSend"); expect(events["tokensToSend"]).to.not.exist; }); From 5695639cdc7d76213ae17488103a6e369f708b3e Mon Sep 17 00:00:00 2001 From: Bertrand Masius Date: Sun, 17 Mar 2019 12:19:18 +0100 Subject: [PATCH 13/64] ERC777 Fix formatting (#1159) --- contracts/drafts/ERC777/ERC777Base.sol | 25 +- contracts/drafts/ERC777/ERC777Burnable.sol | 16 +- contracts/introspection/ERC1820Client.sol | 18 +- contracts/mocks/ERC777ReceiverMock.sol | 88 +-- contracts/mocks/ERC777SenderMock.sol | 134 ++-- test/drafts/ERC777/ERC777.test.js | 808 +++++++++++++-------- test/helpers/expectEvent.js | 11 +- test/introspection/ERC1820Deploy.js | 10 +- 8 files changed, 666 insertions(+), 444 deletions(-) diff --git a/contracts/drafts/ERC777/ERC777Base.sol b/contracts/drafts/ERC777/ERC777Base.sol index e6b1981e520..dc2846e28c1 100644 --- a/contracts/drafts/ERC777/ERC777Base.sol +++ b/contracts/drafts/ERC777/ERC777Base.sol @@ -268,7 +268,13 @@ contract ERC777Base is IERC777, ERC1820Client { _balances[from] = _balances[from].sub(amount); require((_balances[from] % _granularity) == 0); - emit Burned(operator, from, amount, data, operatorData); + emit Burned( + operator, + from, + amount, + data, + operatorData + ); } /** @@ -308,7 +314,13 @@ contract ERC777Base is IERC777, ERC1820Client { _balances[to] = _balances[to].add(amount); require((_balances[to] % _granularity) == 0); - emit Minted(operator, to, amount, userData, operatorData); + emit Minted( + operator, + to, + amount, + userData, + operatorData + ); } /** @@ -394,7 +406,14 @@ contract ERC777Base is IERC777, ERC1820Client { operatorData ); - emit Sent(msg.sender, from, to, amount, userData, operatorData); + emit Sent( + msg.sender, + from, + to, + amount, + userData, + operatorData + ); } /** diff --git a/contracts/drafts/ERC777/ERC777Burnable.sol b/contracts/drafts/ERC777/ERC777Burnable.sol index 04daaf48282..8993e842cd5 100644 --- a/contracts/drafts/ERC777/ERC777Burnable.sol +++ b/contracts/drafts/ERC777/ERC777Burnable.sol @@ -16,7 +16,13 @@ contract ERC777Burnable is ERC777Base { * @param data bytes data provided by the token holder */ function burn(uint256 amount, bytes data) external { - _burn(msg.sender, msg.sender, amount, data, ""); + _burn( + msg.sender, + msg.sender, + amount, + data, + "" + ); } /** @@ -33,6 +39,12 @@ contract ERC777Burnable is ERC777Base { bytes operatorData ) external { address holder = from == address(0) ? msg.sender : from; - _burn(msg.sender, holder, amount, data, operatorData); + _burn( + msg.sender, + holder, + amount, + data, + operatorData + ); } } diff --git a/contracts/introspection/ERC1820Client.sol b/contracts/introspection/ERC1820Client.sol index 1e5ab73b93d..efe1e7811c3 100644 --- a/contracts/introspection/ERC1820Client.sol +++ b/contracts/introspection/ERC1820Client.sol @@ -9,8 +9,13 @@ import "./IERC1820.sol"; */ contract ERC1820Client { - IERC1820 private _erc1820 = - IERC1820(0x1820b744B33945482C17Dc37218C01D858EBc714); + IERC1820 private _erc1820 = IERC1820( + 0x1820b744B33945482C17Dc37218C01D858EBc714 + ); + + function getERC1820Registry() external view returns(address) { + return address(_erc1820); + } function getInterfaceImplementer( address addr, @@ -27,7 +32,10 @@ contract ERC1820Client { _erc1820.setInterfaceImplementer(addr, hash, implementer); } - function updateERC165Cache(address _contract, bytes4 _interfaceId) internal { + function updateERC165Cache( + address _contract, + bytes4 _interfaceId + ) internal { _erc1820.updateERC165Cache(_contract, _interfaceId); } @@ -37,8 +45,4 @@ contract ERC1820Client { ) internal view returns (bool) { return _erc1820.implementsERC165Interface(_contract, _interfaceId); } - - function getERC1820Registry() public view returns(address) { - return address(_erc1820); - } } diff --git a/contracts/mocks/ERC777ReceiverMock.sol b/contracts/mocks/ERC777ReceiverMock.sol index d733045bfd1..3c4b744db0b 100644 --- a/contracts/mocks/ERC777ReceiverMock.sol +++ b/contracts/mocks/ERC777ReceiverMock.sol @@ -10,52 +10,52 @@ import "../introspection/ERC1820Client.sol"; */ contract ERC777ReceiverMock is IERC777TokensRecipient, ERC1820Client { - event TokensReceived( - address indexed operator, - address indexed from, - address indexed to, - uint256 amount, - bytes data, - bytes operatorData - ); + event TokensReceived( + address indexed operator, + address indexed from, + address indexed to, + uint256 amount, + bytes data, + bytes operatorData + ); - constructor(bool setInterface) public { - // register interface - if (setInterface) { - setInterfaceImplementer( - address(this), - keccak256("ERC777TokensRecipient"), - address(this) - ); + constructor(bool setInterface) public { + // register interface + if (setInterface) { + setInterfaceImplementer( + address(this), + keccak256("ERC777TokensRecipient"), + address(this) + ); + } } - } - /** - * @dev tokensReceived() hook - * @param operator address operator requesting the transfer - * @param from address token holder address - * @param to address recipient address - * @param amount uint256 amount of tokens to transfer - * @param userData bytes extra information provided by the token holder (if any) - * @param operatorData bytes extra information provided by the operator (if any) - */ - function tokensReceived( - address operator, - address from, - address to, - uint256 amount, - bytes userData, - bytes operatorData - ) + /** + * @dev tokensReceived() hook + * @param operator address operator requesting the transfer + * @param from address token holder address + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param userData bytes extra information provided by the token holder (if any) + * @param operatorData bytes extra information provided by the operator (if any) + */ + function tokensReceived( + address operator, + address from, + address to, + uint256 amount, + bytes userData, + bytes operatorData + ) external - { - emit TokensReceived( - operator, - from, - to, - amount, - userData, - operatorData - ); - } + { + emit TokensReceived( + operator, + from, + to, + amount, + userData, + operatorData + ); + } } diff --git a/contracts/mocks/ERC777SenderMock.sol b/contracts/mocks/ERC777SenderMock.sol index 4f58f2d6f8e..481f0ffe778 100644 --- a/contracts/mocks/ERC777SenderMock.sol +++ b/contracts/mocks/ERC777SenderMock.sol @@ -10,79 +10,79 @@ import "../introspection/ERC1820Client.sol"; * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-777.md */ contract ERC777SenderMock is IERC777TokensSender, ERC1820Client { - - address private _erc777; - event TokensToSend( - address indexed operator, - address indexed from, - address indexed to, - uint256 amount, - bytes data, - bytes operatorData - ); + address private _erc777; - constructor(bool setInterface, address erc777) public { - _erc777 = erc777; - // register interface - if (setInterface) { - setInterfaceImplementer(address(this), keccak256("ERC777TokensSender"), address(this)); + event TokensToSend( + address indexed operator, + address indexed from, + address indexed to, + uint256 amount, + bytes data, + bytes operatorData + ); + + constructor(bool setInterface, address erc777) public { + _erc777 = erc777; + // register interface + if (setInterface) { + setInterfaceImplementer(address(this), keccak256("ERC777TokensSender"), address(this)); + } } - } - /** - * @dev Send an amount of tokens from this contract to recipient - * @param to address recipient address - * @param amount uint256 amount of tokens to transfer - * @param data bytes extra information provided by the token holder (if any) - */ - function sendTokens(address to, uint amount, bytes data) public { - IERC777(_erc777).send(to, amount, data); - } + /** + * @dev Send an amount of tokens from this contract to recipient + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param data bytes extra information provided by the token holder (if any) + */ + function sendTokens(address to, uint amount, bytes data) external { + IERC777(_erc777).send(to, amount, data); + } - /** - * @dev Burn an amount of tokens from this contract - * @param amount uint256 amount of tokens to transfer - * @param data bytes extra information provided by the token holder (if any) - */ - function burnTokens(uint amount, bytes data) public { - IERC777(_erc777).burn(amount, data); - } + /** + * @dev Burn an amount of tokens from this contract + * @param amount uint256 amount of tokens to transfer + * @param data bytes extra information provided by the token holder (if any) + */ + function burnTokens(uint amount, bytes data) external { + IERC777(_erc777).burn(amount, data); + } - /** - * @dev Authorize an operator - * @param operator address of operator - */ - function authorizeOperator(address operator) public { - IERC777(_erc777).authorizeOperator(operator); - } + /** + * @dev Authorize an operator + * @param operator address of operator + */ + function authorizeOperator(address operator) external { + IERC777(_erc777).authorizeOperator(operator); + } - /** - * @dev tokensSender() hook - * @param operator address operator requesting the transfer - * @param from address token holder address - * @param to address recipient address - * @param amount uint256 amount of tokens to transfer - * @param userData bytes extra information provided by the token holder (if any) - * @param operatorData bytes extra information provided by the operator (if any) - */ - function tokensToSend( - address operator, - address from, - address to, - uint256 amount, - bytes userData, - bytes operatorData - ) + /** + * @dev tokensSender() hook + * @param operator address operator requesting the transfer + * @param from address token holder address + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param userData bytes extra information provided by the token holder (if any) + * @param operatorData bytes extra information provided by the operator (if any) + */ + function tokensToSend( + address operator, + address from, + address to, + uint256 amount, + bytes userData, + bytes operatorData + ) external - { - emit TokensToSend( - operator, - from, - to, - amount, - userData, - operatorData - ); - } + { + emit TokensToSend( + operator, + from, + to, + amount, + userData, + operatorData + ); + } } diff --git a/test/drafts/ERC777/ERC777.test.js b/test/drafts/ERC777/ERC777.test.js index 62f4e60cf8a..334129b07ef 100644 --- a/test/drafts/ERC777/ERC777.test.js +++ b/test/drafts/ERC777/ERC777.test.js @@ -1,6 +1,6 @@ -const {assertRevert} = require('../../helpers/assertRevert'); +const { assertRevert } = require('../../helpers/assertRevert'); const expectEvent = require('../../helpers/expectEvent'); -const {ERC1820Deploy} = require('../../introspection/ERC1820Deploy'); +const { ERC1820Deploy } = require('../../introspection/ERC1820Deploy'); const ERC777 = artifacts.require('ERC777'); const ERC1820 = artifacts.require('IERC1820'); @@ -15,44 +15,46 @@ require('chai') contract('ERC777', function ([_, holder, operator, anotherAccount]) { const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; - const ERC1820_ADDRESS = "0x1820b744B33945482C17Dc37218C01D858EBc714"; - const INITIAL_SUPPLY = "10000"; - const USER_DATA = "0xabcd"; - const OPERATOR_DATA = "0x0a0b0c0d"; - const GRANULARITY = "1"; + const ERC1820_ADDRESS = '0x1820b744B33945482C17Dc37218C01D858EBc714'; + const INITIAL_SUPPLY = '10000'; + const USER_DATA = '0xabcd'; + const OPERATOR_DATA = '0x0a0b0c0d'; + const GRANULARITY = '1'; before('Deploy ERC1820', async function () { try { this.ERC1820Registry = await ERC1820.at(ERC1820_ADDRESS); - } catch(error) { - let address = await ERC1820Deploy(holder); + } catch (error) { + const address = await ERC1820Deploy(holder); this.ERC1820Registry = await ERC1820.at(address); } }); it('Minted event is emitted', async function () { // use web3 deployment to get the receipt - let web3Contract = new web3.eth.Contract(ERC777.abi); + const web3Contract = new web3.eth.Contract(ERC777.abi); web3Contract.options.data = ERC777.binary; - let tx = web3Contract.deploy({arguments: ["Test777", "T77", GRANULARITY, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA]}); + const tx = web3Contract.deploy({ + arguments: ['Test777', 'T77', GRANULARITY, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA], + }); - let instance = await tx - .send({from: holder, gas: '6000000', data: tx}) - .on('receipt', receipt => { - expectEvent.inEvents(receipt.events, 'Minted',{ - operator: holder, - to: holder, - amount: INITIAL_SUPPLY, - data: USER_DATA, - operatorData: OPERATOR_DATA + const instance = await tx + .send({ from: holder, gas: '6000000', data: tx }) + .on('receipt', receipt => { + expectEvent.inEvents(receipt.events, 'Minted', { + operator: holder, + to: holder, + amount: INITIAL_SUPPLY, + data: USER_DATA, + operatorData: OPERATOR_DATA, + }); }); - }); this.token = await ERC777.at(instance.options.address); }); describe('ERC1820 Registry', function () { it('hardcoded address in ERC777 contract is correct', async function () { - let erc1820 = await this.token.getERC1820Registry(); + const erc1820 = await this.token.getERC1820Registry(); erc1820.should.be.equal(this.ERC1820Registry.address); }); }); @@ -66,7 +68,7 @@ contract('ERC777', function ([_, holder, operator, anotherAccount]) { describe('balanceOf', function () { describe('when the requested account has no tokens', function () { it('returns zero', async function () { - (await this.token.balanceOf(anotherAccount)).toString().should.be.equal("0"); + (await this.token.balanceOf(anotherAccount)).toString().should.be.equal('0'); }); }); @@ -83,24 +85,23 @@ contract('ERC777', function ([_, holder, operator, anotherAccount]) { }); it('value is set at creation time', async function () { - let tempToken = await ERC777.new("Test777", "T77", 10, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA); - let granularity = await tempToken.granularity(); - granularity.toString().should.be.equal("10"); + const tempToken = await ERC777.new('Test777', 'T77', 10, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA); + const granularity = await tempToken.granularity(); + granularity.toString().should.be.equal('10'); }); it('value is checked to be greater or equal to 1', async function () { - await assertRevert(ERC777.new("Test777", "T77", 0, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA)); + await assertRevert(ERC777.new('Test777', 'T77', 0, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA)); }); it('initialSupply is a multiple of granularity', async function () { - await assertRevert(ERC777.new("Test777", "T77", "7", [], "11", USER_DATA, OPERATOR_DATA)); + await assertRevert(ERC777.new('Test777', 'T77', '7', [], '11', USER_DATA, OPERATOR_DATA)); }); }); describe('non-default operator', async function () { - before('Deploy ERC777 with no default operator', async function () { - this.token = await ERC777.new("Test777", "T77", 1, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA); + this.token = await ERC777.new('Test777', 'T77', 1, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA); }); it('holder is an operator for itself', function () { @@ -108,12 +109,11 @@ contract('ERC777', function ([_, holder, operator, anotherAccount]) { }); describe('authorize operator', function () { - it('AuthorizedOperator event is emitted', async function () { - const {logs} = await this.token.authorizeOperator(anotherAccount, {from: holder}); + const { logs } = await this.token.authorizeOperator(anotherAccount, { from: holder }); expectEvent.inLogs(logs, 'AuthorizedOperator', { operator: anotherAccount, - tokenHolder: holder + tokenHolder: holder, }); }); @@ -122,63 +122,62 @@ contract('ERC777', function ([_, holder, operator, anotherAccount]) { }); it('AuthorizedOperator event is emitted even if operator is already authorized', async function () { - const {logs} = await this.token.authorizeOperator(anotherAccount, {from: holder}); + const { logs } = await this.token.authorizeOperator(anotherAccount, { from: holder }); expectEvent.inLogs(logs, 'AuthorizedOperator', { operator: anotherAccount, - tokenHolder: holder + tokenHolder: holder, }); }); it('revert when token holder authorizes itself as operator', async function () { - await assertRevert(this.token.authorizeOperator(holder, {from: holder})); + await assertRevert(this.token.authorizeOperator(holder, { from: holder })); }); - }); describe('revoke operator', function () { - it('RevokedOperator event is emitted', async function () { - const {logs} = await this.token.revokeOperator(anotherAccount, {from: holder}); + const { logs } = await this.token.revokeOperator(anotherAccount, { from: holder }); expectEvent.inLogs(logs, 'RevokedOperator', { operator: anotherAccount, - tokenHolder: holder + tokenHolder: holder, }); }); it('operator is revoked', async function () { - let iopf = await this.token.contract.methods.isOperatorFor(anotherAccount, holder).call(); - assert(! iopf); + const iopf = await this.token.contract.methods.isOperatorFor(anotherAccount, holder).call(); + assert(!iopf); }); it('RevokedOperator event is emitted even if operator is already revoked', async function () { - const {logs} = await this.token.revokeOperator(anotherAccount, {from: holder}); + const { logs } = await this.token.revokeOperator(anotherAccount, { from: holder }); expectEvent.inLogs(logs, 'RevokedOperator', { operator: anotherAccount, - tokenHolder: holder + tokenHolder: holder, }); }); it('revert when token holder revoke itself as operator', async function () { - await assertRevert(this.token.revokeOperator(holder, {from: holder})); + await assertRevert(this.token.revokeOperator(holder, { from: holder })); }); - }); }); describe('default operator', async function () { - before('Deploy ERC777 with one default operator', async function () { - this.token = await ERC777.new("Test777", "T77", 1, [operator], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA); + this.token = await ERC777.new('Test777', 'T77', 1, [operator], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA); }); it('returns empty array when no default operator has been declared', async function () { - let tempToken = await ERC777.new("Test777", "T77", 1, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA); + const tempToken = await ERC777.new('Test777', 'T77', 1, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA); + // eslint-disable-next-line no-unused-expressions (await tempToken.defaultOperators()).should.be.an('array').that.is.empty; }); it('array of operators is set at creation time', async function () { - let tempToken = await ERC777.new("Test777", "T77", 1, [operator, anotherAccount], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA); - let defaultOps = await tempToken.defaultOperators(); + const tempToken = await ERC777.new( + 'Test777', 'T77', 1, [operator, anotherAccount], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA + ); + const defaultOps = await tempToken.defaultOperators(); defaultOps.should.be.an('array').that.has.all.members([operator, anotherAccount]); }); @@ -187,637 +186,826 @@ contract('ERC777', function ([_, holder, operator, anotherAccount]) { }); describe('revoke operator', function () { - it('RevokedOperator event is emitted', async function () { - const {logs} = await this.token.revokeOperator(operator, {from: holder}); + const { logs } = await this.token.revokeOperator(operator, { from: holder }); expectEvent.inLogs(logs, 'RevokedOperator', { operator: operator, - tokenHolder: holder + tokenHolder: holder, }); }); it('operator is revoked', async function () { - let iopf = await this.token.contract.methods.isOperatorFor(operator, holder).call(); - assert(! iopf); + const iopf = await this.token.contract.methods.isOperatorFor(operator, holder).call(); + assert(!iopf); }); it('RevokedOperator event is emitted even if operator is already revoked', async function () { - const {logs} = await this.token.revokeOperator(operator, {from: holder}); + const { logs } = await this.token.revokeOperator(operator, { from: holder }); expectEvent.inLogs(logs, 'RevokedOperator', { operator: operator, - tokenHolder: holder + tokenHolder: holder, }); }); - }); describe('re-authorize operator', function () { - it('AuthorizedOperator event is emitted', async function () { - const {logs} = await this.token.authorizeOperator(operator, {from: holder}); + const { logs } = await this.token.authorizeOperator(operator, { from: holder }); expectEvent.inLogs(logs, 'AuthorizedOperator', { operator: operator, - tokenHolder: holder + tokenHolder: holder, }); }); it('operator is authorized', async function () { - let iopf = await this.token.contract.methods.isOperatorFor(operator, holder).call(); + const iopf = await this.token.contract.methods.isOperatorFor(operator, holder).call(); assert(iopf); }); it('AuthorizedOperator is emitted even if operator is already authorized', async function () { - const {logs} = await this.token.authorizeOperator(operator, {from: holder}); + const { logs } = await this.token.authorizeOperator(operator, { from: holder }); expectEvent.inLogs(logs, 'AuthorizedOperator', { operator: operator, - tokenHolder: holder + tokenHolder: holder, }); }); - }); }); - describe('send()',function () { - + describe('send()', function () { before('Deploy ERC777', async function () { - this.token = await ERC777.new("Test777", "T77", 1, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA, {from: holder}); + this.token = await ERC777.new( + 'Test777', 'T77', 1, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA, { from: holder } + ); }); it('Sent event is emitted when sending 0 token', async function () { - let userData = "0xdeadbeef"; + const userData = '0xdeadbeef'; - const {events} = await this.token.contract.methods.send(operator, "0", userData).send({from: holder}); + const { events } = await this.token.contract.methods.send(operator, '0', userData).send({ from: holder }); expectEvent.inEvents(events, 'Sent', { operator: holder, from: holder, to: operator, - amount: "0", + amount: '0', data: userData, }); }); it('revert when sending an amount of token from an account with insufficient balance', async function () { - let amount = parseInt(INITIAL_SUPPLY, 10) + 100; - let userData = "0xdeadbeef"; - await assertRevert(this.token.contract.methods.send(operator, amount.toString(), userData).send({from: holder})); + const amount = parseInt(INITIAL_SUPPLY, 10) + 100; + const userData = '0xdeadbeef'; + await assertRevert( + this.token.contract.methods.send(operator, amount.toString(), userData).send({ from: holder }) + ); }); describe('sending an amount of token from an account with sufficient balance', function () { it('Sent event is emitted', async function () { - let userData = "0xdeadbeef"; + const userData = '0xdeadbeef'; - const {events} = await this.token.contract.methods.send(operator, "100", userData).send({from: holder}); + const { events } = await this.token.contract.methods.send(operator, '100', userData).send({ from: holder }); expectEvent.inEvents(events, 'Sent', { operator: holder, from: holder, to: operator, - amount: "100", + amount: '100', data: userData, }); }); it('sender balance is decreased', async function () { - let balance = parseInt(INITIAL_SUPPLY, 10) - 100; + const balance = parseInt(INITIAL_SUPPLY, 10) - 100; (await this.token.balanceOf(holder)).toString().should.be.equal(balance.toString()); }); it('recipient balance is increased', async function () { - (await this.token.balanceOf(operator)).toString().should.be.equal("100"); + (await this.token.balanceOf(operator)).toString().should.be.equal('100'); }); describe('hooks', function () { it('tokensToSend() hook is called when declared', async function () { - let userData = "0xdeadbeef"; + const userData = '0xdeadbeef'; // deploy sender contract and give tokens - let sender = await ERC777TokensSender.new(true, this.token.address); - await this.token.contract.methods.send(sender.address, "100", userData).send({from: holder}); + const sender = await ERC777TokensSender.new(true, this.token.address); + await this.token.contract.methods.send(sender.address, '100', userData).send({ from: holder }); - const {events} = await sender.contract.methods.sendTokens(operator, "100", userData).send({from: holder}); + const { events } = await sender.contract.methods.sendTokens(operator, '100', userData).send({ from: holder }); expectEvent.inEvents(events, 'TokensToSend', { operator: sender.address, from: sender.address, to: operator, - amount: "100", + amount: '100', data: userData, }); }); it('tokensToSend() hook is not called when not declared', async function () { - let userData = "0xdeadbeef"; + const userData = '0xdeadbeef'; // deploy sender contract and give tokens - let sender = await ERC777TokensSender.new(false, this.token.address); - await this.token.contract.methods.send(sender.address, "100", userData).send({from: holder}); + const sender = await ERC777TokensSender.new(false, this.token.address); + await this.token.contract.methods.send(sender.address, '100', userData).send({ from: holder }); - const {events} = await sender.contract.methods.sendTokens(operator, "100", userData).send({from: holder}); - expect(events["tokensToSend"]).to.not.exist; + const { events } = await sender.contract.methods.sendTokens(operator, '100', userData).send({ from: holder }); + // eslint-disable-next-line no-unused-expressions + expect(events.tokensToSend).to.not.exist; }); it('tokensReceived() hook is called when declared', async function () { - let userData = "0xdeadbeef"; + const userData = '0xdeadbeef'; - let receiver = await ERC777TokensRecipient.new(true); - await this.token.contract.methods.send(receiver.address, "100", userData).send({from: holder}); - let events = await receiver.getPastEvents("TokensReceived"); + const receiver = await ERC777TokensRecipient.new(true); + await this.token.contract.methods.send(receiver.address, '100', userData).send({ from: holder }); + const events = await receiver.getPastEvents('TokensReceived'); events.length.should.be.not.equal(0); - let event = events[0].returnValues; + const event = events[0].returnValues; event.operator.should.be.equal(holder); event.from.should.be.equal(holder); event.to.should.be.equal(receiver.address); - event.amount.toString().should.be.equal("100"); + event.amount.toString().should.be.equal('100'); event.data.should.be.equal(userData); }); it('tokensReceived() hook is not called when not declared', async function () { - let userData = "0xdeadbeef"; + const userData = '0xdeadbeef'; - let receiver = await ERC777TokensRecipient.new(false); - await this.token.contract.methods.send(receiver.address, "100", userData).send({from: holder}); - let events = await receiver.getPastEvents("TokensReceived"); + const receiver = await ERC777TokensRecipient.new(false); + await this.token.contract.methods.send(receiver.address, '100', userData).send({ from: holder }); + const events = await receiver.getPastEvents('TokensReceived'); events.length.should.be.equal(0); }); }); it('revert when sending an amount of token to address(0)', async function () { - let userData = "0xdeadbeef"; - await assertRevert(this.token.contract.methods.send(ZERO_ADDRESS, "100", userData).send({from: holder})); + const userData = '0xdeadbeef'; + await assertRevert(this.token.contract.methods.send(ZERO_ADDRESS, '100', userData).send({ from: holder })); }); it('revert when sending an amount which is not a multiple of granularity', async function () { - let userData = "0xdeadbeef"; - let tempToken = await ERC777.new("Test777", "T77", 10, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA, {from: holder}); - await assertRevert(tempToken.contract.methods.send(anotherAccount, "15", userData).send({from: holder})); + const userData = '0xdeadbeef'; + const tempToken = await ERC777.new( + 'Test777', 'T77', 10, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA, { from: holder } + ); + await assertRevert(tempToken.contract.methods.send(anotherAccount, '15', userData).send({ from: holder })); }); }); - }); - describe('operatorSend()',function () { - let operatorTests = { + describe('operatorSend()', function () { + const operatorTests = { defaultOperatorTest: { - name: "default operator", - deploy_fn: async function (holder, operator) { + name: 'default operator', + deployFn: async function (holder, operator) { this.token = await ERC777.new( - "Test777", - "T77", + 'Test777', + 'T77', 1, [operator], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA, - {from: holder} - ); + { from: holder } + ); + }, + deploySender: async function (holder, operator, declareInterface) { + // deploy sender contract and give tokens + this.sender = await ERC777TokensSender.new(declareInterface, this.token.address); + await this.token.contract.methods.send( + this.sender.address, + '100', + web3.utils.asciiToHex('') + ).send({ from: holder }); }, - deploy_sender: async function (holder, operator, declareInterface) { - // deploy sender contract and give tokens - this.sender = await ERC777TokensSender.new(declareInterface, this.token.address); - await this.token.contract.methods.send(this.sender.address, "100", web3.utils.asciiToHex("")).send({from: holder}); - } }, nonDefaultOperatorTest: { - name: "non-default operator", - deploy_fn: async function (holder, operator) { + name: 'non-default operator', + deployFn: async function (holder, operator) { this.token = await ERC777.new( - "Test777", - "T77", + 'Test777', + 'T77', 1, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA, - {from: holder} - ); - await this.token.authorizeOperator(operator, {from: holder}); + { from: holder } + ); + await this.token.authorizeOperator(operator, { from: holder }); + }, + deploySender: async function (holder, operator, declareInterface) { + // deploy sender contract and give tokens + this.sender = await ERC777TokensSender.new(declareInterface, this.token.address); + await this.token.contract.methods.send( + this.sender.address, + '100', + web3.utils.asciiToHex('') + ).send({ from: holder }); + // declare operator + await this.sender.contract.methods.authorizeOperator(operator).send({ from: holder }); }, - deploy_sender: async function (holder, operator, declareInterface) { - // deploy sender contract and give tokens - this.sender = await ERC777TokensSender.new(declareInterface, this.token.address); - await this.token.contract.methods.send(this.sender.address, "100", web3.utils.asciiToHex("")).send({from: holder}); - // declare operator - await this.sender.contract.methods.authorizeOperator(operator).send({from: holder}); - } - } + }, }; - + it('revert when msg.sender is not an operator', async function () { - let tempToken = await ERC777.new("Test777", "T77", 1, [operator], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA, {from: holder}); - let userData = "0xdeadbeef"; - let opData = "0xbabecafe"; - await assertRevert(tempToken.contract.methods.operatorSend(holder, anotherAccount, "100", userData, opData).send({from: anotherAccount})); + const tempToken = await ERC777.new( + 'Test777', 'T77', 1, [operator], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA, { from: holder } + ); + const userData = '0xdeadbeef'; + const opData = '0xbabecafe'; + await assertRevert( + tempToken.contract.methods.operatorSend( + holder, + anotherAccount, + '100', + userData, + opData + ).send({ from: anotherAccount }) + ); }); - for (let test in operatorTests) { - + for (const test in operatorTests) { describe('when operator is a ' + operatorTests[test].name, function () { - - before('Deploy ERC777', async function() { - await operatorTests[test].deploy_fn.call(this, holder, operator); + before('Deploy ERC777', async function () { + await operatorTests[test].deployFn.call(this, holder, operator); }); it('Sent event is emitted when sending 0 token', async function () { - let userData = "0xdeadbeef"; - let opData = "0xbabecafe"; + const userData = '0xdeadbeef'; + const opData = '0xbabecafe'; + + const { events } = await this.token.contract.methods.operatorSend( + holder, + anotherAccount, + '0', + userData, + opData + ).send({ from: operator }); - const {events} = await this.token.contract.methods.operatorSend(holder, anotherAccount, "0", userData, opData).send({from: operator}); expectEvent.inEvents(events, 'Sent', { operator: operator, from: holder, to: anotherAccount, - amount: "0", + amount: '0', data: userData, operatorData: opData, }); }); it('revert when sending an amount of token from an account with insufficient balance', async function () { - let amount = parseInt(INITIAL_SUPPLY, 10) + 100; - let userData = "0xdeadbeef"; - let opData = "0xbabecafe"; - await assertRevert(this.token.contract.methods.operatorSend(holder, anotherAccount, amount.toString(), userData, opData).send({from: operator})); + const amount = parseInt(INITIAL_SUPPLY, 10) + 100; + const userData = '0xdeadbeef'; + const opData = '0xbabecafe'; + + await assertRevert( + this.token.contract.methods.operatorSend( + holder, + anotherAccount, + amount.toString(), + userData, + opData + ).send({ from: operator }) + ); }); describe('sending an amount of token from an account with sufficient balance', function () { it('Sent event is emitted', async function () { - let userData = "0xdeadbeef"; - let opData = "0xbabecafe"; + const userData = '0xdeadbeef'; + const opData = '0xbabecafe'; + + const { events } = await this.token.contract.methods.operatorSend( + holder, + anotherAccount, + '100', + userData, + opData + ).send({ from: operator }); - const {events} = await this.token.contract.methods.operatorSend(holder, anotherAccount, "100", userData, opData).send({from: operator}); expectEvent.inEvents(events, 'Sent', { operator: operator, from: holder, to: anotherAccount, - amount: "100", + amount: '100', data: userData, operatorData: opData, }); }); it('sender balance is decreased', async function () { - let balance = parseInt(INITIAL_SUPPLY, 10) - 100; + const balance = parseInt(INITIAL_SUPPLY, 10) - 100; (await this.token.balanceOf(holder)).toString().should.be.equal(balance.toString()); }); it('recipient balance is increased', async function () { - (await this.token.balanceOf(anotherAccount)).toString().should.be.equal("100"); + (await this.token.balanceOf(anotherAccount)).toString().should.be.equal('100'); }); it('revert when recipient is address(0)', async function () { - let userData = "0xdeadbeef"; - let opData = "0xbabecafe"; - await assertRevert(this.token.contract.methods.operatorSend(holder, ZERO_ADDRESS, "100", userData, opData).send({from: operator})); + const userData = '0xdeadbeef'; + const opData = '0xbabecafe'; + await assertRevert( + this.token.contract.methods.operatorSend( + holder, + ZERO_ADDRESS, + '100', + userData, + opData + ).send({ from: operator }) + ); }); it('revert when sending an amount which is not a multiple of granularity', async function () { - let userData = "0xdeadbeef"; - let opData = "0xbabecafe"; - let tempToken = await ERC777.new("Test777", "T77", 10, [operator], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA, {from: holder}); - await assertRevert(tempToken.contract.methods.operatorSend(holder, anotherAccount, "15", userData, opData).send({from: operator})); + const userData = '0xdeadbeef'; + const opData = '0xbabecafe'; + const tempToken = await ERC777.new( + 'Test777', + 'T77', + 10, + [operator], + INITIAL_SUPPLY, + USER_DATA, + OPERATOR_DATA, + { from: holder } + ); + await assertRevert( + tempToken.contract.methods.operatorSend( + holder, + anotherAccount, + '15', + userData, + opData + ).send({ from: operator }) + ); }); it('operator is the holder when from is address(0)', async function () { - let userData = "0xdeadbeef"; - let opData = "0xbabecafe"; + const userData = '0xdeadbeef'; + const opData = '0xbabecafe'; + + this.token.contract.methods.send(operator, '100', userData).send({ from: holder }).then(async () => { + const { events } = await this.token.contract.methods.operatorSend( + ZERO_ADDRESS, + anotherAccount, + '100', + userData, + opData + ).send({ from: operator }); - this.token.contract.methods.send(operator, "100", userData).send({from: holder}).then(async () => { - const {events} = await this.token.contract.methods.operatorSend(ZERO_ADDRESS, anotherAccount, "100", userData, opData).send({from: operator}); expectEvent.inEvents(events, 'Sent', { operator: operator, from: operator, to: anotherAccount, - amount: "100", + amount: '100', data: userData, operatorData: opData, }); - }); + }).catch(errors => {}); }); describe('hooks', function () { - it('tokensToSend() hook is called when declared', async function () { - let userData = "0xdeadbeef"; - let opData = "0xbabecafe"; + const userData = '0xdeadbeef'; + const opData = '0xbabecafe'; // deploy sender contract, declare operator and give tokens - await operatorTests[test].deploy_sender.call(this, holder, operator, true); + await operatorTests[test].deploySender.call(this, holder, operator, true); + + await this.token.contract.methods.operatorSend( + this.sender.address, + anotherAccount, + '100', + userData, + opData + ).send({ from: operator }); - await this.token.contract.methods.operatorSend(this.sender.address, anotherAccount, "100", userData, opData).send({from: operator}); - let events = await this.sender.getPastEvents("TokensToSend"); + const events = await this.sender.getPastEvents('TokensToSend'); events.length.should.be.not.equal(0); - let event = events[0].returnValues; + const event = events[0].returnValues; event.operator.should.be.equal(operator); event.from.should.be.equal(this.sender.address); event.to.should.be.equal(anotherAccount); - event.amount.toString().should.be.equal("100"); + event.amount.toString().should.be.equal('100'); event.data.should.be.equal(userData); event.operatorData.should.be.equal(opData); }); it('tokensToSend() hook is not called when not declared', async function () { - - let userData = "0xdeadbeef"; - let opData = "0xbabecafe"; + const userData = '0xdeadbeef'; + const opData = '0xbabecafe'; // deploy sender contract, declare operator and give tokens - await operatorTests[test].deploy_sender.call(this, holder, operator, false); - - await this.token.contract.methods.operatorSend(this.sender.address, anotherAccount, "100", userData, opData).send({from: operator}); - let events = await this.sender.getPastEvents("TokensToSend"); - expect(events["tokensToSend"]).to.not.exist; + await operatorTests[test].deploySender.call(this, holder, operator, false); + + await this.token.contract.methods.operatorSend( + this.sender.address, + anotherAccount, + '100', + userData, + opData + ).send({ from: operator }); + + const events = await this.sender.getPastEvents('TokensToSend'); + // eslint-disable-next-line no-unused-expressions + expect(events.tokensToSend).to.not.exist; }); it('tokensReceived() hook is called when declared', async function () { - let userData = "0xdeadbeef"; - let opData = "0xbabecafe"; - - let receiver = await ERC777TokensRecipient.new(true); - await this.token.contract.methods.operatorSend(holder, receiver.address, "100", userData, opData).send({from: operator}); - let events = await receiver.getPastEvents("TokensReceived"); + const userData = '0xdeadbeef'; + const opData = '0xbabecafe'; + + const receiver = await ERC777TokensRecipient.new(true); + await this.token.contract.methods.operatorSend( + holder, + receiver.address, + '100', + userData, + opData + ).send({ from: operator }); + const events = await receiver.getPastEvents('TokensReceived'); events.length.should.be.not.equal(0); - let event = events[0].returnValues; + const event = events[0].returnValues; event.operator.should.be.equal(operator); event.from.should.be.equal(holder); event.to.should.be.equal(receiver.address); - event.amount.toString().should.be.equal("100"); + event.amount.toString().should.be.equal('100'); event.data.should.be.equal(userData); event.operatorData.should.be.equal(opData); }); it('tokensReceived() hook is not called when not declared', async function () { - let userData = "0xdeadbeef"; - let opData = "0xbabecafe"; - - let receiver = await ERC777TokensRecipient.new(false); - await this.token.contract.methods.operatorSend(holder, receiver.address, "100", userData, opData).send({from: operator}); - let events = await receiver.getPastEvents("TokensReceived"); - expect(events["tokensReceived"]).to.not.exist; + const userData = '0xdeadbeef'; + const opData = '0xbabecafe'; + + const receiver = await ERC777TokensRecipient.new(false); + await this.token.contract.methods.operatorSend( + holder, + receiver.address, + '100', + userData, + opData + ).send({ from: operator }); + + const events = await receiver.getPastEvents('TokensReceived'); + // eslint-disable-next-line no-unused-expressions + expect(events.tokensReceived).to.not.exist; }); }); - }); }); } }); - describe('burn()',function () { - let userData = "0xdeadbeef"; - + describe('burn()', function () { + const userData = '0xdeadbeef'; + before('Deploy ERC777', async function () { - this.token = await ERC777.new("Test777", "T77", 1, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA, {from: holder}); + this.token = await ERC777.new( + 'Test777', + 'T77', + 1, + [], + INITIAL_SUPPLY, + USER_DATA, + OPERATOR_DATA, + { from: holder } + ); }); it('Burned event is emitted when burning 0 token', async function () { - const {events} = await this.token.contract.methods.burn("0", userData).send({from: holder}); + const { events } = await this.token.contract.methods.burn('0', userData).send({ from: holder }); expectEvent.inEvents(events, 'Burned', { operator: holder, from: holder, - amount: "0", - data: userData + amount: '0', + data: userData, }); }); it('revert when burning an amount of token from an account with insufficient balance', async function () { - let amount = parseInt(INITIAL_SUPPLY, 10) + 100; - await assertRevert(this.token.contract.methods.burn(amount.toString(), userData).send({from: holder})); + const amount = parseInt(INITIAL_SUPPLY, 10) + 100; + await assertRevert(this.token.contract.methods.burn(amount.toString(), userData).send({ from: holder })); }); describe('burning an amount of token from an account with sufficient balance', function () { it('Burned event is emitted', async function () { - - const {events} = await this.token.contract.methods.burn("100", userData).send({from: holder}); + const { events } = await this.token.contract.methods.burn('100', userData).send({ from: holder }); expectEvent.inEvents(events, 'Burned', { operator: holder, from: holder, - amount: "100", - data: userData + amount: '100', + data: userData, }); }); it('holder balance is decreased', async function () { - let balance = parseInt(INITIAL_SUPPLY, 10) - 100; + const balance = parseInt(INITIAL_SUPPLY, 10) - 100; (await this.token.balanceOf(holder)).toString().should.be.equal(balance.toString()); }); it('balance of 0x0 is not increased', async function () { - (await this.token.balanceOf(ZERO_ADDRESS)).toString().should.be.equal("0"); + (await this.token.balanceOf(ZERO_ADDRESS)).toString().should.be.equal('0'); }); it('totalSupply is decreased', async function () { - let supply = parseInt(INITIAL_SUPPLY, 10) - 100; + const supply = parseInt(INITIAL_SUPPLY, 10) - 100; (await this.token.totalSupply()).toString().should.be.equal(supply.toString()); }); describe('hooks', function () { it('tokensToSend() hook is called when declared, and data is 0x00', async function () { // deploy sender contract and give tokens - let sender = await ERC777TokensSender.new(true, this.token.address); - await this.token.contract.methods.send(sender.address, "100", web3.utils.asciiToHex("")).send({from: holder}); - - const {events} = await sender.contract.methods.burnTokens("100", userData).send({from: holder}); + const sender = await ERC777TokensSender.new(true, this.token.address); + await this.token.contract.methods.send( + sender.address, + '100', + web3.utils.asciiToHex('') + ).send({ from: holder }); + + const { events } = await sender.contract.methods.burnTokens('100', userData).send({ from: holder }); expectEvent.inEvents(events, 'TokensToSend', { operator: sender.address, from: sender.address, to: ZERO_ADDRESS, - amount: "100", + amount: '100', data: userData, }); }); it('tokensToSend() hook is not called when not declared', async function () { // deploy sender contract and give tokens - let sender = await ERC777TokensSender.new(false, this.token.address); - await this.token.contract.methods.send(sender.address, "100", web3.utils.asciiToHex("")).send({from: holder}); - - const {events} = await sender.contract.methods.burnTokens("100", userData).send({from: holder}); - expect(events["tokensToSend"]).to.not.exist; + const sender = await ERC777TokensSender.new(false, this.token.address); + await this.token.contract.methods.send( + sender.address, + '100', + web3.utils.asciiToHex('') + ).send({ from: holder }); + + const { events } = await sender.contract.methods.burnTokens('100', userData).send({ from: holder }); + // eslint-disable-next-line no-unused-expressions + expect(events.tokensToSend).to.not.exist; }); }); it('revert when sending an amount which is not a multiple of granularity', async function () { - let tempToken = await ERC777.new("Test777", "T77", 10, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA, {from: holder}); - await assertRevert(tempToken.contract.methods.burn("15", userData).send({from: holder})); + const tempToken = await ERC777.new( + 'Test777', + 'T77', + 10, + [], + INITIAL_SUPPLY, + USER_DATA, + OPERATOR_DATA, + { from: holder } + ); + await assertRevert(tempToken.contract.methods.burn('15', userData).send({ from: holder })); }); }); }); - describe('operatorBurn()',function () { - let operatorTests = { + describe('operatorBurn()', function () { + const operatorTests = { defaultOperatorTest: { - name: "default operator", - deploy_fn: async function (holder, operator) { + name: 'default operator', + deployFn: async function (holder, operator) { this.token = await ERC777.new( - "Test777", - "T77", + 'Test777', + 'T77', 1, [operator], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA, - {from: holder} - ); + { from: holder } + ); + }, + deploySender: async function (holder, operator, declareInterface) { + // deploy sender contract and give tokens + this.sender = await ERC777TokensSender.new(declareInterface, this.token.address); + await this.token.contract.methods.send( + this.sender.address, + '100', + web3.utils.asciiToHex('') + ).send({ from: holder }); }, - deploy_sender: async function (holder, operator, declareInterface) { - // deploy sender contract and give tokens - this.sender = await ERC777TokensSender.new(declareInterface, this.token.address); - await this.token.contract.methods.send(this.sender.address, "100", web3.utils.asciiToHex("")).send({from: holder}); - } }, nonDefaultOperatorTest: { - name: "non-default operator", - deploy_fn: async function (holder, operator) { + name: 'non-default operator', + deployFn: async function (holder, operator) { this.token = await ERC777.new( - "Test777", - "T77", + 'Test777', + 'T77', 1, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA, - {from: holder} - ); - await this.token.authorizeOperator(operator, {from: holder}); + { from: holder } + ); + await this.token.authorizeOperator(operator, { from: holder }); + }, + deploySender: async function (holder, operator, declareInterface) { + // deploy sender contract and give tokens + this.sender = await ERC777TokensSender.new(declareInterface, this.token.address); + + await this.token.contract.methods.send( + this.sender.address, + '100', + web3.utils.asciiToHex('') + ).send({ from: holder }); + + // declare operator + await this.sender.contract.methods.authorizeOperator(operator).send({ from: holder }); }, - deploy_sender: async function (holder, operator, declareInterface) { - // deploy sender contract and give tokens - this.sender = await ERC777TokensSender.new(declareInterface, this.token.address); - await this.token.contract.methods.send(this.sender.address, "100", web3.utils.asciiToHex("")).send({from: holder}); - // declare operator - await this.sender.contract.methods.authorizeOperator(operator).send({from: holder}); - } - } + }, }; - + it('revert when msg.sender is not an operator', async function () { - let tempToken = await ERC777.new("Test777", "T77", 1, [operator], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA, {from: holder}); - let opData = "0xbabecafe"; - let userData = "0xdeadbeef"; - await assertRevert(tempToken.contract.methods.operatorBurn(holder, "100", userData, opData).send({from: anotherAccount})); + const tempToken = await ERC777.new( + 'Test777', + 'T77', + 1, + [operator], + INITIAL_SUPPLY, + USER_DATA, + OPERATOR_DATA, + { from: holder } + ); + const opData = '0xbabecafe'; + const userData = '0xdeadbeef'; + await assertRevert( + tempToken.contract.methods.operatorBurn(holder, '100', userData, opData).send({ from: anotherAccount }) + ); }); - for (let test in operatorTests) { - + for (const test in operatorTests) { describe('when operator is a ' + operatorTests[test].name, function () { - - before('Deploy ERC777', async function() { - await operatorTests[test].deploy_fn.call(this, holder, operator); + before('Deploy ERC777', async function () { + await operatorTests[test].deployFn.call(this, holder, operator); }); it('Burned event is emitted when burning 0 token', async function () { - let opData = "0xbabecafe"; - let userData = "0xdeadbeef"; + const opData = '0xbabecafe'; + const userData = '0xdeadbeef'; + + const { events } = await this.token.contract.methods.operatorBurn( + holder, + '0', + userData, + opData + ).send({ from: operator }); - const {events} = await this.token.contract.methods.operatorBurn(holder, "0", userData, opData).send({from: operator}); expectEvent.inEvents(events, 'Burned', { operator: operator, from: holder, - amount: "0", + amount: '0', data: userData, operatorData: opData, }); }); it('revert when burning an amount of token from an account with insufficient balance', async function () { - let amount = parseInt(INITIAL_SUPPLY, 10) + 100; - let opData = "0xbabecafe"; - let userData = "0xdeadbeef"; - await assertRevert(this.token.contract.methods.operatorBurn(holder, amount.toString(), userData, opData).send({from: operator})); + const amount = parseInt(INITIAL_SUPPLY, 10) + 100; + const opData = '0xbabecafe'; + const userData = '0xdeadbeef'; + await assertRevert( + this.token.contract.methods.operatorBurn( + holder, + amount.toString(), + userData, + opData + ).send({ from: operator }) + ); }); describe('burning an amount of token from an account with sufficient balance', function () { it('Burned event is emitted', async function () { - let opData = "0xbabecafe"; - let userData = "0xdeadbeef"; + const opData = '0xbabecafe'; + const userData = '0xdeadbeef'; + + const { events } = await this.token.contract.methods.operatorBurn( + holder, + '100', + userData, + opData + ).send({ from: operator }); - const {events} = await this.token.contract.methods.operatorBurn(holder, "100", userData, opData).send({from: operator}); expectEvent.inEvents(events, 'Burned', { operator: operator, from: holder, - amount: "100", + amount: '100', data: userData, operatorData: opData, }); }); it('holder balance is decreased', async function () { - let balance = parseInt(INITIAL_SUPPLY, 10) - 100; + const balance = parseInt(INITIAL_SUPPLY, 10) - 100; (await this.token.balanceOf(holder)).toString().should.be.equal(balance.toString()); }); it('balance of 0x0 is not increased', async function () { - (await this.token.balanceOf(ZERO_ADDRESS)).toString().should.be.equal("0"); + (await this.token.balanceOf(ZERO_ADDRESS)).toString().should.be.equal('0'); }); it('totalSupply is decreased', async function () { - let supply = parseInt(INITIAL_SUPPLY, 10) - 100; + const supply = parseInt(INITIAL_SUPPLY, 10) - 100; (await this.token.totalSupply()).toString().should.be.equal(supply.toString()); }); it('revert when burning an amount which is not a multiple of granularity', async function () { - let opData = "0xbabecafe"; - let userData = "0xdeadbeef"; - let tempToken = await ERC777.new("Test777", "T77", 10, [operator], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA, {from: holder}); - await assertRevert(tempToken.contract.methods.operatorBurn(holder, "15", userData, opData).send({from: operator})); + const opData = '0xbabecafe'; + const userData = '0xdeadbeef'; + const tempToken = await ERC777.new( + 'Test777', + 'T77', + 10, + [operator], + INITIAL_SUPPLY, + USER_DATA, + OPERATOR_DATA, + { from: holder } + ); + await assertRevert( + tempToken.contract.methods.operatorBurn(holder, '15', userData, opData).send({ from: operator }) + ); }); it('operator is the holder when from is address(0)', async function () { - let opData = "0xbabecafe"; - let userData = "0xdeadbeef"; + const opData = '0xbabecafe'; + const userData = '0xdeadbeef'; + + await this.token.contract.methods.send(operator, '100', web3.utils.asciiToHex('')).send({ from: holder }); + const { events } = await this.token.contract.methods.operatorBurn( + ZERO_ADDRESS, + '100', + userData, + opData + ).send({ from: operator }); - await this.token.contract.methods.send(operator, "100", web3.utils.asciiToHex("")).send({from: holder}); - const {events} = await this.token.contract.methods.operatorBurn(ZERO_ADDRESS, "100", userData, opData).send({from: operator}); expectEvent.inEvents(events, 'Burned', { operator: operator, from: operator, - amount: "100", + amount: '100', data: userData, operatorData: opData, }); }); describe('hooks', function () { - it('tokensToSend() hook is called when declared', async function () { - let opData = "0xbabecafe"; - let userData = "0xdeadbeef"; + const opData = '0xbabecafe'; + const userData = '0xdeadbeef'; // deploy sender contract, declare operator and give tokens - await operatorTests[test].deploy_sender.call(this, holder, operator, true); + await operatorTests[test].deploySender.call(this, holder, operator, true); + + await this.token.contract.methods.operatorBurn( + this.sender.address, + '100', + userData, + opData + ).send({ from: operator }); - await this.token.contract.methods.operatorBurn(this.sender.address, "100", userData, opData).send({from: operator}); - let events = await this.sender.getPastEvents("TokensToSend"); + const events = await this.sender.getPastEvents('TokensToSend'); events.length.should.be.not.equal(0); - let event = events[0].returnValues; + const event = events[0].returnValues; event.operator.should.be.equal(operator); event.from.should.be.equal(this.sender.address); - event.amount.toString().should.be.equal("100"); + event.amount.toString().should.be.equal('100'); event.data.should.be.equal(userData); event.operatorData.should.be.equal(opData); }); it('tokensToSend() hook is not called when not declared', async function () { - - let opData = "0xbabecafe"; - let userData = "0xdeadbeef"; + const opData = '0xbabecafe'; + const userData = '0xdeadbeef'; // deploy sender contract, declare operator and give tokens - await operatorTests[test].deploy_sender.call(this, holder, operator, false); - - await this.token.contract.methods.operatorBurn(this.sender.address, "100", userData, opData).send({from: operator}); - let events = await this.sender.getPastEvents("TokensToSend"); - expect(events["tokensToSend"]).to.not.exist; + await operatorTests[test].deploySender.call(this, holder, operator, false); + + await this.token.contract.methods.operatorBurn( + this.sender.address, + '100', + userData, + opData + ).send({ from: operator }); + + const events = await this.sender.getPastEvents('TokensToSend'); + // eslint-disable-next-line no-unused-expressions + expect(events.tokensToSend).to.not.exist; }); }); }); }); } }); - }); diff --git a/test/helpers/expectEvent.js b/test/helpers/expectEvent.js index 81eea675225..5750157391e 100644 --- a/test/helpers/expectEvent.js +++ b/test/helpers/expectEvent.js @@ -4,7 +4,7 @@ const should = require('chai') .should(); function inEvents (events, eventName, eventArgs = {}) { - event = Object.values(events).find(function (e) { + const _event = Object.values(events).find(function (e) { if (e.event === eventName) { for (const [k, v] of Object.entries(eventArgs)) { contains(e.returnValues, k, v); @@ -12,8 +12,8 @@ function inEvents (events, eventName, eventArgs = {}) { return true; } }); - should.exist(event); - return event; + should.exist(_event); + return _event; } function inLogs (logs, eventName, eventArgs = {}) { @@ -36,9 +36,8 @@ async function inTransaction (tx, eventName, eventArgs = {}) { function contains (args, key, value) { if (args[key] == null) { - value.should.be.equal("0x00"); - } - else if (isBigNumber(args[key])) { + value.should.be.equal('0x00'); + } else if (isBigNumber(args[key])) { args[key].toString().should.be.equal(value); } else { args[key].should.be.equal(value); diff --git a/test/introspection/ERC1820Deploy.js b/test/introspection/ERC1820Deploy.js index 34e7bc0c12b..9482935b2ef 100644 --- a/test/introspection/ERC1820Deploy.js +++ b/test/introspection/ERC1820Deploy.js @@ -1,14 +1,14 @@ -const BN = web3.utils.BN; const { sendEther } = require('../helpers/sendTransaction'); const ERC1820Deploy = async function (owner) { - const deployAccount = "0x5808bA8E60E0367C9067b328D75C1f3d29de58cf"; - const deployTx = "0xf90a388085174876e800830c35008080b909e5608060405234801561001057600080fd5b506109c5806100206000396000f3fe608060405234801561001057600080fd5b50600436106100a5576000357c010000000000000000000000000000000000000000000000000000000090048063a41e7d5111610078578063a41e7d51146101d4578063aabbb8ca1461020a578063b705676514610236578063f712f3e814610280576100a5565b806329965a1d146100aa5780633d584063146100e25780635df8122f1461012457806365ba36c114610152575b600080fd5b6100e0600480360360608110156100c057600080fd5b50600160a060020a038135811691602081013591604090910135166102b6565b005b610108600480360360208110156100f857600080fd5b5035600160a060020a0316610570565b60408051600160a060020a039092168252519081900360200190f35b6100e06004803603604081101561013a57600080fd5b50600160a060020a03813581169160200135166105bc565b6101c26004803603602081101561016857600080fd5b81019060208101813564010000000081111561018357600080fd5b82018360208201111561019557600080fd5b803590602001918460018302840111640100000000831117156101b757600080fd5b5090925090506106b3565b60408051918252519081900360200190f35b6100e0600480360360408110156101ea57600080fd5b508035600160a060020a03169060200135600160e060020a0319166106ee565b6101086004803603604081101561022057600080fd5b50600160a060020a038135169060200135610778565b61026c6004803603604081101561024c57600080fd5b508035600160a060020a03169060200135600160e060020a0319166107ef565b604080519115158252519081900360200190f35b61026c6004803603604081101561029657600080fd5b508035600160a060020a03169060200135600160e060020a0319166108aa565b6000600160a060020a038416156102cd57836102cf565b335b9050336102db82610570565b600160a060020a031614610339576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b6103428361092a565b15610397576040805160e560020a62461bcd02815260206004820152601a60248201527f4d757374206e6f7420626520616e204552433136352068617368000000000000604482015290519081900360640190fd5b600160a060020a038216158015906103b85750600160a060020a0382163314155b156104ff5760405160200180807f455243313832305f4143434550545f4d4147494300000000000000000000000081525060140190506040516020818303038152906040528051906020012082600160a060020a031663249cb3fa85846040518363ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018083815260200182600160a060020a0316600160a060020a031681526020019250505060206040518083038186803b15801561047e57600080fd5b505afa158015610492573d6000803e3d6000fd5b505050506040513d60208110156104a857600080fd5b5051146104ff576040805160e560020a62461bcd02815260206004820181905260248201527f446f6573206e6f7420696d706c656d656e742074686520696e74657266616365604482015290519081900360640190fd5b600160a060020a03818116600081815260208181526040808320888452909152808220805473ffffffffffffffffffffffffffffffffffffffff19169487169485179055518692917f93baa6efbd2244243bfee6ce4cfdd1d04fc4c0e9a786abd3a41313bd352db15391a450505050565b600160a060020a03818116600090815260016020526040812054909116151561059a5750806105b7565b50600160a060020a03808216600090815260016020526040902054165b919050565b336105c683610570565b600160a060020a031614610624576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b81600160a060020a031681600160a060020a0316146106435780610646565b60005b600160a060020a03838116600081815260016020526040808220805473ffffffffffffffffffffffffffffffffffffffff19169585169590951790945592519184169290917f605c2dbf762e5f7d60a546d42e7205dcb1b011ebc62a61736a57c9089d3a43509190a35050565b600082826040516020018083838082843780830192505050925050506040516020818303038152906040528051906020012090505b92915050565b6106f882826107ef565b610703576000610705565b815b600160a060020a03928316600081815260208181526040808320600160e060020a031996909616808452958252808320805473ffffffffffffffffffffffffffffffffffffffff19169590971694909417909555908152600284528181209281529190925220805460ff19166001179055565b600080600160a060020a038416156107905783610792565b335b905061079d8361092a565b156107c357826107ad82826108aa565b6107b85760006107ba565b815b925050506106e8565b600160a060020a0390811660009081526020818152604080832086845290915290205416905092915050565b6000808061081d857f01ffc9a70000000000000000000000000000000000000000000000000000000061094c565b909250905081158061082d575080155b1561083d576000925050506106e8565b61084f85600160e060020a031961094c565b909250905081158061086057508015155b15610870576000925050506106e8565b61087a858561094c565b909250905060018214801561088f5750806001145b1561089f576001925050506106e8565b506000949350505050565b600160a060020a0382166000908152600260209081526040808320600160e060020a03198516845290915281205460ff1615156108f2576108eb83836107ef565b90506106e8565b50600160a060020a03808316600081815260208181526040808320600160e060020a0319871684529091529020549091161492915050565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff161590565b6040517f01ffc9a7000000000000000000000000000000000000000000000000000000008082526004820183905260009182919060208160248189617530fa90519096909550935050505056fea165627a7a723058207d33f0c34a1016c7fcf5f8547cd8c09a74f837ed2564550f647531f1128056ec00291ba01820182018201820182018201820182018201820182018201820182018201820a01820182018201820182018201820182018201820182018201820182018201820"; + const deployAccount = '0x5808bA8E60E0367C9067b328D75C1f3d29de58cf'; + // eslint-disable-next-line max-len + const deployTx = '0xf90a388085174876e800830c35008080b909e5608060405234801561001057600080fd5b506109c5806100206000396000f3fe608060405234801561001057600080fd5b50600436106100a5576000357c010000000000000000000000000000000000000000000000000000000090048063a41e7d5111610078578063a41e7d51146101d4578063aabbb8ca1461020a578063b705676514610236578063f712f3e814610280576100a5565b806329965a1d146100aa5780633d584063146100e25780635df8122f1461012457806365ba36c114610152575b600080fd5b6100e0600480360360608110156100c057600080fd5b50600160a060020a038135811691602081013591604090910135166102b6565b005b610108600480360360208110156100f857600080fd5b5035600160a060020a0316610570565b60408051600160a060020a039092168252519081900360200190f35b6100e06004803603604081101561013a57600080fd5b50600160a060020a03813581169160200135166105bc565b6101c26004803603602081101561016857600080fd5b81019060208101813564010000000081111561018357600080fd5b82018360208201111561019557600080fd5b803590602001918460018302840111640100000000831117156101b757600080fd5b5090925090506106b3565b60408051918252519081900360200190f35b6100e0600480360360408110156101ea57600080fd5b508035600160a060020a03169060200135600160e060020a0319166106ee565b6101086004803603604081101561022057600080fd5b50600160a060020a038135169060200135610778565b61026c6004803603604081101561024c57600080fd5b508035600160a060020a03169060200135600160e060020a0319166107ef565b604080519115158252519081900360200190f35b61026c6004803603604081101561029657600080fd5b508035600160a060020a03169060200135600160e060020a0319166108aa565b6000600160a060020a038416156102cd57836102cf565b335b9050336102db82610570565b600160a060020a031614610339576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b6103428361092a565b15610397576040805160e560020a62461bcd02815260206004820152601a60248201527f4d757374206e6f7420626520616e204552433136352068617368000000000000604482015290519081900360640190fd5b600160a060020a038216158015906103b85750600160a060020a0382163314155b156104ff5760405160200180807f455243313832305f4143434550545f4d4147494300000000000000000000000081525060140190506040516020818303038152906040528051906020012082600160a060020a031663249cb3fa85846040518363ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018083815260200182600160a060020a0316600160a060020a031681526020019250505060206040518083038186803b15801561047e57600080fd5b505afa158015610492573d6000803e3d6000fd5b505050506040513d60208110156104a857600080fd5b5051146104ff576040805160e560020a62461bcd02815260206004820181905260248201527f446f6573206e6f7420696d706c656d656e742074686520696e74657266616365604482015290519081900360640190fd5b600160a060020a03818116600081815260208181526040808320888452909152808220805473ffffffffffffffffffffffffffffffffffffffff19169487169485179055518692917f93baa6efbd2244243bfee6ce4cfdd1d04fc4c0e9a786abd3a41313bd352db15391a450505050565b600160a060020a03818116600090815260016020526040812054909116151561059a5750806105b7565b50600160a060020a03808216600090815260016020526040902054165b919050565b336105c683610570565b600160a060020a031614610624576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b81600160a060020a031681600160a060020a0316146106435780610646565b60005b600160a060020a03838116600081815260016020526040808220805473ffffffffffffffffffffffffffffffffffffffff19169585169590951790945592519184169290917f605c2dbf762e5f7d60a546d42e7205dcb1b011ebc62a61736a57c9089d3a43509190a35050565b600082826040516020018083838082843780830192505050925050506040516020818303038152906040528051906020012090505b92915050565b6106f882826107ef565b610703576000610705565b815b600160a060020a03928316600081815260208181526040808320600160e060020a031996909616808452958252808320805473ffffffffffffffffffffffffffffffffffffffff19169590971694909417909555908152600284528181209281529190925220805460ff19166001179055565b600080600160a060020a038416156107905783610792565b335b905061079d8361092a565b156107c357826107ad82826108aa565b6107b85760006107ba565b815b925050506106e8565b600160a060020a0390811660009081526020818152604080832086845290915290205416905092915050565b6000808061081d857f01ffc9a70000000000000000000000000000000000000000000000000000000061094c565b909250905081158061082d575080155b1561083d576000925050506106e8565b61084f85600160e060020a031961094c565b909250905081158061086057508015155b15610870576000925050506106e8565b61087a858561094c565b909250905060018214801561088f5750806001145b1561089f576001925050506106e8565b506000949350505050565b600160a060020a0382166000908152600260209081526040808320600160e060020a03198516845290915281205460ff1615156108f2576108eb83836107ef565b90506106e8565b50600160a060020a03808316600081815260208181526040808320600160e060020a0319871684529091529020549091161492915050565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff161590565b6040517f01ffc9a7000000000000000000000000000000000000000000000000000000008082526004820183905260009182919060208160248189617530fa90519096909550935050505056fea165627a7a723058207d33f0c34a1016c7fcf5f8547cd8c09a74f837ed2564550f647531f1128056ec00291ba01820182018201820182018201820182018201820182018201820182018201820a01820182018201820182018201820182018201820182018201820182018201820'; // send 0.08 ether to deployment account - sendEther(owner, deployAccount, web3.utils.toWei("0.08",'ether')); + sendEther(owner, deployAccount, web3.utils.toWei('0.08', 'ether')); // create ERC1820 contract - let address = (await web3.eth.sendSignedTransaction(deployTx)).contractAddress; + const address = (await web3.eth.sendSignedTransaction(deployTx)).contractAddress; return address; }; From 2582a2a0655ff60d65c8a2b54d9784794bf2c98c Mon Sep 17 00:00:00 2001 From: Bertrand Masius Date: Sun, 17 Mar 2019 14:14:54 +0100 Subject: [PATCH 14/64] ERC777 Update to solc 0.5.2 (#1159) --- contracts/drafts/ERC777/ERC777.sol | 12 ++--- contracts/drafts/ERC777/ERC777Base.sol | 46 +++++++++---------- contracts/drafts/ERC777/ERC777Burnable.sol | 8 ++-- contracts/drafts/ERC777/IERC777.sol | 20 ++++---- .../drafts/ERC777/IERC777TokensRecipient.sol | 7 ++- .../drafts/ERC777/IERC777TokensSender.sol | 7 ++- contracts/introspection/ERC1820Client.sol | 2 +- contracts/introspection/IERC1820.sol | 4 +- contracts/mocks/ERC777ReceiverMock.sol | 6 +-- contracts/mocks/ERC777SenderMock.sol | 20 +++++--- test/drafts/ERC777/ERC777.test.js | 44 +++++++++--------- test/helpers/expectEvent.js | 12 ++--- test/introspection/ERC1820Deploy.js | 4 +- 13 files changed, 98 insertions(+), 94 deletions(-) diff --git a/contracts/drafts/ERC777/ERC777.sol b/contracts/drafts/ERC777/ERC777.sol index 943183a7ca5..84580ce8d2c 100644 --- a/contracts/drafts/ERC777/ERC777.sol +++ b/contracts/drafts/ERC777/ERC777.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.4.24; +pragma solidity ^0.5.2; import "./ERC777Base.sol"; @@ -21,13 +21,13 @@ contract ERC777 is ERC777Base { * @param operatorData bytes extra information provided by the operator (if any) */ constructor( - string name, - string symbol, + string memory name, + string memory symbol, uint256 granularity, - address[] defaultOperators, + address[] memory defaultOperators, uint256 initialSupply, - bytes data, - bytes operatorData + bytes memory data, + bytes memory operatorData ) ERC777Base( name, diff --git a/contracts/drafts/ERC777/ERC777Base.sol b/contracts/drafts/ERC777/ERC777Base.sol index dc2846e28c1..d0c89b99cbf 100644 --- a/contracts/drafts/ERC777/ERC777Base.sol +++ b/contracts/drafts/ERC777/ERC777Base.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.4.24; +pragma solidity ^0.5.2; import "./IERC777.sol"; import "./IERC777TokensRecipient.sol"; @@ -37,10 +37,10 @@ contract ERC777Base is IERC777, ERC1820Client { mapping(address => mapping(address => bool)) private _ops; constructor( - string name, - string symbol, + string memory name, + string memory symbol, uint256 granularity, - address[] defaultOperators + address[] memory defaultOperators ) internal { require(granularity > 0); _name = name; @@ -67,7 +67,7 @@ contract ERC777Base is IERC777, ERC1820Client { function send( address to, uint256 amount, - bytes data + bytes calldata data ) external { _send( msg.sender, @@ -91,8 +91,8 @@ contract ERC777Base is IERC777, ERC1820Client { address from, address to, uint256 amount, - bytes data, - bytes operatorData + bytes calldata data, + bytes calldata operatorData ) external { @@ -112,7 +112,7 @@ contract ERC777Base is IERC777, ERC1820Client { * @param amount uint256 amount of tokens to transfer * @param data bytes extra information provided by the token holder */ - function burn(uint256 amount, bytes data) external { + function burn(uint256 amount, bytes calldata data) external { _burn( msg.sender, msg.sender, @@ -132,8 +132,8 @@ contract ERC777Base is IERC777, ERC1820Client { function operatorBurn( address from, uint256 amount, - bytes data, - bytes operatorData + bytes calldata data, + bytes calldata operatorData ) external { @@ -150,14 +150,14 @@ contract ERC777Base is IERC777, ERC1820Client { /** * @return the name of the token. */ - function name() public view returns (string) { + function name() public view returns (string memory) { return _name; } /** * @return the symbol of the token. */ - function symbol() public view returns (string) { + function symbol() public view returns (string memory) { return _symbol; } @@ -191,7 +191,7 @@ contract ERC777Base is IERC777, ERC1820Client { * @dev Get the list of default operators as defined by the token contract. * @return address[] default operators */ - function defaultOperators() public view returns (address[]) { + function defaultOperators() public view returns (address[] memory) { return _defaultOpsArray; } @@ -246,8 +246,8 @@ contract ERC777Base is IERC777, ERC1820Client { address operator, address from, uint256 amount, - bytes data, - bytes operatorData + bytes memory data, + bytes memory operatorData ) internal { @@ -290,8 +290,8 @@ contract ERC777Base is IERC777, ERC1820Client { address operator, address to, uint256 amount, - bytes userData, - bytes operatorData + bytes memory userData, + bytes memory operatorData ) internal { @@ -373,8 +373,8 @@ contract ERC777Base is IERC777, ERC1820Client { address from, address to, uint256 amount, - bytes userData, - bytes operatorData + bytes memory userData, + bytes memory operatorData ) private { @@ -430,8 +430,8 @@ contract ERC777Base is IERC777, ERC1820Client { address from, address to, uint256 amount, - bytes userData, - bytes operatorData + bytes memory userData, + bytes memory operatorData ) private { @@ -464,8 +464,8 @@ contract ERC777Base is IERC777, ERC1820Client { address from, address to, uint256 amount, - bytes userData, - bytes operatorData + bytes memory userData, + bytes memory operatorData ) private returns(bool) diff --git a/contracts/drafts/ERC777/ERC777Burnable.sol b/contracts/drafts/ERC777/ERC777Burnable.sol index 8993e842cd5..2aeb883b9b2 100644 --- a/contracts/drafts/ERC777/ERC777Burnable.sol +++ b/contracts/drafts/ERC777/ERC777Burnable.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.4.24; +pragma solidity ^0.5.2; import "./ERC777Base.sol"; @@ -15,7 +15,7 @@ contract ERC777Burnable is ERC777Base { * @param amount uint256 amount of tokens to transfer * @param data bytes data provided by the token holder */ - function burn(uint256 amount, bytes data) external { + function burn(uint256 amount, bytes calldata data) external { _burn( msg.sender, msg.sender, @@ -35,8 +35,8 @@ contract ERC777Burnable is ERC777Base { function operatorBurn( address from, uint256 amount, - bytes data, - bytes operatorData + bytes calldata data, + bytes calldata operatorData ) external { address holder = from == address(0) ? msg.sender : from; _burn( diff --git a/contracts/drafts/ERC777/IERC777.sol b/contracts/drafts/ERC777/IERC777.sol index 8168abe8f8b..4b6b99bfee3 100644 --- a/contracts/drafts/ERC777/IERC777.sol +++ b/contracts/drafts/ERC777/IERC777.sol @@ -1,13 +1,13 @@ -pragma solidity ^0.4.24; +pragma solidity ^0.5.2; /** * @title ERC777 interface * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-777.md */ interface IERC777 { - function name() external view returns (string); + function name() external view returns (string memory); - function symbol() external view returns (string); + function symbol() external view returns (string memory); function totalSupply() external view returns (uint256); @@ -15,7 +15,7 @@ interface IERC777 { function granularity() external view returns (uint256); - function defaultOperators() external view returns (address[]); + function defaultOperators() external view returns (address[] memory); function authorizeOperator(address operator) external; @@ -26,23 +26,23 @@ interface IERC777 { address tokenHolder ) external view returns (bool); - function send(address to, uint256 amount, bytes data) external; + function send(address to, uint256 amount, bytes calldata data) external; function operatorSend( address from, address to, uint256 amount, - bytes data, - bytes operatorData + bytes calldata data, + bytes calldata operatorData ) external; - function burn(uint256 amount, bytes data) external; + function burn(uint256 amount, bytes calldata data) external; function operatorBurn( address from, uint256 amount, - bytes data, - bytes operatorData + bytes calldata data, + bytes calldata operatorData ) external; event Sent( diff --git a/contracts/drafts/ERC777/IERC777TokensRecipient.sol b/contracts/drafts/ERC777/IERC777TokensRecipient.sol index ce7e11d3e34..c44fc53f04d 100644 --- a/contracts/drafts/ERC777/IERC777TokensRecipient.sol +++ b/contracts/drafts/ERC777/IERC777TokensRecipient.sol @@ -1,8 +1,7 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -// solhint-disable-next-line compiler-fixed -pragma solidity ^0.4.24; +pragma solidity ^0.5.2; interface IERC777TokensRecipient { function tokensReceived( @@ -10,7 +9,7 @@ interface IERC777TokensRecipient { address from, address to, uint amount, - bytes userData, - bytes operatorData + bytes calldata userData, + bytes calldata operatorData ) external; } diff --git a/contracts/drafts/ERC777/IERC777TokensSender.sol b/contracts/drafts/ERC777/IERC777TokensSender.sol index 54570a81932..73b2e79a8f0 100644 --- a/contracts/drafts/ERC777/IERC777TokensSender.sol +++ b/contracts/drafts/ERC777/IERC777TokensSender.sol @@ -1,8 +1,7 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -// solhint-disable-next-line compiler-fixed -pragma solidity ^0.4.24; +pragma solidity ^0.5.2; interface IERC777TokensSender { function tokensToSend( @@ -10,7 +9,7 @@ interface IERC777TokensSender { address from, address to, uint amount, - bytes userData, - bytes operatorData + bytes calldata userData, + bytes calldata operatorData ) external; } diff --git a/contracts/introspection/ERC1820Client.sol b/contracts/introspection/ERC1820Client.sol index efe1e7811c3..1c9084195fe 100644 --- a/contracts/introspection/ERC1820Client.sol +++ b/contracts/introspection/ERC1820Client.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.4.24; +pragma solidity ^0.5.2; import "./IERC1820.sol"; diff --git a/contracts/introspection/IERC1820.sol b/contracts/introspection/IERC1820.sol index 76c4ade9743..1572e39206e 100644 --- a/contracts/introspection/IERC1820.sol +++ b/contracts/introspection/IERC1820.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.4.24; +pragma solidity ^0.5.2; /** * @title IERC1820 @@ -24,7 +24,7 @@ interface IERC1820 { function getManager(address _addr) external view returns(address); function interfaceHash( - string _interfaceName + string calldata _interfaceName ) external pure returns(bytes32); function updateERC165Cache( diff --git a/contracts/mocks/ERC777ReceiverMock.sol b/contracts/mocks/ERC777ReceiverMock.sol index 3c4b744db0b..a0f6b9f4d44 100644 --- a/contracts/mocks/ERC777ReceiverMock.sol +++ b/contracts/mocks/ERC777ReceiverMock.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.4.24; +pragma solidity ^0.5.2; import "../drafts/ERC777/IERC777TokensRecipient.sol"; import "../introspection/ERC1820Client.sol"; @@ -44,8 +44,8 @@ contract ERC777ReceiverMock is IERC777TokensRecipient, ERC1820Client { address from, address to, uint256 amount, - bytes userData, - bytes operatorData + bytes calldata userData, + bytes calldata operatorData ) external { diff --git a/contracts/mocks/ERC777SenderMock.sol b/contracts/mocks/ERC777SenderMock.sol index 481f0ffe778..cd63393846f 100644 --- a/contracts/mocks/ERC777SenderMock.sol +++ b/contracts/mocks/ERC777SenderMock.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.4.24; +pragma solidity ^0.5.2; import "../drafts/ERC777/IERC777.sol"; import "../drafts/ERC777/IERC777TokensSender.sol"; @@ -26,7 +26,11 @@ contract ERC777SenderMock is IERC777TokensSender, ERC1820Client { _erc777 = erc777; // register interface if (setInterface) { - setInterfaceImplementer(address(this), keccak256("ERC777TokensSender"), address(this)); + setInterfaceImplementer( + address(this), + keccak256("ERC777TokensSender"), + address(this) + ); } } @@ -36,7 +40,11 @@ contract ERC777SenderMock is IERC777TokensSender, ERC1820Client { * @param amount uint256 amount of tokens to transfer * @param data bytes extra information provided by the token holder (if any) */ - function sendTokens(address to, uint amount, bytes data) external { + function sendTokens( + address to, + uint amount, + bytes calldata data + ) external { IERC777(_erc777).send(to, amount, data); } @@ -45,7 +53,7 @@ contract ERC777SenderMock is IERC777TokensSender, ERC1820Client { * @param amount uint256 amount of tokens to transfer * @param data bytes extra information provided by the token holder (if any) */ - function burnTokens(uint amount, bytes data) external { + function burnTokens(uint amount, bytes calldata data) external { IERC777(_erc777).burn(amount, data); } @@ -71,8 +79,8 @@ contract ERC777SenderMock is IERC777TokensSender, ERC1820Client { address from, address to, uint256 amount, - bytes userData, - bytes operatorData + bytes calldata userData, + bytes calldata operatorData ) external { diff --git a/test/drafts/ERC777/ERC777.test.js b/test/drafts/ERC777/ERC777.test.js index 334129b07ef..c0fcc08537b 100644 --- a/test/drafts/ERC777/ERC777.test.js +++ b/test/drafts/ERC777/ERC777.test.js @@ -1,4 +1,4 @@ -const { assertRevert } = require('../../helpers/assertRevert'); +const { BN, constants, should, shouldFail } = require('openzeppelin-test-helpers'); const expectEvent = require('../../helpers/expectEvent'); const { ERC1820Deploy } = require('../../introspection/ERC1820Deploy'); @@ -7,11 +7,7 @@ const ERC1820 = artifacts.require('IERC1820'); const ERC777TokensRecipient = artifacts.require('ERC777ReceiverMock'); const ERC777TokensSender = artifacts.require('ERC777SenderMock'); -const BigNumber = web3.utils.BN; - -require('chai') - .use(require('chai-bignumber')(BigNumber)) - .should(); +const BigNumber = BN; contract('ERC777', function ([_, holder, operator, anotherAccount]) { const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; @@ -91,11 +87,11 @@ contract('ERC777', function ([_, holder, operator, anotherAccount]) { }); it('value is checked to be greater or equal to 1', async function () { - await assertRevert(ERC777.new('Test777', 'T77', 0, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA)); + await shouldFail.reverting(ERC777.new('Test777', 'T77', 0, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA)); }); it('initialSupply is a multiple of granularity', async function () { - await assertRevert(ERC777.new('Test777', 'T77', '7', [], '11', USER_DATA, OPERATOR_DATA)); + await shouldFail.reverting(ERC777.new('Test777', 'T77', '7', [], '11', USER_DATA, OPERATOR_DATA)); }); }); @@ -130,7 +126,7 @@ contract('ERC777', function ([_, holder, operator, anotherAccount]) { }); it('revert when token holder authorizes itself as operator', async function () { - await assertRevert(this.token.authorizeOperator(holder, { from: holder })); + await shouldFail.reverting(this.token.authorizeOperator(holder, { from: holder })); }); }); @@ -157,7 +153,7 @@ contract('ERC777', function ([_, holder, operator, anotherAccount]) { }); it('revert when token holder revoke itself as operator', async function () { - await assertRevert(this.token.revokeOperator(holder, { from: holder })); + await shouldFail.reverting(this.token.revokeOperator(holder, { from: holder })); }); }); }); @@ -255,7 +251,7 @@ contract('ERC777', function ([_, holder, operator, anotherAccount]) { it('revert when sending an amount of token from an account with insufficient balance', async function () { const amount = parseInt(INITIAL_SUPPLY, 10) + 100; const userData = '0xdeadbeef'; - await assertRevert( + await shouldFail.reverting( this.token.contract.methods.send(operator, amount.toString(), userData).send({ from: holder }) ); }); @@ -340,7 +336,9 @@ contract('ERC777', function ([_, holder, operator, anotherAccount]) { it('revert when sending an amount of token to address(0)', async function () { const userData = '0xdeadbeef'; - await assertRevert(this.token.contract.methods.send(ZERO_ADDRESS, '100', userData).send({ from: holder })); + await shouldFail.reverting( + this.token.contract.methods.send(ZERO_ADDRESS, '100', userData).send({ from: holder }) + ); }); it('revert when sending an amount which is not a multiple of granularity', async function () { @@ -348,7 +346,9 @@ contract('ERC777', function ([_, holder, operator, anotherAccount]) { const tempToken = await ERC777.new( 'Test777', 'T77', 10, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA, { from: holder } ); - await assertRevert(tempToken.contract.methods.send(anotherAccount, '15', userData).send({ from: holder })); + await shouldFail.reverting( + tempToken.contract.methods.send(anotherAccount, '15', userData).send({ from: holder }) + ); }); }); }); @@ -418,7 +418,7 @@ contract('ERC777', function ([_, holder, operator, anotherAccount]) { ); const userData = '0xdeadbeef'; const opData = '0xbabecafe'; - await assertRevert( + await shouldFail.reverting( tempToken.contract.methods.operatorSend( holder, anotherAccount, @@ -462,7 +462,7 @@ contract('ERC777', function ([_, holder, operator, anotherAccount]) { const userData = '0xdeadbeef'; const opData = '0xbabecafe'; - await assertRevert( + await shouldFail.reverting( this.token.contract.methods.operatorSend( holder, anotherAccount, @@ -508,7 +508,7 @@ contract('ERC777', function ([_, holder, operator, anotherAccount]) { it('revert when recipient is address(0)', async function () { const userData = '0xdeadbeef'; const opData = '0xbabecafe'; - await assertRevert( + await shouldFail.reverting( this.token.contract.methods.operatorSend( holder, ZERO_ADDRESS, @@ -532,7 +532,7 @@ contract('ERC777', function ([_, holder, operator, anotherAccount]) { OPERATOR_DATA, { from: holder } ); - await assertRevert( + await shouldFail.reverting( tempToken.contract.methods.operatorSend( holder, anotherAccount, @@ -688,7 +688,7 @@ contract('ERC777', function ([_, holder, operator, anotherAccount]) { it('revert when burning an amount of token from an account with insufficient balance', async function () { const amount = parseInt(INITIAL_SUPPLY, 10) + 100; - await assertRevert(this.token.contract.methods.burn(amount.toString(), userData).send({ from: holder })); + await shouldFail.reverting(this.token.contract.methods.burn(amount.toString(), userData).send({ from: holder })); }); describe('burning an amount of token from an account with sufficient balance', function () { @@ -762,7 +762,7 @@ contract('ERC777', function ([_, holder, operator, anotherAccount]) { OPERATOR_DATA, { from: holder } ); - await assertRevert(tempToken.contract.methods.burn('15', userData).send({ from: holder })); + await shouldFail.reverting(tempToken.contract.methods.burn('15', userData).send({ from: holder })); }); }); }); @@ -841,7 +841,7 @@ contract('ERC777', function ([_, holder, operator, anotherAccount]) { ); const opData = '0xbabecafe'; const userData = '0xdeadbeef'; - await assertRevert( + await shouldFail.reverting( tempToken.contract.methods.operatorBurn(holder, '100', userData, opData).send({ from: anotherAccount }) ); }); @@ -876,7 +876,7 @@ contract('ERC777', function ([_, holder, operator, anotherAccount]) { const amount = parseInt(INITIAL_SUPPLY, 10) + 100; const opData = '0xbabecafe'; const userData = '0xdeadbeef'; - await assertRevert( + await shouldFail.reverting( this.token.contract.methods.operatorBurn( holder, amount.toString(), @@ -934,7 +934,7 @@ contract('ERC777', function ([_, holder, operator, anotherAccount]) { OPERATOR_DATA, { from: holder } ); - await assertRevert( + await shouldFail.reverting( tempToken.contract.methods.operatorBurn(holder, '15', userData, opData).send({ from: operator }) ); }); diff --git a/test/helpers/expectEvent.js b/test/helpers/expectEvent.js index 5750157391e..3e8a29284d7 100644 --- a/test/helpers/expectEvent.js +++ b/test/helpers/expectEvent.js @@ -1,10 +1,8 @@ -const BigNumber = web3.utils.BN; -const should = require('chai') - .use(require('chai-bignumber')(BigNumber)) - .should(); +const { BN, should } = require('openzeppelin-test-helpers'); +const BigNumber = BN; function inEvents (events, eventName, eventArgs = {}) { - const _event = Object.values(events).find(function (e) { + const event = Object.values(events).find(function (e) { if (e.event === eventName) { for (const [k, v] of Object.entries(eventArgs)) { contains(e.returnValues, k, v); @@ -12,8 +10,8 @@ function inEvents (events, eventName, eventArgs = {}) { return true; } }); - should.exist(_event); - return _event; + should.exist(event); + return event; } function inLogs (logs, eventName, eventArgs = {}) { diff --git a/test/introspection/ERC1820Deploy.js b/test/introspection/ERC1820Deploy.js index 9482935b2ef..233b61806f7 100644 --- a/test/introspection/ERC1820Deploy.js +++ b/test/introspection/ERC1820Deploy.js @@ -1,4 +1,4 @@ -const { sendEther } = require('../helpers/sendTransaction'); +const { send } = require('openzeppelin-test-helpers'); const ERC1820Deploy = async function (owner) { const deployAccount = '0x5808bA8E60E0367C9067b328D75C1f3d29de58cf'; @@ -6,7 +6,7 @@ const ERC1820Deploy = async function (owner) { const deployTx = '0xf90a388085174876e800830c35008080b909e5608060405234801561001057600080fd5b506109c5806100206000396000f3fe608060405234801561001057600080fd5b50600436106100a5576000357c010000000000000000000000000000000000000000000000000000000090048063a41e7d5111610078578063a41e7d51146101d4578063aabbb8ca1461020a578063b705676514610236578063f712f3e814610280576100a5565b806329965a1d146100aa5780633d584063146100e25780635df8122f1461012457806365ba36c114610152575b600080fd5b6100e0600480360360608110156100c057600080fd5b50600160a060020a038135811691602081013591604090910135166102b6565b005b610108600480360360208110156100f857600080fd5b5035600160a060020a0316610570565b60408051600160a060020a039092168252519081900360200190f35b6100e06004803603604081101561013a57600080fd5b50600160a060020a03813581169160200135166105bc565b6101c26004803603602081101561016857600080fd5b81019060208101813564010000000081111561018357600080fd5b82018360208201111561019557600080fd5b803590602001918460018302840111640100000000831117156101b757600080fd5b5090925090506106b3565b60408051918252519081900360200190f35b6100e0600480360360408110156101ea57600080fd5b508035600160a060020a03169060200135600160e060020a0319166106ee565b6101086004803603604081101561022057600080fd5b50600160a060020a038135169060200135610778565b61026c6004803603604081101561024c57600080fd5b508035600160a060020a03169060200135600160e060020a0319166107ef565b604080519115158252519081900360200190f35b61026c6004803603604081101561029657600080fd5b508035600160a060020a03169060200135600160e060020a0319166108aa565b6000600160a060020a038416156102cd57836102cf565b335b9050336102db82610570565b600160a060020a031614610339576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b6103428361092a565b15610397576040805160e560020a62461bcd02815260206004820152601a60248201527f4d757374206e6f7420626520616e204552433136352068617368000000000000604482015290519081900360640190fd5b600160a060020a038216158015906103b85750600160a060020a0382163314155b156104ff5760405160200180807f455243313832305f4143434550545f4d4147494300000000000000000000000081525060140190506040516020818303038152906040528051906020012082600160a060020a031663249cb3fa85846040518363ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018083815260200182600160a060020a0316600160a060020a031681526020019250505060206040518083038186803b15801561047e57600080fd5b505afa158015610492573d6000803e3d6000fd5b505050506040513d60208110156104a857600080fd5b5051146104ff576040805160e560020a62461bcd02815260206004820181905260248201527f446f6573206e6f7420696d706c656d656e742074686520696e74657266616365604482015290519081900360640190fd5b600160a060020a03818116600081815260208181526040808320888452909152808220805473ffffffffffffffffffffffffffffffffffffffff19169487169485179055518692917f93baa6efbd2244243bfee6ce4cfdd1d04fc4c0e9a786abd3a41313bd352db15391a450505050565b600160a060020a03818116600090815260016020526040812054909116151561059a5750806105b7565b50600160a060020a03808216600090815260016020526040902054165b919050565b336105c683610570565b600160a060020a031614610624576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b81600160a060020a031681600160a060020a0316146106435780610646565b60005b600160a060020a03838116600081815260016020526040808220805473ffffffffffffffffffffffffffffffffffffffff19169585169590951790945592519184169290917f605c2dbf762e5f7d60a546d42e7205dcb1b011ebc62a61736a57c9089d3a43509190a35050565b600082826040516020018083838082843780830192505050925050506040516020818303038152906040528051906020012090505b92915050565b6106f882826107ef565b610703576000610705565b815b600160a060020a03928316600081815260208181526040808320600160e060020a031996909616808452958252808320805473ffffffffffffffffffffffffffffffffffffffff19169590971694909417909555908152600284528181209281529190925220805460ff19166001179055565b600080600160a060020a038416156107905783610792565b335b905061079d8361092a565b156107c357826107ad82826108aa565b6107b85760006107ba565b815b925050506106e8565b600160a060020a0390811660009081526020818152604080832086845290915290205416905092915050565b6000808061081d857f01ffc9a70000000000000000000000000000000000000000000000000000000061094c565b909250905081158061082d575080155b1561083d576000925050506106e8565b61084f85600160e060020a031961094c565b909250905081158061086057508015155b15610870576000925050506106e8565b61087a858561094c565b909250905060018214801561088f5750806001145b1561089f576001925050506106e8565b506000949350505050565b600160a060020a0382166000908152600260209081526040808320600160e060020a03198516845290915281205460ff1615156108f2576108eb83836107ef565b90506106e8565b50600160a060020a03808316600081815260208181526040808320600160e060020a0319871684529091529020549091161492915050565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff161590565b6040517f01ffc9a7000000000000000000000000000000000000000000000000000000008082526004820183905260009182919060208160248189617530fa90519096909550935050505056fea165627a7a723058207d33f0c34a1016c7fcf5f8547cd8c09a74f837ed2564550f647531f1128056ec00291ba01820182018201820182018201820182018201820182018201820182018201820a01820182018201820182018201820182018201820182018201820182018201820'; // send 0.08 ether to deployment account - sendEther(owner, deployAccount, web3.utils.toWei('0.08', 'ether')); + send.ether(owner, deployAccount, web3.utils.toWei('0.08', 'ether')); // create ERC1820 contract const address = (await web3.eth.sendSignedTransaction(deployTx)).contractAddress; return address; From 7f7d2960debf251de0f592a90244e7cf59f9e50f Mon Sep 17 00:00:00 2001 From: Bertrand Masius Date: Thu, 21 Mar 2019 06:45:38 +0100 Subject: [PATCH 15/64] ERC777 Fix travis CI errors (#1159) --- test/drafts/ERC777/ERC777.test.js | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/test/drafts/ERC777/ERC777.test.js b/test/drafts/ERC777/ERC777.test.js index c0fcc08537b..5598d6c7576 100644 --- a/test/drafts/ERC777/ERC777.test.js +++ b/test/drafts/ERC777/ERC777.test.js @@ -1,4 +1,4 @@ -const { BN, constants, should, shouldFail } = require('openzeppelin-test-helpers'); +const { shouldFail } = require('openzeppelin-test-helpers'); const expectEvent = require('../../helpers/expectEvent'); const { ERC1820Deploy } = require('../../introspection/ERC1820Deploy'); @@ -7,8 +7,6 @@ const ERC1820 = artifacts.require('IERC1820'); const ERC777TokensRecipient = artifacts.require('ERC777ReceiverMock'); const ERC777TokensSender = artifacts.require('ERC777SenderMock'); -const BigNumber = BN; - contract('ERC777', function ([_, holder, operator, anotherAccount]) { const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; const ERC1820_ADDRESS = '0x1820b744B33945482C17Dc37218C01D858EBc714'; @@ -16,14 +14,20 @@ contract('ERC777', function ([_, holder, operator, anotherAccount]) { const USER_DATA = '0xabcd'; const OPERATOR_DATA = '0x0a0b0c0d'; const GRANULARITY = '1'; - - before('Deploy ERC1820', async function () { - try { - this.ERC1820Registry = await ERC1820.at(ERC1820_ADDRESS); - } catch (error) { - const address = await ERC1820Deploy(holder); - this.ERC1820Registry = await ERC1820.at(address); - } + var ERC1820Registry; + + before('Deploy ERC1820', function (done) { + ERC1820.at(ERC1820_ADDRESS).then( + function(contract) { + ERC1820Registry = contract.address; + done(); + }, + async function(reject) { + const address = await ERC1820Deploy(holder); + ERC1820Registry = (await ERC1820.at(address)).address; + done(); + } + ); }); it('Minted event is emitted', async function () { @@ -51,7 +55,7 @@ contract('ERC777', function ([_, holder, operator, anotherAccount]) { describe('ERC1820 Registry', function () { it('hardcoded address in ERC777 contract is correct', async function () { const erc1820 = await this.token.getERC1820Registry(); - erc1820.should.be.equal(this.ERC1820Registry.address); + erc1820.should.be.equal(ERC1820Registry); }); }); From 990073fa5aeec2677b18ac8e23819df02a14271e Mon Sep 17 00:00:00 2001 From: Bertrand Masius Date: Thu, 21 Mar 2019 07:17:28 +0100 Subject: [PATCH 16/64] ERC777 Fix linter errors again... (#1159) --- contracts/drafts/ERC777/ERC777.sol | 3 ++- contracts/drafts/ERC777/ERC777Base.sol | 18 ++++++++------ contracts/drafts/ERC777/IERC777.sol | 34 +++++++++++++------------- contracts/introspection/IERC1820.sol | 23 ++++++++--------- contracts/mocks/ERC777SenderMock.sol | 1 + test/drafts/ERC777/ERC777.test.js | 7 +++--- 6 files changed, 47 insertions(+), 39 deletions(-) diff --git a/contracts/drafts/ERC777/ERC777.sol b/contracts/drafts/ERC777/ERC777.sol index 84580ce8d2c..672b596e924 100644 --- a/contracts/drafts/ERC777/ERC777.sol +++ b/contracts/drafts/ERC777/ERC777.sol @@ -29,12 +29,13 @@ contract ERC777 is ERC777Base { bytes memory data, bytes memory operatorData ) + public ERC777Base( name, symbol, granularity, defaultOperators - ) public { + ) { _mint( msg.sender, msg.sender, diff --git a/contracts/drafts/ERC777/ERC777Base.sol b/contracts/drafts/ERC777/ERC777Base.sol index d0c89b99cbf..8e47bcdbdff 100644 --- a/contracts/drafts/ERC777/ERC777Base.sol +++ b/contracts/drafts/ERC777/ERC777Base.sol @@ -29,8 +29,8 @@ contract ERC777Base is IERC777, ERC1820Client { address[] private _defaultOpsArray; - bytes32 constant sendHash = keccak256("ERC777TokensSender"); - bytes32 constant receivedHash = keccak256("ERC777TokensRecipient"); + bytes32 constant private SENDHASH = keccak256("ERC777TokensSender"); + bytes32 constant private RECEIVEDHASH = keccak256("ERC777TokensRecipient"); mapping(address => bool) private _defaultOps; mapping(address => mapping(address => bool)) private _revokedDefaultOps; @@ -203,7 +203,9 @@ contract ERC777Base is IERC777, ERC1820Client { require(msg.sender != operator); if (_defaultOps[operator]) { _reAuthorizeDefaultOperator(operator); - } else _authorizeOperator(operator); + } else { + _authorizeOperator(operator); + } } /** @@ -214,7 +216,9 @@ contract ERC777Base is IERC777, ERC1820Client { require(operator != msg.sender); if (_defaultOps[operator]) { _revokeDefaultOperator(operator); - } else _revokeOperator(operator); + } else { + _revokeOperator(operator); + } } /** @@ -435,7 +439,7 @@ contract ERC777Base is IERC777, ERC1820Client { ) private { - address implementer = getInterfaceImplementer(from, sendHash); + address implementer = getInterfaceImplementer(from, SENDHASH); if (implementer != address(0)) { IERC777TokensSender(implementer).tokensToSend( operator, @@ -470,9 +474,9 @@ contract ERC777Base is IERC777, ERC1820Client { private returns(bool) { - address implementer = getInterfaceImplementer(to, receivedHash); + address implementer = getInterfaceImplementer(to, RECEIVEDHASH); if (implementer == address(0)) { - return(! to.isContract()); + return(!to.isContract()); } IERC777TokensRecipient(implementer).tokensReceived( operator, diff --git a/contracts/drafts/ERC777/IERC777.sol b/contracts/drafts/ERC777/IERC777.sol index 4b6b99bfee3..a1ebd09b1d6 100644 --- a/contracts/drafts/ERC777/IERC777.sol +++ b/contracts/drafts/ERC777/IERC777.sol @@ -5,27 +5,10 @@ pragma solidity ^0.5.2; * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-777.md */ interface IERC777 { - function name() external view returns (string memory); - - function symbol() external view returns (string memory); - - function totalSupply() external view returns (uint256); - - function balanceOf(address owner) external view returns (uint256); - - function granularity() external view returns (uint256); - - function defaultOperators() external view returns (address[] memory); - function authorizeOperator(address operator) external; function revokeOperator(address operator) external; - function isOperatorFor( - address operator, - address tokenHolder - ) external view returns (bool); - function send(address to, uint256 amount, bytes calldata data) external; function operatorSend( @@ -45,6 +28,23 @@ interface IERC777 { bytes calldata operatorData ) external; + function name() external view returns (string memory); + + function symbol() external view returns (string memory); + + function totalSupply() external view returns (uint256); + + function balanceOf(address owner) external view returns (uint256); + + function granularity() external view returns (uint256); + + function defaultOperators() external view returns (address[] memory); + + function isOperatorFor( + address operator, + address tokenHolder + ) external view returns (bool); + event Sent( address indexed operator, address indexed from, diff --git a/contracts/introspection/IERC1820.sol b/contracts/introspection/IERC1820.sol index 1572e39206e..2e68a3e274d 100644 --- a/contracts/introspection/IERC1820.sol +++ b/contracts/introspection/IERC1820.sol @@ -11,29 +11,30 @@ interface IERC1820 { address _implementer ) external; - function getInterfaceImplementer( - address _addr, - bytes32 _interfaceHash - ) external view returns (address); - function setManager( address _addr, address _newManager ) external; - function getManager(address _addr) external view returns(address); - - function interfaceHash( - string calldata _interfaceName - ) external pure returns(bytes32); - function updateERC165Cache( address _contract, bytes4 _interfaceId ) external; + function getInterfaceImplementer( + address _addr, + bytes32 _interfaceHash + ) external view returns (address); + function implementsERC165Interface( address _contract, bytes4 _interfaceId ) external view returns (bool); + + function getManager(address _addr) external view returns(address); + + function interfaceHash( + string calldata _interfaceName + ) external pure returns(bytes32); + } diff --git a/contracts/mocks/ERC777SenderMock.sol b/contracts/mocks/ERC777SenderMock.sol index cd63393846f..b6316e54567 100644 --- a/contracts/mocks/ERC777SenderMock.sol +++ b/contracts/mocks/ERC777SenderMock.sol @@ -45,6 +45,7 @@ contract ERC777SenderMock is IERC777TokensSender, ERC1820Client { uint amount, bytes calldata data ) external { + // solhint-disable-next-line check-send-result IERC777(_erc777).send(to, amount, data); } diff --git a/test/drafts/ERC777/ERC777.test.js b/test/drafts/ERC777/ERC777.test.js index 5598d6c7576..fb82b444f2c 100644 --- a/test/drafts/ERC777/ERC777.test.js +++ b/test/drafts/ERC777/ERC777.test.js @@ -14,15 +14,16 @@ contract('ERC777', function ([_, holder, operator, anotherAccount]) { const USER_DATA = '0xabcd'; const OPERATOR_DATA = '0x0a0b0c0d'; const GRANULARITY = '1'; - var ERC1820Registry; + let ERC1820Registry; before('Deploy ERC1820', function (done) { + // eslint-disable-next-line promise/catch-or-return ERC1820.at(ERC1820_ADDRESS).then( - function(contract) { + function (contract) { ERC1820Registry = contract.address; done(); }, - async function(reject) { + async function (reject) { const address = await ERC1820Deploy(holder); ERC1820Registry = (await ERC1820.at(address)).address; done(); From 17930e5b162796fd7be725e6ce717553729d78a3 Mon Sep 17 00:00:00 2001 From: Bertrand Masius Date: Thu, 21 Mar 2019 20:56:21 +0100 Subject: [PATCH 17/64] ERC777 Fix unit test (#1159) --- test/drafts/ERC777/ERC777.test.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/drafts/ERC777/ERC777.test.js b/test/drafts/ERC777/ERC777.test.js index fb82b444f2c..b9051c163bb 100644 --- a/test/drafts/ERC777/ERC777.test.js +++ b/test/drafts/ERC777/ERC777.test.js @@ -24,9 +24,10 @@ contract('ERC777', function ([_, holder, operator, anotherAccount]) { done(); }, async function (reject) { - const address = await ERC1820Deploy(holder); - ERC1820Registry = (await ERC1820.at(address)).address; - done(); + ERC1820Deploy(holder).then(async function (address) { + ERC1820Registry = (await ERC1820.at(address)).address; + done(); + }).catch(done); } ); }); From 65257d51d77f42f66ad852c674aa43b7be519032 Mon Sep 17 00:00:00 2001 From: Bertrand Masius Date: Thu, 21 Mar 2019 21:09:57 +0100 Subject: [PATCH 18/64] ERC777 Fix unit test again (#1159) --- test/drafts/ERC777/ERC777.test.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/drafts/ERC777/ERC777.test.js b/test/drafts/ERC777/ERC777.test.js index b9051c163bb..644a03b7fb8 100644 --- a/test/drafts/ERC777/ERC777.test.js +++ b/test/drafts/ERC777/ERC777.test.js @@ -27,7 +27,10 @@ contract('ERC777', function ([_, holder, operator, anotherAccount]) { ERC1820Deploy(holder).then(async function (address) { ERC1820Registry = (await ERC1820.at(address)).address; done(); - }).catch(done); + }).catch(async function (address) { + ERC1820Registry = (await ERC1820.at(address)).address; + done(); + }); } ); }); From d98ef862e4a07bd5b950ceb48ca81a52be916438 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Tue, 26 Mar 2019 16:29:32 -0300 Subject: [PATCH 19/64] Remove extra newlines. --- contracts/drafts/ERC777/ERC777Base.sol | 144 ++++--------------------- 1 file changed, 21 insertions(+), 123 deletions(-) diff --git a/contracts/drafts/ERC777/ERC777Base.sol b/contracts/drafts/ERC777/ERC777Base.sol index 8e47bcdbdff..d0cb238618e 100644 --- a/contracts/drafts/ERC777/ERC777Base.sol +++ b/contracts/drafts/ERC777/ERC777Base.sol @@ -43,19 +43,18 @@ contract ERC777Base is IERC777, ERC1820Client { address[] memory defaultOperators ) internal { require(granularity > 0); + _name = name; _symbol = symbol; _granularity = granularity; _defaultOpsArray = defaultOperators; + for (uint i = 0; i < defaultOperators.length; i++) { _defaultOps[defaultOperators[i]] = true; } + // register interface - setInterfaceImplementer( - address(this), - keccak256("ERC777Token"), - address(this) - ); + setInterfaceImplementer(address(this), keccak256("ERC777Token"), address(this)); } /** @@ -64,19 +63,8 @@ contract ERC777Base is IERC777, ERC1820Client { * @param amount uint256 amount of tokens to transfer * @param data bytes information attached to the send, and intended for the recipient (to) */ - function send( - address to, - uint256 amount, - bytes calldata data - ) external { - _send( - msg.sender, - msg.sender, - to, - amount, - data, - "" - ); + function send(address to, uint256 amount, bytes calldata data) external { + _send(msg.sender, msg.sender, to, amount, data, ""); } /** @@ -97,14 +85,7 @@ contract ERC777Base is IERC777, ERC1820Client { external { address holder = from == address(0) ? msg.sender : from; - _send( - msg.sender, - holder, - to, - amount, - data, - operatorData - ); + _send(msg.sender, holder, to, amount, data, operatorData); } /** @@ -113,13 +94,7 @@ contract ERC777Base is IERC777, ERC1820Client { * @param data bytes extra information provided by the token holder */ function burn(uint256 amount, bytes calldata data) external { - _burn( - msg.sender, - msg.sender, - amount, - data, - "" - ); + _burn(msg.sender, msg.sender, amount, data, ""); } /** @@ -129,22 +104,9 @@ contract ERC777Base is IERC777, ERC1820Client { * @param data bytes extra information provided by the token holder * @param operatorData bytes extra information provided by the operator (if any) */ - function operatorBurn( - address from, - uint256 amount, - bytes calldata data, - bytes calldata operatorData - ) - external - { + function operatorBurn(address from, uint256 amount, bytes calldata data, bytes calldata operatorData) external { address holder = from == address(0) ? msg.sender : from; - _burn( - msg.sender, - holder, - amount, - data, - operatorData - ); + _burn(msg.sender, holder, amount, data, operatorData); } /** @@ -232,8 +194,7 @@ contract ERC777Base is IERC777, ERC1820Client { address operator, address tokenHolder ) public view returns (bool) { - return - operator == tokenHolder || + return operator == tokenHolder || _defaultOps[operator] && !_revokedDefaultOps[tokenHolder][operator] || _ops[tokenHolder][operator]; } @@ -258,27 +219,14 @@ contract ERC777Base is IERC777, ERC1820Client { require(from != address(0)); require(isOperatorFor(msg.sender, from)); - _callTokensToSend( - operator, - from, - address(0), - amount, - data, - operatorData - ); + _callTokensToSend(operator, from, address(0), amount, data, operatorData); // Update state variables _totalSupply = _totalSupply.sub(amount); _balances[from] = _balances[from].sub(amount); require((_balances[from] % _granularity) == 0); - emit Burned( - operator, - from, - amount, - data, - operatorData - ); + emit Burned(operator, from, amount, data, operatorData); } /** @@ -302,29 +250,14 @@ contract ERC777Base is IERC777, ERC1820Client { require(to != address(0)); // revert if 'to' is a contract not implementing tokensReceived() - require( - _callTokensReceived( - operator, - address(0), - to, - amount, - userData, - operatorData - ) - ); + require(_callTokensReceived(operator, address(0), to, amount, userData, operatorData)); // Update state variables _totalSupply = _totalSupply.add(amount); _balances[to] = _balances[to].add(amount); require((_balances[to] % _granularity) == 0); - emit Minted( - operator, - to, - amount, - userData, - operatorData - ); + emit Minted(operator, to, amount, userData, operatorData); } /** @@ -386,14 +319,7 @@ contract ERC777Base is IERC777, ERC1820Client { require(to != address(0)); require(isOperatorFor(msg.sender, from)); - _callTokensToSend( - operator, - from, - to, - amount, - userData, - operatorData - ); + _callTokensToSend(operator, from, to, amount, userData, operatorData); // Update state variables _balances[from] = _balances[from].sub(amount); @@ -401,23 +327,9 @@ contract ERC777Base is IERC777, ERC1820Client { require((_balances[from] % _granularity) == 0); require((_balances[to] % _granularity) == 0); - _callTokensReceived( - operator, - from, - to, - amount, - userData, - operatorData - ); - - emit Sent( - msg.sender, - from, - to, - amount, - userData, - operatorData - ); + _callTokensReceived(operator, from, to, amount, userData, operatorData); + + emit Sent(msg.sender, from, to, amount, userData, operatorData); } /** @@ -441,14 +353,7 @@ contract ERC777Base is IERC777, ERC1820Client { { address implementer = getInterfaceImplementer(from, SENDHASH); if (implementer != address(0)) { - IERC777TokensSender(implementer).tokensToSend( - operator, - from, - to, - amount, - userData, - operatorData - ); + IERC777TokensSender(implementer).tokensToSend(operator, from, to, amount, userData, operatorData); } } @@ -478,14 +383,7 @@ contract ERC777Base is IERC777, ERC1820Client { if (implementer == address(0)) { return(!to.isContract()); } - IERC777TokensRecipient(implementer).tokensReceived( - operator, - from, - to, - amount, - userData, - operatorData - ); + IERC777TokensRecipient(implementer).tokensReceived(operator, from, to, amount, userData, operatorData); return true; } } From 831b3670d974544ce82b10ea36948da8824bc333 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Tue, 26 Mar 2019 16:40:29 -0300 Subject: [PATCH 20/64] Rename ERC777Base to ERC777. --- contracts/drafts/ERC777/ERC777.sol | 403 +++++++++++++++++++-- contracts/drafts/ERC777/ERC777Base.sol | 389 -------------------- contracts/drafts/ERC777/ERC777Burnable.sol | 4 +- 3 files changed, 374 insertions(+), 422 deletions(-) delete mode 100644 contracts/drafts/ERC777/ERC777Base.sol diff --git a/contracts/drafts/ERC777/ERC777.sol b/contracts/drafts/ERC777/ERC777.sol index 672b596e924..c502f1e8e40 100644 --- a/contracts/drafts/ERC777/ERC777.sol +++ b/contracts/drafts/ERC777/ERC777.sol @@ -1,47 +1,388 @@ pragma solidity ^0.5.2; -import "./ERC777Base.sol"; - +import "./IERC777.sol"; +import "./IERC777TokensRecipient.sol"; +import "./IERC777TokensSender.sol"; +import "../../math/SafeMath.sol"; +import "../../utils/Address.sol"; +import "../../introspection/ERC1820Client.sol"; /** * @title ERC777 token implementation - * @notice mint an amount of tokens given to msg.sender - * @author Bertrand Masius + * @author etsvigun , Bertrand Masius * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-777.md */ -contract ERC777 is ERC777Base { - /* - * @dev constructor - * @param name name of the token - * @param symbol symbol of the token - * @param granularity granularity of token - * @param defaultOperators array of default operators address - * @param initialSupply amount of tokens given to msg.sender - * @param data bytes information attached to the send, and intended for the recipient (to) - * @param operatorData bytes extra information provided by the operator (if any) - */ +contract ERC777 is IERC777, ERC1820Client { + using SafeMath for uint256; + using Address for address; + + string private _name; + + string private _symbol; + + mapping(address => uint256) private _balances; + + uint256 private _totalSupply; + + uint256 private _granularity; + + address[] private _defaultOpsArray; + + bytes32 constant private SENDHASH = keccak256("ERC777TokensSender"); + bytes32 constant private RECEIVEDHASH = keccak256("ERC777TokensRecipient"); + + mapping(address => bool) private _defaultOps; + mapping(address => mapping(address => bool)) private _revokedDefaultOps; + mapping(address => mapping(address => bool)) private _ops; + constructor( string memory name, string memory symbol, uint256 granularity, - address[] memory defaultOperators, - uint256 initialSupply, + address[] memory defaultOperators + ) public { + require(granularity > 0); + + _name = name; + _symbol = symbol; + _granularity = granularity; + _defaultOpsArray = defaultOperators; + + for (uint i = 0; i < defaultOperators.length; i++) { + _defaultOps[defaultOperators[i]] = true; + } + + // register interface + setInterfaceImplementer(address(this), keccak256("ERC777Token"), address(this)); + } + + /** + * @dev Send the amount of tokens from the address msg.sender to the address to + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param data bytes information attached to the send, and intended for the recipient (to) + */ + function send(address to, uint256 amount, bytes calldata data) external { + _send(msg.sender, msg.sender, to, amount, data, ""); + } + + /** + * @dev Send the amount of tokens on behalf of the address from to the address to + * @param from address token holder address. Set to 0x0 to use msg.sender as token holder + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param data bytes information attached to the send, and intended for the recipient (to) + * @param operatorData bytes extra information provided by the operator (if any) + */ + function operatorSend( + address from, + address to, + uint256 amount, + bytes calldata data, + bytes calldata operatorData + ) + external + { + address holder = from == address(0) ? msg.sender : from; + _send(msg.sender, holder, to, amount, data, operatorData); + } + + /** + * @dev Burn the amount of tokens from the address msg.sender + * @param amount uint256 amount of tokens to transfer + * @param data bytes extra information provided by the token holder + */ + function burn(uint256 amount, bytes calldata data) external { + _burn(msg.sender, msg.sender, amount, data, ""); + } + + /** + * @dev Burn the amount of tokens on behalf of the address from + * @param from address token holder address. Set to 0x0 to use msg.sender as token holder + * @param amount uint256 amount of tokens to transfer + * @param data bytes extra information provided by the token holder + * @param operatorData bytes extra information provided by the operator (if any) + */ + function operatorBurn(address from, uint256 amount, bytes calldata data, bytes calldata operatorData) external { + address holder = from == address(0) ? msg.sender : from; + _burn(msg.sender, holder, amount, data, operatorData); + } + + /** + * @return the name of the token. + */ + function name() public view returns (string memory) { + return _name; + } + + /** + * @return the symbol of the token. + */ + function symbol() public view returns (string memory) { + return _symbol; + } + + /** + * @dev Total number of tokens in existence + */ + function totalSupply() public view returns (uint256) { + return _totalSupply; + } + + /** + * @dev Gets the balance of the specified address. + * @param tokenHolder The address to query the balance of. + * @return uint256 representing the amount owned by the specified address. + */ + function balanceOf(address tokenHolder) public view returns (uint256) { + return _balances[tokenHolder]; + } + + /** + * @dev Gets the token's granularity, + * i.e. the smallest number of tokens (in the basic unit) + * which may be minted, sent or burned at any time + * @return uint256 granularity + */ + function granularity() public view returns (uint256) { + return _granularity; + } + + /** + * @dev Get the list of default operators as defined by the token contract. + * @return address[] default operators + */ + function defaultOperators() public view returns (address[] memory) { + return _defaultOpsArray; + } + + /** + * @dev Authorize an operator for the sender + * @param operator address to be authorized as operator + */ + function authorizeOperator(address operator) public { + require(msg.sender != operator); + if (_defaultOps[operator]) { + _reAuthorizeDefaultOperator(operator); + } else { + _authorizeOperator(operator); + } + } + + /** + * @dev Revoke operator rights from one of the default operators + * @param operator address to revoke operator rights from + */ + function revokeOperator(address operator) public { + require(operator != msg.sender); + if (_defaultOps[operator]) { + _revokeDefaultOperator(operator); + } else { + _revokeOperator(operator); + } + } + + /** + * @dev Indicate whether an address + * is an operator of the tokenHolder address + * @param operator address which may be an operator of tokenHolder + * @param tokenHolder address of a token holder which may have the operator + * address as an operator. + */ + function isOperatorFor( + address operator, + address tokenHolder + ) public view returns (bool) { + return operator == tokenHolder || + _defaultOps[operator] && !_revokedDefaultOps[tokenHolder][operator] || + _ops[tokenHolder][operator]; + } + + /** + * @dev Burn tokens + * @param operator address operator requesting the operation + * @param from address token holder address + * @param amount uint256 amount of tokens to burn + * @param data bytes extra information provided by the token holder + * @param operatorData bytes extra information provided by the operator (if any) + */ + function _burn( + address operator, + address from, + uint256 amount, bytes memory data, bytes memory operatorData ) - public - ERC777Base( - name, - symbol, - granularity, - defaultOperators - ) { - _mint( - msg.sender, - msg.sender, - initialSupply, - data, - operatorData - ); + internal + { + require(from != address(0)); + require(isOperatorFor(msg.sender, from)); + + _callTokensToSend(operator, from, address(0), amount, data, operatorData); + + // Update state variables + _totalSupply = _totalSupply.sub(amount); + _balances[from] = _balances[from].sub(amount); + require((_balances[from] % _granularity) == 0); + + emit Burned(operator, from, amount, data, operatorData); + } + + /** + * @dev Mint tokens. Does not check authorization of operator + * @dev the caller may ckeck that operator is authorized before calling + * @param operator address operator requesting the operation + * @param to address token recipient address + * @param amount uint256 amount of tokens to mint + * @param userData bytes extra information defined by the token recipient (if any) + * @param operatorData bytes extra information provided by the operator (if any) + */ + function _mint( + address operator, + address to, + uint256 amount, + bytes memory userData, + bytes memory operatorData + ) + internal + { + require(to != address(0)); + + // revert if 'to' is a contract not implementing tokensReceived() + require(_callTokensReceived(operator, address(0), to, amount, userData, operatorData)); + + // Update state variables + _totalSupply = _totalSupply.add(amount); + _balances[to] = _balances[to].add(amount); + require((_balances[to] % _granularity) == 0); + + emit Minted(operator, to, amount, userData, operatorData); + } + + /** + * @dev Authorize an operator for the sender + * @param operator address to be authorized as operator + */ + function _authorizeOperator(address operator) private { + _ops[msg.sender][operator] = true; + emit AuthorizedOperator(operator, msg.sender); + } + + /** + * @dev Re-authorize a previously revoked default operator + * @param operator address to be re-authorized as operator + */ + function _reAuthorizeDefaultOperator(address operator) private { + delete _revokedDefaultOps[msg.sender][operator]; + emit AuthorizedOperator(operator, msg.sender); + } + + /** + * @dev Revoke operator rights from one of the default operators + * @param operator address to revoke operator rights from + */ + function _revokeDefaultOperator(address operator) private { + _revokedDefaultOps[msg.sender][operator] = true; + emit RevokedOperator(operator, msg.sender); + } + + /** + * @dev Revoke an operator for the sender + * @param operator address to revoke operator rights from + */ + function _revokeOperator(address operator) private { + delete _ops[msg.sender][operator]; + emit RevokedOperator(operator, msg.sender); + } + + /** + * @dev Send tokens + * @param operator address operator requesting the transfer + * @param from address token holder address + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param userData bytes extra information provided by the token holder (if any) + * @param operatorData bytes extra information provided by the operator (if any) + */ + function _send( + address operator, + address from, + address to, + uint256 amount, + bytes memory userData, + bytes memory operatorData + ) + private + { + require(from != address(0)); + require(to != address(0)); + require(isOperatorFor(msg.sender, from)); + + _callTokensToSend(operator, from, to, amount, userData, operatorData); + + // Update state variables + _balances[from] = _balances[from].sub(amount); + _balances[to] = _balances[to].add(amount); + require((_balances[from] % _granularity) == 0); + require((_balances[to] % _granularity) == 0); + + _callTokensReceived(operator, from, to, amount, userData, operatorData); + + emit Sent(msg.sender, from, to, amount, userData, operatorData); + } + + /** + * @dev Call from.tokensToSend() if the interface is registered + * @param operator address operator requesting the transfer + * @param from address token holder address + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param userData bytes extra information provided by the token holder (if any) + * @param operatorData bytes extra information provided by the operator (if any) + */ + function _callTokensToSend( + address operator, + address from, + address to, + uint256 amount, + bytes memory userData, + bytes memory operatorData + ) + private + { + address implementer = getInterfaceImplementer(from, SENDHASH); + if (implementer != address(0)) { + IERC777TokensSender(implementer).tokensToSend(operator, from, to, amount, userData, operatorData); + } + } + + /** + * @dev Call to.tokensReceived() if the interface is registered + * @param operator address operator requesting the transfer + * @param from address token holder address + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param userData bytes extra information provided by the token holder (if any) + * @param operatorData bytes extra information provided by the operator (if any) + * @return false if the recipient is a contract but tokensReceived() was not + * registered for the recipient + */ + function _callTokensReceived( + address operator, + address from, + address to, + uint256 amount, + bytes memory userData, + bytes memory operatorData + ) + private + returns(bool) + { + address implementer = getInterfaceImplementer(to, RECEIVEDHASH); + if (implementer == address(0)) { + return(!to.isContract()); + } + IERC777TokensRecipient(implementer).tokensReceived(operator, from, to, amount, userData, operatorData); + return true; } } diff --git a/contracts/drafts/ERC777/ERC777Base.sol b/contracts/drafts/ERC777/ERC777Base.sol deleted file mode 100644 index d0cb238618e..00000000000 --- a/contracts/drafts/ERC777/ERC777Base.sol +++ /dev/null @@ -1,389 +0,0 @@ -pragma solidity ^0.5.2; - -import "./IERC777.sol"; -import "./IERC777TokensRecipient.sol"; -import "./IERC777TokensSender.sol"; -import "../../math/SafeMath.sol"; -import "../../utils/Address.sol"; -import "../../introspection/ERC1820Client.sol"; - -/** - * @title ERC777 token implementation to inherit from - * @author etsvigun , Bertrand Masius - * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-777.md - * @dev inherit from this contract, do not use directly - */ -contract ERC777Base is IERC777, ERC1820Client { - using SafeMath for uint256; - using Address for address; - - string private _name; - - string private _symbol; - - mapping(address => uint256) private _balances; - - uint256 private _totalSupply; - - uint256 private _granularity; - - address[] private _defaultOpsArray; - - bytes32 constant private SENDHASH = keccak256("ERC777TokensSender"); - bytes32 constant private RECEIVEDHASH = keccak256("ERC777TokensRecipient"); - - mapping(address => bool) private _defaultOps; - mapping(address => mapping(address => bool)) private _revokedDefaultOps; - mapping(address => mapping(address => bool)) private _ops; - - constructor( - string memory name, - string memory symbol, - uint256 granularity, - address[] memory defaultOperators - ) internal { - require(granularity > 0); - - _name = name; - _symbol = symbol; - _granularity = granularity; - _defaultOpsArray = defaultOperators; - - for (uint i = 0; i < defaultOperators.length; i++) { - _defaultOps[defaultOperators[i]] = true; - } - - // register interface - setInterfaceImplementer(address(this), keccak256("ERC777Token"), address(this)); - } - - /** - * @dev Send the amount of tokens from the address msg.sender to the address to - * @param to address recipient address - * @param amount uint256 amount of tokens to transfer - * @param data bytes information attached to the send, and intended for the recipient (to) - */ - function send(address to, uint256 amount, bytes calldata data) external { - _send(msg.sender, msg.sender, to, amount, data, ""); - } - - /** - * @dev Send the amount of tokens on behalf of the address from to the address to - * @param from address token holder address. Set to 0x0 to use msg.sender as token holder - * @param to address recipient address - * @param amount uint256 amount of tokens to transfer - * @param data bytes information attached to the send, and intended for the recipient (to) - * @param operatorData bytes extra information provided by the operator (if any) - */ - function operatorSend( - address from, - address to, - uint256 amount, - bytes calldata data, - bytes calldata operatorData - ) - external - { - address holder = from == address(0) ? msg.sender : from; - _send(msg.sender, holder, to, amount, data, operatorData); - } - - /** - * @dev Burn the amount of tokens from the address msg.sender - * @param amount uint256 amount of tokens to transfer - * @param data bytes extra information provided by the token holder - */ - function burn(uint256 amount, bytes calldata data) external { - _burn(msg.sender, msg.sender, amount, data, ""); - } - - /** - * @dev Burn the amount of tokens on behalf of the address from - * @param from address token holder address. Set to 0x0 to use msg.sender as token holder - * @param amount uint256 amount of tokens to transfer - * @param data bytes extra information provided by the token holder - * @param operatorData bytes extra information provided by the operator (if any) - */ - function operatorBurn(address from, uint256 amount, bytes calldata data, bytes calldata operatorData) external { - address holder = from == address(0) ? msg.sender : from; - _burn(msg.sender, holder, amount, data, operatorData); - } - - /** - * @return the name of the token. - */ - function name() public view returns (string memory) { - return _name; - } - - /** - * @return the symbol of the token. - */ - function symbol() public view returns (string memory) { - return _symbol; - } - - /** - * @dev Total number of tokens in existence - */ - function totalSupply() public view returns (uint256) { - return _totalSupply; - } - - /** - * @dev Gets the balance of the specified address. - * @param tokenHolder The address to query the balance of. - * @return uint256 representing the amount owned by the specified address. - */ - function balanceOf(address tokenHolder) public view returns (uint256) { - return _balances[tokenHolder]; - } - - /** - * @dev Gets the token's granularity, - * i.e. the smallest number of tokens (in the basic unit) - * which may be minted, sent or burned at any time - * @return uint256 granularity - */ - function granularity() public view returns (uint256) { - return _granularity; - } - - /** - * @dev Get the list of default operators as defined by the token contract. - * @return address[] default operators - */ - function defaultOperators() public view returns (address[] memory) { - return _defaultOpsArray; - } - - /** - * @dev Authorize an operator for the sender - * @param operator address to be authorized as operator - */ - function authorizeOperator(address operator) public { - require(msg.sender != operator); - if (_defaultOps[operator]) { - _reAuthorizeDefaultOperator(operator); - } else { - _authorizeOperator(operator); - } - } - - /** - * @dev Revoke operator rights from one of the default operators - * @param operator address to revoke operator rights from - */ - function revokeOperator(address operator) public { - require(operator != msg.sender); - if (_defaultOps[operator]) { - _revokeDefaultOperator(operator); - } else { - _revokeOperator(operator); - } - } - - /** - * @dev Indicate whether an address - * is an operator of the tokenHolder address - * @param operator address which may be an operator of tokenHolder - * @param tokenHolder address of a token holder which may have the operator - * address as an operator. - */ - function isOperatorFor( - address operator, - address tokenHolder - ) public view returns (bool) { - return operator == tokenHolder || - _defaultOps[operator] && !_revokedDefaultOps[tokenHolder][operator] || - _ops[tokenHolder][operator]; - } - - /** - * @dev Burn tokens - * @param operator address operator requesting the operation - * @param from address token holder address - * @param amount uint256 amount of tokens to burn - * @param data bytes extra information provided by the token holder - * @param operatorData bytes extra information provided by the operator (if any) - */ - function _burn( - address operator, - address from, - uint256 amount, - bytes memory data, - bytes memory operatorData - ) - internal - { - require(from != address(0)); - require(isOperatorFor(msg.sender, from)); - - _callTokensToSend(operator, from, address(0), amount, data, operatorData); - - // Update state variables - _totalSupply = _totalSupply.sub(amount); - _balances[from] = _balances[from].sub(amount); - require((_balances[from] % _granularity) == 0); - - emit Burned(operator, from, amount, data, operatorData); - } - - /** - * @dev Mint tokens. Does not check authorization of operator - * @dev the caller may ckeck that operator is authorized before calling - * @param operator address operator requesting the operation - * @param to address token recipient address - * @param amount uint256 amount of tokens to mint - * @param userData bytes extra information defined by the token recipient (if any) - * @param operatorData bytes extra information provided by the operator (if any) - */ - function _mint( - address operator, - address to, - uint256 amount, - bytes memory userData, - bytes memory operatorData - ) - internal - { - require(to != address(0)); - - // revert if 'to' is a contract not implementing tokensReceived() - require(_callTokensReceived(operator, address(0), to, amount, userData, operatorData)); - - // Update state variables - _totalSupply = _totalSupply.add(amount); - _balances[to] = _balances[to].add(amount); - require((_balances[to] % _granularity) == 0); - - emit Minted(operator, to, amount, userData, operatorData); - } - - /** - * @dev Authorize an operator for the sender - * @param operator address to be authorized as operator - */ - function _authorizeOperator(address operator) private { - _ops[msg.sender][operator] = true; - emit AuthorizedOperator(operator, msg.sender); - } - - /** - * @dev Re-authorize a previously revoked default operator - * @param operator address to be re-authorized as operator - */ - function _reAuthorizeDefaultOperator(address operator) private { - delete _revokedDefaultOps[msg.sender][operator]; - emit AuthorizedOperator(operator, msg.sender); - } - - /** - * @dev Revoke operator rights from one of the default operators - * @param operator address to revoke operator rights from - */ - function _revokeDefaultOperator(address operator) private { - _revokedDefaultOps[msg.sender][operator] = true; - emit RevokedOperator(operator, msg.sender); - } - - /** - * @dev Revoke an operator for the sender - * @param operator address to revoke operator rights from - */ - function _revokeOperator(address operator) private { - delete _ops[msg.sender][operator]; - emit RevokedOperator(operator, msg.sender); - } - - /** - * @dev Send tokens - * @param operator address operator requesting the transfer - * @param from address token holder address - * @param to address recipient address - * @param amount uint256 amount of tokens to transfer - * @param userData bytes extra information provided by the token holder (if any) - * @param operatorData bytes extra information provided by the operator (if any) - */ - function _send( - address operator, - address from, - address to, - uint256 amount, - bytes memory userData, - bytes memory operatorData - ) - private - { - require(from != address(0)); - require(to != address(0)); - require(isOperatorFor(msg.sender, from)); - - _callTokensToSend(operator, from, to, amount, userData, operatorData); - - // Update state variables - _balances[from] = _balances[from].sub(amount); - _balances[to] = _balances[to].add(amount); - require((_balances[from] % _granularity) == 0); - require((_balances[to] % _granularity) == 0); - - _callTokensReceived(operator, from, to, amount, userData, operatorData); - - emit Sent(msg.sender, from, to, amount, userData, operatorData); - } - - /** - * @dev Call from.tokensToSend() if the interface is registered - * @param operator address operator requesting the transfer - * @param from address token holder address - * @param to address recipient address - * @param amount uint256 amount of tokens to transfer - * @param userData bytes extra information provided by the token holder (if any) - * @param operatorData bytes extra information provided by the operator (if any) - */ - function _callTokensToSend( - address operator, - address from, - address to, - uint256 amount, - bytes memory userData, - bytes memory operatorData - ) - private - { - address implementer = getInterfaceImplementer(from, SENDHASH); - if (implementer != address(0)) { - IERC777TokensSender(implementer).tokensToSend(operator, from, to, amount, userData, operatorData); - } - } - - /** - * @dev Call to.tokensReceived() if the interface is registered - * @param operator address operator requesting the transfer - * @param from address token holder address - * @param to address recipient address - * @param amount uint256 amount of tokens to transfer - * @param userData bytes extra information provided by the token holder (if any) - * @param operatorData bytes extra information provided by the operator (if any) - * @return false if the recipient is a contract but tokensReceived() was not - * registered for the recipient - */ - function _callTokensReceived( - address operator, - address from, - address to, - uint256 amount, - bytes memory userData, - bytes memory operatorData - ) - private - returns(bool) - { - address implementer = getInterfaceImplementer(to, RECEIVEDHASH); - if (implementer == address(0)) { - return(!to.isContract()); - } - IERC777TokensRecipient(implementer).tokensReceived(operator, from, to, amount, userData, operatorData); - return true; - } -} diff --git a/contracts/drafts/ERC777/ERC777Burnable.sol b/contracts/drafts/ERC777/ERC777Burnable.sol index 2aeb883b9b2..80ecaf594aa 100644 --- a/contracts/drafts/ERC777/ERC777Burnable.sol +++ b/contracts/drafts/ERC777/ERC777Burnable.sol @@ -1,6 +1,6 @@ pragma solidity ^0.5.2; -import "./ERC777Base.sol"; +import "./ERC777.sol"; /** @@ -8,7 +8,7 @@ import "./ERC777Base.sol"; * @author Bertrand Masius * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-777.md */ -contract ERC777Burnable is ERC777Base { +contract ERC777Burnable is ERC777 { /** * @dev Burn the amount of tokens from the address msg.sender From f1df62d8a9fdcf6c993deaf6f8e73667c132fe25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Tue, 26 Mar 2019 16:45:18 -0300 Subject: [PATCH 21/64] Remove 'Token' from contract names. --- contracts/drafts/ERC777/ERC777.sol | 8 ++++---- .../{IERC777TokensRecipient.sol => IERC777Recipient.sol} | 2 +- .../ERC777/{IERC777TokensSender.sol => IERC777Sender.sol} | 2 +- contracts/mocks/ERC777ReceiverMock.sol | 4 ++-- contracts/mocks/ERC777SenderMock.sol | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) rename contracts/drafts/ERC777/{IERC777TokensRecipient.sol => IERC777Recipient.sol} (92%) rename contracts/drafts/ERC777/{IERC777TokensSender.sol => IERC777Sender.sol} (93%) diff --git a/contracts/drafts/ERC777/ERC777.sol b/contracts/drafts/ERC777/ERC777.sol index c502f1e8e40..1054cdda36d 100644 --- a/contracts/drafts/ERC777/ERC777.sol +++ b/contracts/drafts/ERC777/ERC777.sol @@ -1,8 +1,8 @@ pragma solidity ^0.5.2; import "./IERC777.sol"; -import "./IERC777TokensRecipient.sol"; -import "./IERC777TokensSender.sol"; +import "./IERC777Recipient.sol"; +import "./IERC777Sender.sol"; import "../../math/SafeMath.sol"; import "../../utils/Address.sol"; import "../../introspection/ERC1820Client.sol"; @@ -352,7 +352,7 @@ contract ERC777 is IERC777, ERC1820Client { { address implementer = getInterfaceImplementer(from, SENDHASH); if (implementer != address(0)) { - IERC777TokensSender(implementer).tokensToSend(operator, from, to, amount, userData, operatorData); + IERC777Sender(implementer).tokensToSend(operator, from, to, amount, userData, operatorData); } } @@ -382,7 +382,7 @@ contract ERC777 is IERC777, ERC1820Client { if (implementer == address(0)) { return(!to.isContract()); } - IERC777TokensRecipient(implementer).tokensReceived(operator, from, to, amount, userData, operatorData); + IERC777Recipient(implementer).tokensReceived(operator, from, to, amount, userData, operatorData); return true; } } diff --git a/contracts/drafts/ERC777/IERC777TokensRecipient.sol b/contracts/drafts/ERC777/IERC777Recipient.sol similarity index 92% rename from contracts/drafts/ERC777/IERC777TokensRecipient.sol rename to contracts/drafts/ERC777/IERC777Recipient.sol index c44fc53f04d..81313dfa99e 100644 --- a/contracts/drafts/ERC777/IERC777TokensRecipient.sol +++ b/contracts/drafts/ERC777/IERC777Recipient.sol @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ pragma solidity ^0.5.2; -interface IERC777TokensRecipient { +interface IERC777Recipient { function tokensReceived( address operator, address from, diff --git a/contracts/drafts/ERC777/IERC777TokensSender.sol b/contracts/drafts/ERC777/IERC777Sender.sol similarity index 93% rename from contracts/drafts/ERC777/IERC777TokensSender.sol rename to contracts/drafts/ERC777/IERC777Sender.sol index 73b2e79a8f0..6b9dcbdd752 100644 --- a/contracts/drafts/ERC777/IERC777TokensSender.sol +++ b/contracts/drafts/ERC777/IERC777Sender.sol @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ pragma solidity ^0.5.2; -interface IERC777TokensSender { +interface IERC777Sender { function tokensToSend( address operator, address from, diff --git a/contracts/mocks/ERC777ReceiverMock.sol b/contracts/mocks/ERC777ReceiverMock.sol index a0f6b9f4d44..60db9991bec 100644 --- a/contracts/mocks/ERC777ReceiverMock.sol +++ b/contracts/mocks/ERC777ReceiverMock.sol @@ -1,6 +1,6 @@ pragma solidity ^0.5.2; -import "../drafts/ERC777/IERC777TokensRecipient.sol"; +import "../drafts/ERC777/IERC777Recipient.sol"; import "../introspection/ERC1820Client.sol"; /** @@ -8,7 +8,7 @@ import "../introspection/ERC1820Client.sol"; * @author Bertrand Masius * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-777.md */ -contract ERC777ReceiverMock is IERC777TokensRecipient, ERC1820Client { +contract ERC777ReceiverMock is IERC777Recipient, ERC1820Client { event TokensReceived( address indexed operator, diff --git a/contracts/mocks/ERC777SenderMock.sol b/contracts/mocks/ERC777SenderMock.sol index b6316e54567..3eee21098ae 100644 --- a/contracts/mocks/ERC777SenderMock.sol +++ b/contracts/mocks/ERC777SenderMock.sol @@ -1,7 +1,7 @@ pragma solidity ^0.5.2; import "../drafts/ERC777/IERC777.sol"; -import "../drafts/ERC777/IERC777TokensSender.sol"; +import "../drafts/ERC777/IERC777Sender.sol"; import "../introspection/ERC1820Client.sol"; /** @@ -9,7 +9,7 @@ import "../introspection/ERC1820Client.sol"; * @author Bertrand Masius * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-777.md */ -contract ERC777SenderMock is IERC777TokensSender, ERC1820Client { +contract ERC777SenderMock is IERC777Sender, ERC1820Client { address private _erc777; From 00df2b60c78be266d2f5ca8044d93e99a40c6934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Tue, 26 Mar 2019 16:52:22 -0300 Subject: [PATCH 22/64] Replace ops for operators. --- contracts/drafts/ERC777/ERC777.sol | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/contracts/drafts/ERC777/ERC777.sol b/contracts/drafts/ERC777/ERC777.sol index 1054cdda36d..e125ec64cb3 100644 --- a/contracts/drafts/ERC777/ERC777.sol +++ b/contracts/drafts/ERC777/ERC777.sol @@ -26,14 +26,14 @@ contract ERC777 is IERC777, ERC1820Client { uint256 private _granularity; - address[] private _defaultOpsArray; + address[] private _defaultOperatorsArray; bytes32 constant private SENDHASH = keccak256("ERC777TokensSender"); bytes32 constant private RECEIVEDHASH = keccak256("ERC777TokensRecipient"); - mapping(address => bool) private _defaultOps; - mapping(address => mapping(address => bool)) private _revokedDefaultOps; - mapping(address => mapping(address => bool)) private _ops; + mapping(address => bool) private _defaultOperators; + mapping(address => mapping(address => bool)) private _revokedDefaultOperators; + mapping(address => mapping(address => bool)) private _operators; constructor( string memory name, @@ -46,10 +46,10 @@ contract ERC777 is IERC777, ERC1820Client { _name = name; _symbol = symbol; _granularity = granularity; - _defaultOpsArray = defaultOperators; + _defaultOperatorsArray = defaultOperators; for (uint i = 0; i < defaultOperators.length; i++) { - _defaultOps[defaultOperators[i]] = true; + _defaultOperators[defaultOperators[i]] = true; } // register interface @@ -153,7 +153,7 @@ contract ERC777 is IERC777, ERC1820Client { * @return address[] default operators */ function defaultOperators() public view returns (address[] memory) { - return _defaultOpsArray; + return _defaultOperatorsArray; } /** @@ -162,7 +162,7 @@ contract ERC777 is IERC777, ERC1820Client { */ function authorizeOperator(address operator) public { require(msg.sender != operator); - if (_defaultOps[operator]) { + if (_defaultOperators[operator]) { _reAuthorizeDefaultOperator(operator); } else { _authorizeOperator(operator); @@ -175,7 +175,7 @@ contract ERC777 is IERC777, ERC1820Client { */ function revokeOperator(address operator) public { require(operator != msg.sender); - if (_defaultOps[operator]) { + if (_defaultOperators[operator]) { _revokeDefaultOperator(operator); } else { _revokeOperator(operator); @@ -194,8 +194,8 @@ contract ERC777 is IERC777, ERC1820Client { address tokenHolder ) public view returns (bool) { return operator == tokenHolder || - _defaultOps[operator] && !_revokedDefaultOps[tokenHolder][operator] || - _ops[tokenHolder][operator]; + _defaultOperators[operator] && !_revokedDefaultOperators[tokenHolder][operator] || + _operators[tokenHolder][operator]; } /** @@ -264,7 +264,7 @@ contract ERC777 is IERC777, ERC1820Client { * @param operator address to be authorized as operator */ function _authorizeOperator(address operator) private { - _ops[msg.sender][operator] = true; + _operators[msg.sender][operator] = true; emit AuthorizedOperator(operator, msg.sender); } @@ -273,7 +273,7 @@ contract ERC777 is IERC777, ERC1820Client { * @param operator address to be re-authorized as operator */ function _reAuthorizeDefaultOperator(address operator) private { - delete _revokedDefaultOps[msg.sender][operator]; + delete _revokedDefaultOperators[msg.sender][operator]; emit AuthorizedOperator(operator, msg.sender); } @@ -282,7 +282,7 @@ contract ERC777 is IERC777, ERC1820Client { * @param operator address to revoke operator rights from */ function _revokeDefaultOperator(address operator) private { - _revokedDefaultOps[msg.sender][operator] = true; + _revokedDefaultOperators[msg.sender][operator] = true; emit RevokedOperator(operator, msg.sender); } @@ -291,7 +291,7 @@ contract ERC777 is IERC777, ERC1820Client { * @param operator address to revoke operator rights from */ function _revokeOperator(address operator) private { - delete _ops[msg.sender][operator]; + delete _operators[msg.sender][operator]; emit RevokedOperator(operator, msg.sender); } From 5a0195a76498c052bc7ce4909ed2fae29d0a7636 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Tue, 26 Mar 2019 16:56:07 -0300 Subject: [PATCH 23/64] Move operator check out of _send. --- contracts/drafts/ERC777/ERC777.sol | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/contracts/drafts/ERC777/ERC777.sol b/contracts/drafts/ERC777/ERC777.sol index e125ec64cb3..e2bc0cb68e9 100644 --- a/contracts/drafts/ERC777/ERC777.sol +++ b/contracts/drafts/ERC777/ERC777.sol @@ -83,7 +83,14 @@ contract ERC777 is IERC777, ERC1820Client { ) external { - address holder = from == address(0) ? msg.sender : from; + address holder; + if (from == address(0)) { + holder = msg.sender; + } else { + holder = from; + require(isOperatorFor(msg.sender, holder)); + } + _send(msg.sender, holder, to, amount, data, operatorData); } @@ -316,7 +323,6 @@ contract ERC777 is IERC777, ERC1820Client { { require(from != address(0)); require(to != address(0)); - require(isOperatorFor(msg.sender, from)); _callTokensToSend(operator, from, to, amount, userData, operatorData); @@ -328,7 +334,7 @@ contract ERC777 is IERC777, ERC1820Client { _callTokensReceived(operator, from, to, amount, userData, operatorData); - emit Sent(msg.sender, from, to, amount, userData, operatorData); + emit Sent(operator, from, to, amount, userData, operatorData); } /** From 06fd3a9c60439a1ec73dcb33e05105dc27078223 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Tue, 26 Mar 2019 17:50:00 -0300 Subject: [PATCH 24/64] Remove ERC777Burnable. --- contracts/drafts/ERC777/ERC777Burnable.sol | 50 ---------------------- 1 file changed, 50 deletions(-) delete mode 100644 contracts/drafts/ERC777/ERC777Burnable.sol diff --git a/contracts/drafts/ERC777/ERC777Burnable.sol b/contracts/drafts/ERC777/ERC777Burnable.sol deleted file mode 100644 index 80ecaf594aa..00000000000 --- a/contracts/drafts/ERC777/ERC777Burnable.sol +++ /dev/null @@ -1,50 +0,0 @@ -pragma solidity ^0.5.2; - -import "./ERC777.sol"; - - -/** - * @title ERC777 burnable token implementation - * @author Bertrand Masius - * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-777.md - */ -contract ERC777Burnable is ERC777 { - - /** - * @dev Burn the amount of tokens from the address msg.sender - * @param amount uint256 amount of tokens to transfer - * @param data bytes data provided by the token holder - */ - function burn(uint256 amount, bytes calldata data) external { - _burn( - msg.sender, - msg.sender, - amount, - data, - "" - ); - } - - /** - * @dev Burn the amount of tokens on behalf of the address from - * @param from address token holder address. Set to 0x0 to use msg.sender as token holder - * @param amount uint256 amount of tokens to transfer - * @param data bytes data provided by the token holder - * @param operatorData bytes extra information provided by the operator (if any) - */ - function operatorBurn( - address from, - uint256 amount, - bytes calldata data, - bytes calldata operatorData - ) external { - address holder = from == address(0) ? msg.sender : from; - _burn( - msg.sender, - holder, - amount, - data, - operatorData - ); - } -} From 4528200499c80543d89f5413219cef9f08578c30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Tue, 26 Mar 2019 18:35:14 -0300 Subject: [PATCH 25/64] Remove ERC1820Client, now using the interface directly. --- contracts/drafts/ERC777/ERC777.sol | 12 +++--- contracts/introspection/ERC1820Client.sol | 48 ----------------------- contracts/introspection/IERC1820.sol | 40 ------------------- contracts/mocks/ERC777ReceiverMock.sol | 8 ++-- contracts/mocks/ERC777SenderMock.sol | 17 ++++---- 5 files changed, 21 insertions(+), 104 deletions(-) delete mode 100644 contracts/introspection/ERC1820Client.sol delete mode 100644 contracts/introspection/IERC1820.sol diff --git a/contracts/drafts/ERC777/ERC777.sol b/contracts/drafts/ERC777/ERC777.sol index e2bc0cb68e9..84f220dd99a 100644 --- a/contracts/drafts/ERC777/ERC777.sol +++ b/contracts/drafts/ERC777/ERC777.sol @@ -5,17 +5,19 @@ import "./IERC777Recipient.sol"; import "./IERC777Sender.sol"; import "../../math/SafeMath.sol"; import "../../utils/Address.sol"; -import "../../introspection/ERC1820Client.sol"; +import "../IERC1820Registry.sol"; /** * @title ERC777 token implementation * @author etsvigun , Bertrand Masius * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-777.md */ -contract ERC777 is IERC777, ERC1820Client { +contract ERC777 is IERC777 { using SafeMath for uint256; using Address for address; + IERC1820Registry private _erc1820 = IERC1820Registry(0x1820b744B33945482C17Dc37218C01D858EBc714); + string private _name; string private _symbol; @@ -53,7 +55,7 @@ contract ERC777 is IERC777, ERC1820Client { } // register interface - setInterfaceImplementer(address(this), keccak256("ERC777Token"), address(this)); + _erc1820.setInterfaceImplementer(address(this), keccak256("ERC777Token"), address(this)); } /** @@ -356,7 +358,7 @@ contract ERC777 is IERC777, ERC1820Client { ) private { - address implementer = getInterfaceImplementer(from, SENDHASH); + address implementer = _erc1820.getInterfaceImplementer(from, SENDHASH); if (implementer != address(0)) { IERC777Sender(implementer).tokensToSend(operator, from, to, amount, userData, operatorData); } @@ -384,7 +386,7 @@ contract ERC777 is IERC777, ERC1820Client { private returns(bool) { - address implementer = getInterfaceImplementer(to, RECEIVEDHASH); + address implementer = _erc1820.getInterfaceImplementer(to, RECEIVEDHASH); if (implementer == address(0)) { return(!to.isContract()); } diff --git a/contracts/introspection/ERC1820Client.sol b/contracts/introspection/ERC1820Client.sol deleted file mode 100644 index 1c9084195fe..00000000000 --- a/contracts/introspection/ERC1820Client.sol +++ /dev/null @@ -1,48 +0,0 @@ -pragma solidity ^0.5.2; - -import "./IERC1820.sol"; - -/** - * @title ERC1820 client implementation - * @dev https://eips.ethereum.org/EIPS/eip-1820 - * @author Bertrand Masius - */ -contract ERC1820Client { - - IERC1820 private _erc1820 = IERC1820( - 0x1820b744B33945482C17Dc37218C01D858EBc714 - ); - - function getERC1820Registry() external view returns(address) { - return address(_erc1820); - } - - function getInterfaceImplementer( - address addr, - bytes32 hash - ) internal view returns(address) { - return _erc1820.getInterfaceImplementer(addr, hash); - } - - function setInterfaceImplementer( - address addr, - bytes32 hash, - address implementer - ) internal { - _erc1820.setInterfaceImplementer(addr, hash, implementer); - } - - function updateERC165Cache( - address _contract, - bytes4 _interfaceId - ) internal { - _erc1820.updateERC165Cache(_contract, _interfaceId); - } - - function implementsERC165Interface( - address _contract, - bytes4 _interfaceId - ) internal view returns (bool) { - return _erc1820.implementsERC165Interface(_contract, _interfaceId); - } -} diff --git a/contracts/introspection/IERC1820.sol b/contracts/introspection/IERC1820.sol deleted file mode 100644 index 2e68a3e274d..00000000000 --- a/contracts/introspection/IERC1820.sol +++ /dev/null @@ -1,40 +0,0 @@ -pragma solidity ^0.5.2; - -/** - * @title IERC1820 - * @dev https://eips.ethereum.org/EIPS/eip-1820 - */ -interface IERC1820 { - function setInterfaceImplementer( - address _addr, - bytes32 _interfaceHash, - address _implementer - ) external; - - function setManager( - address _addr, - address _newManager - ) external; - - function updateERC165Cache( - address _contract, - bytes4 _interfaceId - ) external; - - function getInterfaceImplementer( - address _addr, - bytes32 _interfaceHash - ) external view returns (address); - - function implementsERC165Interface( - address _contract, - bytes4 _interfaceId - ) external view returns (bool); - - function getManager(address _addr) external view returns(address); - - function interfaceHash( - string calldata _interfaceName - ) external pure returns(bytes32); - -} diff --git a/contracts/mocks/ERC777ReceiverMock.sol b/contracts/mocks/ERC777ReceiverMock.sol index 60db9991bec..7ee852969d1 100644 --- a/contracts/mocks/ERC777ReceiverMock.sol +++ b/contracts/mocks/ERC777ReceiverMock.sol @@ -1,14 +1,16 @@ pragma solidity ^0.5.2; import "../drafts/ERC777/IERC777Recipient.sol"; -import "../introspection/ERC1820Client.sol"; +import "../drafts/IERC1820Registry.sol"; /** * @title ERC777TokensRecipientMock a contract that implements tokensReceived() hook * @author Bertrand Masius * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-777.md */ -contract ERC777ReceiverMock is IERC777Recipient, ERC1820Client { +contract ERC777ReceiverMock is IERC777Recipient { + + IERC1820Registry private _erc1820 = IERC1820Registry(0x1820b744B33945482C17Dc37218C01D858EBc714); event TokensReceived( address indexed operator, @@ -22,7 +24,7 @@ contract ERC777ReceiverMock is IERC777Recipient, ERC1820Client { constructor(bool setInterface) public { // register interface if (setInterface) { - setInterfaceImplementer( + _erc1820.setInterfaceImplementer( address(this), keccak256("ERC777TokensRecipient"), address(this) diff --git a/contracts/mocks/ERC777SenderMock.sol b/contracts/mocks/ERC777SenderMock.sol index 3eee21098ae..1ac564d4a8d 100644 --- a/contracts/mocks/ERC777SenderMock.sol +++ b/contracts/mocks/ERC777SenderMock.sol @@ -2,16 +2,17 @@ pragma solidity ^0.5.2; import "../drafts/ERC777/IERC777.sol"; import "../drafts/ERC777/IERC777Sender.sol"; -import "../introspection/ERC1820Client.sol"; +import "../drafts/IERC1820Registry.sol"; /** * @title ERC777TokensSenderMock a contract that implements tokensToSend() hook * @author Bertrand Masius * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-777.md */ -contract ERC777SenderMock is IERC777Sender, ERC1820Client { +contract ERC777SenderMock is IERC777Sender { - address private _erc777; + IERC1820Registry private _erc1820 = IERC1820Registry(0x1820b744B33945482C17Dc37218C01D858EBc714); + IERC777 private _erc777; event TokensToSend( address indexed operator, @@ -22,11 +23,11 @@ contract ERC777SenderMock is IERC777Sender, ERC1820Client { bytes operatorData ); - constructor(bool setInterface, address erc777) public { + constructor(bool setInterface, IERC777 erc777) public { _erc777 = erc777; // register interface if (setInterface) { - setInterfaceImplementer( + _erc1820.setInterfaceImplementer( address(this), keccak256("ERC777TokensSender"), address(this) @@ -46,7 +47,7 @@ contract ERC777SenderMock is IERC777Sender, ERC1820Client { bytes calldata data ) external { // solhint-disable-next-line check-send-result - IERC777(_erc777).send(to, amount, data); + _erc777.send(to, amount, data); } /** @@ -55,7 +56,7 @@ contract ERC777SenderMock is IERC777Sender, ERC1820Client { * @param data bytes extra information provided by the token holder (if any) */ function burnTokens(uint amount, bytes calldata data) external { - IERC777(_erc777).burn(amount, data); + _erc777.burn(amount, data); } /** @@ -63,7 +64,7 @@ contract ERC777SenderMock is IERC777Sender, ERC1820Client { * @param operator address of operator */ function authorizeOperator(address operator) external { - IERC777(_erc777).authorizeOperator(operator); + _erc777.authorizeOperator(operator); } /** From 9d44f7cd7c4253acecbb80ba8f7f0432810751d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Tue, 26 Mar 2019 19:25:55 -0300 Subject: [PATCH 26/64] Minor internal refactors in contracts. --- contracts/drafts/ERC777/ERC777.sol | 36 ++++++++++++-------- contracts/drafts/ERC777/IERC777.sol | 35 ++++--------------- contracts/drafts/ERC777/IERC777Recipient.sol | 7 ++-- contracts/drafts/ERC777/IERC777Sender.sol | 7 ++-- 4 files changed, 36 insertions(+), 49 deletions(-) diff --git a/contracts/drafts/ERC777/ERC777.sol b/contracts/drafts/ERC777/ERC777.sol index 84f220dd99a..7047b279bf3 100644 --- a/contracts/drafts/ERC777/ERC777.sol +++ b/contracts/drafts/ERC777/ERC777.sol @@ -10,7 +10,6 @@ import "../IERC1820Registry.sol"; /** * @title ERC777 token implementation * @author etsvigun , Bertrand Masius - * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-777.md */ contract ERC777 is IERC777 { using SafeMath for uint256; @@ -28,14 +27,18 @@ contract ERC777 is IERC777 { uint256 private _granularity; - address[] private _defaultOperatorsArray; + bytes32 constant private TOKENS_SENDER_INTEFACE_HASH = keccak256("ERC777TokensSender"); + bytes32 constant private TOKENS_RECIPIENT_INTERFACE_HASH = keccak256("ERC777TokensRecipient"); - bytes32 constant private SENDHASH = keccak256("ERC777TokensSender"); - bytes32 constant private RECEIVEDHASH = keccak256("ERC777TokensRecipient"); + // This isn't ever read from - it's only used to respond to the defaultOperators query. + address[] private _defaultOperatorsArray; + // Immutable, but accounts may revoke them (tracked in __revokedDefaultOperators). mapping(address => bool) private _defaultOperators; - mapping(address => mapping(address => bool)) private _revokedDefaultOperators; + + // For each account, a mapping of its operators and revoked default operators. mapping(address => mapping(address => bool)) private _operators; + mapping(address => mapping(address => bool)) private _revokedDefaultOperators; constructor( string memory name, @@ -48,10 +51,10 @@ contract ERC777 is IERC777 { _name = name; _symbol = symbol; _granularity = granularity; - _defaultOperatorsArray = defaultOperators; - for (uint i = 0; i < defaultOperators.length; i++) { - _defaultOperators[defaultOperators[i]] = true; + _defaultOperatorsArray = defaultOperators; + for (uint256 i = 0; i < _defaultOperatorsArray.length; i++) { + _defaultOperators[_defaultOperatorsArray[i]] = true; } // register interface @@ -102,7 +105,7 @@ contract ERC777 is IERC777 { * @param data bytes extra information provided by the token holder */ function burn(uint256 amount, bytes calldata data) external { - _burn(msg.sender, msg.sender, amount, data, ""); + _burn(msg.sender, msg.sender, amount, data, ""); } /** @@ -226,13 +229,14 @@ contract ERC777 is IERC777 { { require(from != address(0)); require(isOperatorFor(msg.sender, from)); + require((amount % _granularity) == 0); _callTokensToSend(operator, from, address(0), amount, data, operatorData); // Update state variables _totalSupply = _totalSupply.sub(amount); _balances[from] = _balances[from].sub(amount); - require((_balances[from] % _granularity) == 0); + assert((_balances[from] % _granularity) == 0); emit Burned(operator, from, amount, data, operatorData); } @@ -256,6 +260,7 @@ contract ERC777 is IERC777 { internal { require(to != address(0)); + require((amount % _granularity) == 0); // revert if 'to' is a contract not implementing tokensReceived() require(_callTokensReceived(operator, address(0), to, amount, userData, operatorData)); @@ -263,7 +268,7 @@ contract ERC777 is IERC777 { // Update state variables _totalSupply = _totalSupply.add(amount); _balances[to] = _balances[to].add(amount); - require((_balances[to] % _granularity) == 0); + assert((_balances[to] % _granularity) == 0); emit Minted(operator, to, amount, userData, operatorData); } @@ -325,14 +330,15 @@ contract ERC777 is IERC777 { { require(from != address(0)); require(to != address(0)); + require((amount % _granularity) == 0); _callTokensToSend(operator, from, to, amount, userData, operatorData); // Update state variables _balances[from] = _balances[from].sub(amount); _balances[to] = _balances[to].add(amount); - require((_balances[from] % _granularity) == 0); - require((_balances[to] % _granularity) == 0); + assert((_balances[from] % _granularity) == 0); + assert((_balances[to] % _granularity) == 0); _callTokensReceived(operator, from, to, amount, userData, operatorData); @@ -358,7 +364,7 @@ contract ERC777 is IERC777 { ) private { - address implementer = _erc1820.getInterfaceImplementer(from, SENDHASH); + address implementer = _erc1820.getInterfaceImplementer(from, TOKENS_SENDER_INTEFACE_HASH); if (implementer != address(0)) { IERC777Sender(implementer).tokensToSend(operator, from, to, amount, userData, operatorData); } @@ -386,7 +392,7 @@ contract ERC777 is IERC777 { private returns(bool) { - address implementer = _erc1820.getInterfaceImplementer(to, RECEIVEDHASH); + address implementer = _erc1820.getInterfaceImplementer(to, TOKENS_RECIPIENT_INTERFACE_HASH); if (implementer == address(0)) { return(!to.isContract()); } diff --git a/contracts/drafts/ERC777/IERC777.sol b/contracts/drafts/ERC777/IERC777.sol index a1ebd09b1d6..4da72fb1e1c 100644 --- a/contracts/drafts/ERC777/IERC777.sol +++ b/contracts/drafts/ERC777/IERC777.sol @@ -1,8 +1,8 @@ pragma solidity ^0.5.2; /** - * @title ERC777 interface - * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-777.md + * @title ERC777 token interface + * @dev See https://eips.ethereum.org/EIPS/eip-777 */ interface IERC777 { function authorizeOperator(address operator) external; @@ -40,10 +40,7 @@ interface IERC777 { function defaultOperators() external view returns (address[] memory); - function isOperatorFor( - address operator, - address tokenHolder - ) external view returns (bool); + function isOperatorFor(address operator, address tokenHolder) external view returns (bool); event Sent( address indexed operator, @@ -54,29 +51,11 @@ interface IERC777 { bytes operatorData ); - event Minted( - address indexed operator, - address indexed to, - uint256 amount, - bytes data, - bytes operatorData - ); + event Minted(address indexed operator, address indexed to, uint256 amount, bytes data, bytes operatorData); - event Burned( - address indexed operator, - address indexed from, - uint256 amount, - bytes data, - bytes operatorData - ); + event Burned(address indexed operator, address indexed from, uint256 amount, bytes data, bytes operatorData); - event AuthorizedOperator( - address indexed operator, - address indexed tokenHolder - ); + event AuthorizedOperator(address indexed operator, address indexed tokenHolder); - event RevokedOperator( - address indexed operator, - address indexed tokenHolder - ); + event RevokedOperator(address indexed operator, address indexed tokenHolder); } diff --git a/contracts/drafts/ERC777/IERC777Recipient.sol b/contracts/drafts/ERC777/IERC777Recipient.sol index 81313dfa99e..c5be87057d2 100644 --- a/contracts/drafts/ERC777/IERC777Recipient.sol +++ b/contracts/drafts/ERC777/IERC777Recipient.sol @@ -1,8 +1,9 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ pragma solidity ^0.5.2; +/** + * @title ERC777 token recipient interface + * @dev See https://eips.ethereum.org/EIPS/eip-777 + */ interface IERC777Recipient { function tokensReceived( address operator, diff --git a/contracts/drafts/ERC777/IERC777Sender.sol b/contracts/drafts/ERC777/IERC777Sender.sol index 6b9dcbdd752..084b530e863 100644 --- a/contracts/drafts/ERC777/IERC777Sender.sol +++ b/contracts/drafts/ERC777/IERC777Sender.sol @@ -1,8 +1,9 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ pragma solidity ^0.5.2; +/** + * @title ERC777 token sender interface + * @dev See https://eips.ethereum.org/EIPS/eip-777 + */ interface IERC777Sender { function tokensToSend( address operator, From 4d383d41c63d6668de31a1f7b0529b754cb8dd03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Tue, 26 Mar 2019 19:27:13 -0300 Subject: [PATCH 27/64] Delete extra test helpers. --- test/helpers/expectEvent.js | 55 ----------------------------- test/introspection/ERC1820Deploy.js | 17 --------- 2 files changed, 72 deletions(-) delete mode 100644 test/helpers/expectEvent.js delete mode 100644 test/introspection/ERC1820Deploy.js diff --git a/test/helpers/expectEvent.js b/test/helpers/expectEvent.js deleted file mode 100644 index 3e8a29284d7..00000000000 --- a/test/helpers/expectEvent.js +++ /dev/null @@ -1,55 +0,0 @@ -const { BN, should } = require('openzeppelin-test-helpers'); -const BigNumber = BN; - -function inEvents (events, eventName, eventArgs = {}) { - const event = Object.values(events).find(function (e) { - if (e.event === eventName) { - for (const [k, v] of Object.entries(eventArgs)) { - contains(e.returnValues, k, v); - } - return true; - } - }); - should.exist(event); - return event; -} - -function inLogs (logs, eventName, eventArgs = {}) { - const event = logs.find(function (e) { - if (e.event === eventName) { - for (const [k, v] of Object.entries(eventArgs)) { - contains(e.args, k, v); - } - return true; - } - }); - should.exist(event); - return event; -} - -async function inTransaction (tx, eventName, eventArgs = {}) { - const { logs } = await tx; - return inLogs(logs, eventName, eventArgs); -} - -function contains (args, key, value) { - if (args[key] == null) { - value.should.be.equal('0x00'); - } else if (isBigNumber(args[key])) { - args[key].toString().should.be.equal(value); - } else { - args[key].should.be.equal(value); - } -} - -function isBigNumber (object) { - return object.isBigNumber || - object instanceof BigNumber || - (object.constructor && object.constructor.name === 'BigNumber'); -} - -module.exports = { - inEvents, - inLogs, - inTransaction, -}; diff --git a/test/introspection/ERC1820Deploy.js b/test/introspection/ERC1820Deploy.js deleted file mode 100644 index 233b61806f7..00000000000 --- a/test/introspection/ERC1820Deploy.js +++ /dev/null @@ -1,17 +0,0 @@ -const { send } = require('openzeppelin-test-helpers'); - -const ERC1820Deploy = async function (owner) { - const deployAccount = '0x5808bA8E60E0367C9067b328D75C1f3d29de58cf'; - // eslint-disable-next-line max-len - const deployTx = '0xf90a388085174876e800830c35008080b909e5608060405234801561001057600080fd5b506109c5806100206000396000f3fe608060405234801561001057600080fd5b50600436106100a5576000357c010000000000000000000000000000000000000000000000000000000090048063a41e7d5111610078578063a41e7d51146101d4578063aabbb8ca1461020a578063b705676514610236578063f712f3e814610280576100a5565b806329965a1d146100aa5780633d584063146100e25780635df8122f1461012457806365ba36c114610152575b600080fd5b6100e0600480360360608110156100c057600080fd5b50600160a060020a038135811691602081013591604090910135166102b6565b005b610108600480360360208110156100f857600080fd5b5035600160a060020a0316610570565b60408051600160a060020a039092168252519081900360200190f35b6100e06004803603604081101561013a57600080fd5b50600160a060020a03813581169160200135166105bc565b6101c26004803603602081101561016857600080fd5b81019060208101813564010000000081111561018357600080fd5b82018360208201111561019557600080fd5b803590602001918460018302840111640100000000831117156101b757600080fd5b5090925090506106b3565b60408051918252519081900360200190f35b6100e0600480360360408110156101ea57600080fd5b508035600160a060020a03169060200135600160e060020a0319166106ee565b6101086004803603604081101561022057600080fd5b50600160a060020a038135169060200135610778565b61026c6004803603604081101561024c57600080fd5b508035600160a060020a03169060200135600160e060020a0319166107ef565b604080519115158252519081900360200190f35b61026c6004803603604081101561029657600080fd5b508035600160a060020a03169060200135600160e060020a0319166108aa565b6000600160a060020a038416156102cd57836102cf565b335b9050336102db82610570565b600160a060020a031614610339576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b6103428361092a565b15610397576040805160e560020a62461bcd02815260206004820152601a60248201527f4d757374206e6f7420626520616e204552433136352068617368000000000000604482015290519081900360640190fd5b600160a060020a038216158015906103b85750600160a060020a0382163314155b156104ff5760405160200180807f455243313832305f4143434550545f4d4147494300000000000000000000000081525060140190506040516020818303038152906040528051906020012082600160a060020a031663249cb3fa85846040518363ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018083815260200182600160a060020a0316600160a060020a031681526020019250505060206040518083038186803b15801561047e57600080fd5b505afa158015610492573d6000803e3d6000fd5b505050506040513d60208110156104a857600080fd5b5051146104ff576040805160e560020a62461bcd02815260206004820181905260248201527f446f6573206e6f7420696d706c656d656e742074686520696e74657266616365604482015290519081900360640190fd5b600160a060020a03818116600081815260208181526040808320888452909152808220805473ffffffffffffffffffffffffffffffffffffffff19169487169485179055518692917f93baa6efbd2244243bfee6ce4cfdd1d04fc4c0e9a786abd3a41313bd352db15391a450505050565b600160a060020a03818116600090815260016020526040812054909116151561059a5750806105b7565b50600160a060020a03808216600090815260016020526040902054165b919050565b336105c683610570565b600160a060020a031614610624576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b81600160a060020a031681600160a060020a0316146106435780610646565b60005b600160a060020a03838116600081815260016020526040808220805473ffffffffffffffffffffffffffffffffffffffff19169585169590951790945592519184169290917f605c2dbf762e5f7d60a546d42e7205dcb1b011ebc62a61736a57c9089d3a43509190a35050565b600082826040516020018083838082843780830192505050925050506040516020818303038152906040528051906020012090505b92915050565b6106f882826107ef565b610703576000610705565b815b600160a060020a03928316600081815260208181526040808320600160e060020a031996909616808452958252808320805473ffffffffffffffffffffffffffffffffffffffff19169590971694909417909555908152600284528181209281529190925220805460ff19166001179055565b600080600160a060020a038416156107905783610792565b335b905061079d8361092a565b156107c357826107ad82826108aa565b6107b85760006107ba565b815b925050506106e8565b600160a060020a0390811660009081526020818152604080832086845290915290205416905092915050565b6000808061081d857f01ffc9a70000000000000000000000000000000000000000000000000000000061094c565b909250905081158061082d575080155b1561083d576000925050506106e8565b61084f85600160e060020a031961094c565b909250905081158061086057508015155b15610870576000925050506106e8565b61087a858561094c565b909250905060018214801561088f5750806001145b1561089f576001925050506106e8565b506000949350505050565b600160a060020a0382166000908152600260209081526040808320600160e060020a03198516845290915281205460ff1615156108f2576108eb83836107ef565b90506106e8565b50600160a060020a03808316600081815260208181526040808320600160e060020a0319871684529091529020549091161492915050565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff161590565b6040517f01ffc9a7000000000000000000000000000000000000000000000000000000008082526004820183905260009182919060208160248189617530fa90519096909550935050505056fea165627a7a723058207d33f0c34a1016c7fcf5f8547cd8c09a74f837ed2564550f647531f1128056ec00291ba01820182018201820182018201820182018201820182018201820182018201820a01820182018201820182018201820182018201820182018201820182018201820'; - - // send 0.08 ether to deployment account - send.ether(owner, deployAccount, web3.utils.toWei('0.08', 'ether')); - // create ERC1820 contract - const address = (await web3.eth.sendSignedTransaction(deployTx)).contractAddress; - return address; -}; - -module.exports = { - ERC1820Deploy, -}; From dc91c59248928025ca50f269178f9ce42d595c2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Wed, 27 Mar 2019 03:47:16 -0300 Subject: [PATCH 28/64] Simplified tests. --- test/drafts/ERC777/ERC777.test.js | 1021 +---------------------------- 1 file changed, 24 insertions(+), 997 deletions(-) diff --git a/test/drafts/ERC777/ERC777.test.js b/test/drafts/ERC777/ERC777.test.js index 644a03b7fb8..34cf5114b62 100644 --- a/test/drafts/ERC777/ERC777.test.js +++ b/test/drafts/ERC777/ERC777.test.js @@ -1,1020 +1,47 @@ -const { shouldFail } = require('openzeppelin-test-helpers'); -const expectEvent = require('../../helpers/expectEvent'); -const { ERC1820Deploy } = require('../../introspection/ERC1820Deploy'); +const { BN, constants, shouldFail, singletons } = require('openzeppelin-test-helpers'); const ERC777 = artifacts.require('ERC777'); -const ERC1820 = artifacts.require('IERC1820'); -const ERC777TokensRecipient = artifacts.require('ERC777ReceiverMock'); -const ERC777TokensSender = artifacts.require('ERC777SenderMock'); -contract('ERC777', function ([_, holder, operator, anotherAccount]) { - const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; - const ERC1820_ADDRESS = '0x1820b744B33945482C17Dc37218C01D858EBc714'; - const INITIAL_SUPPLY = '10000'; - const USER_DATA = '0xabcd'; - const OPERATOR_DATA = '0x0a0b0c0d'; - const GRANULARITY = '1'; - let ERC1820Registry; +contract.only('ERC777', function ([_, registryFunder, initialHolder, defaultOperatorA, defaultOperatorB, operator, anyone]) { + const initialSupply = new BN('10000'); + const name = 'ERC777Test'; + const symbol = '777T'; - before('Deploy ERC1820', function (done) { - // eslint-disable-next-line promise/catch-or-return - ERC1820.at(ERC1820_ADDRESS).then( - function (contract) { - ERC1820Registry = contract.address; - done(); - }, - async function (reject) { - ERC1820Deploy(holder).then(async function (address) { - ERC1820Registry = (await ERC1820.at(address)).address; - done(); - }).catch(async function (address) { - ERC1820Registry = (await ERC1820.at(address)).address; - done(); - }); - } - ); + before(async function () { + this.erc1820 = await singletons.ERC1820Registry(registryFunder); }); - it('Minted event is emitted', async function () { - // use web3 deployment to get the receipt - const web3Contract = new web3.eth.Contract(ERC777.abi); - web3Contract.options.data = ERC777.binary; - const tx = web3Contract.deploy({ - arguments: ['Test777', 'T77', GRANULARITY, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA], - }); - - const instance = await tx - .send({ from: holder, gas: '6000000', data: tx }) - .on('receipt', receipt => { - expectEvent.inEvents(receipt.events, 'Minted', { - operator: holder, - to: holder, - amount: INITIAL_SUPPLY, - data: USER_DATA, - operatorData: OPERATOR_DATA, - }); - }); - this.token = await ERC777.at(instance.options.address); - }); - - describe('ERC1820 Registry', function () { - it('hardcoded address in ERC777 contract is correct', async function () { - const erc1820 = await this.token.getERC1820Registry(); - erc1820.should.be.equal(ERC1820Registry); - }); + it('reverts with a granularity of zero', async function () { + await shouldFail.reverting(ERC777.new(name, symbol, 0, [])); }); - describe('total supply', function () { - it('returns the total amount of tokens', async function () { - (await this.token.totalSupply()).toString().should.be.equal(INITIAL_SUPPLY); + context('with default operators', function () { + beforeEach(async function () { + this.token = await ERC777.new(name, symbol, 1, [defaultOperatorA, defaultOperatorB]); }); - }); - describe('balanceOf', function () { - describe('when the requested account has no tokens', function () { - it('returns zero', async function () { - (await this.token.balanceOf(anotherAccount)).toString().should.be.equal('0'); + describe('basic information', function () { + it('returns the name', async function () { + (await this.token.name()).should.equal(name); }); - }); - describe('when the requested account has some tokens', function () { - it('returns the total amount of tokens', async function () { - (await this.token.balanceOf(holder)).toString().should.be.equal(INITIAL_SUPPLY); + it('returns the symbol', async function () { + (await this.token.symbol()).should.equal(symbol); }); - }); - }); - - describe('granularity', function () { - it('returns granularity amount of the token', async function () { - (await this.token.granularity()).toString().should.be.equal(GRANULARITY); - }); - - it('value is set at creation time', async function () { - const tempToken = await ERC777.new('Test777', 'T77', 10, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA); - const granularity = await tempToken.granularity(); - granularity.toString().should.be.equal('10'); - }); - - it('value is checked to be greater or equal to 1', async function () { - await shouldFail.reverting(ERC777.new('Test777', 'T77', 0, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA)); - }); - - it('initialSupply is a multiple of granularity', async function () { - await shouldFail.reverting(ERC777.new('Test777', 'T77', '7', [], '11', USER_DATA, OPERATOR_DATA)); - }); - }); - - describe('non-default operator', async function () { - before('Deploy ERC777 with no default operator', async function () { - this.token = await ERC777.new('Test777', 'T77', 1, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA); - }); - - it('holder is an operator for itself', function () { - assert(this.token.contract.methods.isOperatorFor(holder, holder)); - }); - describe('authorize operator', function () { - it('AuthorizedOperator event is emitted', async function () { - const { logs } = await this.token.authorizeOperator(anotherAccount, { from: holder }); - expectEvent.inLogs(logs, 'AuthorizedOperator', { - operator: anotherAccount, - tokenHolder: holder, - }); + it('returns the granularity', async function () { + (await this.token.granularity()).should.be.bignumber.equal('1'); }); - it('operator is authorized', function () { - assert(this.token.contract.methods.isOperatorFor(anotherAccount, holder)); - }); - - it('AuthorizedOperator event is emitted even if operator is already authorized', async function () { - const { logs } = await this.token.authorizeOperator(anotherAccount, { from: holder }); - expectEvent.inLogs(logs, 'AuthorizedOperator', { - operator: anotherAccount, - tokenHolder: holder, - }); - }); - - it('revert when token holder authorizes itself as operator', async function () { - await shouldFail.reverting(this.token.authorizeOperator(holder, { from: holder })); - }); - }); - - describe('revoke operator', function () { - it('RevokedOperator event is emitted', async function () { - const { logs } = await this.token.revokeOperator(anotherAccount, { from: holder }); - expectEvent.inLogs(logs, 'RevokedOperator', { - operator: anotherAccount, - tokenHolder: holder, - }); - }); - - it('operator is revoked', async function () { - const iopf = await this.token.contract.methods.isOperatorFor(anotherAccount, holder).call(); - assert(!iopf); - }); - - it('RevokedOperator event is emitted even if operator is already revoked', async function () { - const { logs } = await this.token.revokeOperator(anotherAccount, { from: holder }); - expectEvent.inLogs(logs, 'RevokedOperator', { - operator: anotherAccount, - tokenHolder: holder, - }); - }); - - it('revert when token holder revoke itself as operator', async function () { - await shouldFail.reverting(this.token.revokeOperator(holder, { from: holder })); + it('is registered in the registry', async function () { + (await this.erc1820.getInterfaceImplementer(this.token.address, )).should.equal(this.token.address); }); }); }); - describe('default operator', async function () { - before('Deploy ERC777 with one default operator', async function () { - this.token = await ERC777.new('Test777', 'T77', 1, [operator], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA); - }); - - it('returns empty array when no default operator has been declared', async function () { - const tempToken = await ERC777.new('Test777', 'T77', 1, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA); - // eslint-disable-next-line no-unused-expressions - (await tempToken.defaultOperators()).should.be.an('array').that.is.empty; - }); - - it('array of operators is set at creation time', async function () { - const tempToken = await ERC777.new( - 'Test777', 'T77', 1, [operator, anotherAccount], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA - ); - const defaultOps = await tempToken.defaultOperators(); - defaultOps.should.be.an('array').that.has.all.members([operator, anotherAccount]); + context('with no default operators', function () { + beforeEach(async function () { + await shouldFail.reverting(ERC777.new(name, symbol, 1, [])); }); - - it('operator is an authorized operator for any holder', function () { - assert(this.token.contract.methods.isOperatorFor(operator, holder)); - }); - - describe('revoke operator', function () { - it('RevokedOperator event is emitted', async function () { - const { logs } = await this.token.revokeOperator(operator, { from: holder }); - expectEvent.inLogs(logs, 'RevokedOperator', { - operator: operator, - tokenHolder: holder, - }); - }); - - it('operator is revoked', async function () { - const iopf = await this.token.contract.methods.isOperatorFor(operator, holder).call(); - assert(!iopf); - }); - - it('RevokedOperator event is emitted even if operator is already revoked', async function () { - const { logs } = await this.token.revokeOperator(operator, { from: holder }); - expectEvent.inLogs(logs, 'RevokedOperator', { - operator: operator, - tokenHolder: holder, - }); - }); - }); - - describe('re-authorize operator', function () { - it('AuthorizedOperator event is emitted', async function () { - const { logs } = await this.token.authorizeOperator(operator, { from: holder }); - expectEvent.inLogs(logs, 'AuthorizedOperator', { - operator: operator, - tokenHolder: holder, - }); - }); - - it('operator is authorized', async function () { - const iopf = await this.token.contract.methods.isOperatorFor(operator, holder).call(); - assert(iopf); - }); - - it('AuthorizedOperator is emitted even if operator is already authorized', async function () { - const { logs } = await this.token.authorizeOperator(operator, { from: holder }); - expectEvent.inLogs(logs, 'AuthorizedOperator', { - operator: operator, - tokenHolder: holder, - }); - }); - }); - }); - - describe('send()', function () { - before('Deploy ERC777', async function () { - this.token = await ERC777.new( - 'Test777', 'T77', 1, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA, { from: holder } - ); - }); - - it('Sent event is emitted when sending 0 token', async function () { - const userData = '0xdeadbeef'; - - const { events } = await this.token.contract.methods.send(operator, '0', userData).send({ from: holder }); - expectEvent.inEvents(events, 'Sent', { - operator: holder, - from: holder, - to: operator, - amount: '0', - data: userData, - }); - }); - - it('revert when sending an amount of token from an account with insufficient balance', async function () { - const amount = parseInt(INITIAL_SUPPLY, 10) + 100; - const userData = '0xdeadbeef'; - await shouldFail.reverting( - this.token.contract.methods.send(operator, amount.toString(), userData).send({ from: holder }) - ); - }); - - describe('sending an amount of token from an account with sufficient balance', function () { - it('Sent event is emitted', async function () { - const userData = '0xdeadbeef'; - - const { events } = await this.token.contract.methods.send(operator, '100', userData).send({ from: holder }); - expectEvent.inEvents(events, 'Sent', { - operator: holder, - from: holder, - to: operator, - amount: '100', - data: userData, - }); - }); - - it('sender balance is decreased', async function () { - const balance = parseInt(INITIAL_SUPPLY, 10) - 100; - (await this.token.balanceOf(holder)).toString().should.be.equal(balance.toString()); - }); - - it('recipient balance is increased', async function () { - (await this.token.balanceOf(operator)).toString().should.be.equal('100'); - }); - - describe('hooks', function () { - it('tokensToSend() hook is called when declared', async function () { - const userData = '0xdeadbeef'; - - // deploy sender contract and give tokens - const sender = await ERC777TokensSender.new(true, this.token.address); - await this.token.contract.methods.send(sender.address, '100', userData).send({ from: holder }); - - const { events } = await sender.contract.methods.sendTokens(operator, '100', userData).send({ from: holder }); - expectEvent.inEvents(events, 'TokensToSend', { - operator: sender.address, - from: sender.address, - to: operator, - amount: '100', - data: userData, - }); - }); - - it('tokensToSend() hook is not called when not declared', async function () { - const userData = '0xdeadbeef'; - - // deploy sender contract and give tokens - const sender = await ERC777TokensSender.new(false, this.token.address); - await this.token.contract.methods.send(sender.address, '100', userData).send({ from: holder }); - - const { events } = await sender.contract.methods.sendTokens(operator, '100', userData).send({ from: holder }); - // eslint-disable-next-line no-unused-expressions - expect(events.tokensToSend).to.not.exist; - }); - - it('tokensReceived() hook is called when declared', async function () { - const userData = '0xdeadbeef'; - - const receiver = await ERC777TokensRecipient.new(true); - await this.token.contract.methods.send(receiver.address, '100', userData).send({ from: holder }); - const events = await receiver.getPastEvents('TokensReceived'); - events.length.should.be.not.equal(0); - const event = events[0].returnValues; - event.operator.should.be.equal(holder); - event.from.should.be.equal(holder); - event.to.should.be.equal(receiver.address); - event.amount.toString().should.be.equal('100'); - event.data.should.be.equal(userData); - }); - - it('tokensReceived() hook is not called when not declared', async function () { - const userData = '0xdeadbeef'; - - const receiver = await ERC777TokensRecipient.new(false); - await this.token.contract.methods.send(receiver.address, '100', userData).send({ from: holder }); - const events = await receiver.getPastEvents('TokensReceived'); - events.length.should.be.equal(0); - }); - }); - - it('revert when sending an amount of token to address(0)', async function () { - const userData = '0xdeadbeef'; - await shouldFail.reverting( - this.token.contract.methods.send(ZERO_ADDRESS, '100', userData).send({ from: holder }) - ); - }); - - it('revert when sending an amount which is not a multiple of granularity', async function () { - const userData = '0xdeadbeef'; - const tempToken = await ERC777.new( - 'Test777', 'T77', 10, [], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA, { from: holder } - ); - await shouldFail.reverting( - tempToken.contract.methods.send(anotherAccount, '15', userData).send({ from: holder }) - ); - }); - }); - }); - - describe('operatorSend()', function () { - const operatorTests = { - defaultOperatorTest: - { - name: 'default operator', - deployFn: async function (holder, operator) { - this.token = - await ERC777.new( - 'Test777', - 'T77', - 1, - [operator], - INITIAL_SUPPLY, - USER_DATA, - OPERATOR_DATA, - { from: holder } - ); - }, - deploySender: async function (holder, operator, declareInterface) { - // deploy sender contract and give tokens - this.sender = await ERC777TokensSender.new(declareInterface, this.token.address); - await this.token.contract.methods.send( - this.sender.address, - '100', - web3.utils.asciiToHex('') - ).send({ from: holder }); - }, - }, - nonDefaultOperatorTest: - { - name: 'non-default operator', - deployFn: async function (holder, operator) { - this.token = - await ERC777.new( - 'Test777', - 'T77', - 1, - [], - INITIAL_SUPPLY, - USER_DATA, - OPERATOR_DATA, - { from: holder } - ); - await this.token.authorizeOperator(operator, { from: holder }); - }, - deploySender: async function (holder, operator, declareInterface) { - // deploy sender contract and give tokens - this.sender = await ERC777TokensSender.new(declareInterface, this.token.address); - await this.token.contract.methods.send( - this.sender.address, - '100', - web3.utils.asciiToHex('') - ).send({ from: holder }); - // declare operator - await this.sender.contract.methods.authorizeOperator(operator).send({ from: holder }); - }, - }, - }; - - it('revert when msg.sender is not an operator', async function () { - const tempToken = await ERC777.new( - 'Test777', 'T77', 1, [operator], INITIAL_SUPPLY, USER_DATA, OPERATOR_DATA, { from: holder } - ); - const userData = '0xdeadbeef'; - const opData = '0xbabecafe'; - await shouldFail.reverting( - tempToken.contract.methods.operatorSend( - holder, - anotherAccount, - '100', - userData, - opData - ).send({ from: anotherAccount }) - ); - }); - - for (const test in operatorTests) { - describe('when operator is a ' + operatorTests[test].name, function () { - before('Deploy ERC777', async function () { - await operatorTests[test].deployFn.call(this, holder, operator); - }); - - it('Sent event is emitted when sending 0 token', async function () { - const userData = '0xdeadbeef'; - const opData = '0xbabecafe'; - - const { events } = await this.token.contract.methods.operatorSend( - holder, - anotherAccount, - '0', - userData, - opData - ).send({ from: operator }); - - expectEvent.inEvents(events, 'Sent', { - operator: operator, - from: holder, - to: anotherAccount, - amount: '0', - data: userData, - operatorData: opData, - }); - }); - - it('revert when sending an amount of token from an account with insufficient balance', async function () { - const amount = parseInt(INITIAL_SUPPLY, 10) + 100; - const userData = '0xdeadbeef'; - const opData = '0xbabecafe'; - - await shouldFail.reverting( - this.token.contract.methods.operatorSend( - holder, - anotherAccount, - amount.toString(), - userData, - opData - ).send({ from: operator }) - ); - }); - - describe('sending an amount of token from an account with sufficient balance', function () { - it('Sent event is emitted', async function () { - const userData = '0xdeadbeef'; - const opData = '0xbabecafe'; - - const { events } = await this.token.contract.methods.operatorSend( - holder, - anotherAccount, - '100', - userData, - opData - ).send({ from: operator }); - - expectEvent.inEvents(events, 'Sent', { - operator: operator, - from: holder, - to: anotherAccount, - amount: '100', - data: userData, - operatorData: opData, - }); - }); - - it('sender balance is decreased', async function () { - const balance = parseInt(INITIAL_SUPPLY, 10) - 100; - (await this.token.balanceOf(holder)).toString().should.be.equal(balance.toString()); - }); - - it('recipient balance is increased', async function () { - (await this.token.balanceOf(anotherAccount)).toString().should.be.equal('100'); - }); - - it('revert when recipient is address(0)', async function () { - const userData = '0xdeadbeef'; - const opData = '0xbabecafe'; - await shouldFail.reverting( - this.token.contract.methods.operatorSend( - holder, - ZERO_ADDRESS, - '100', - userData, - opData - ).send({ from: operator }) - ); - }); - - it('revert when sending an amount which is not a multiple of granularity', async function () { - const userData = '0xdeadbeef'; - const opData = '0xbabecafe'; - const tempToken = await ERC777.new( - 'Test777', - 'T77', - 10, - [operator], - INITIAL_SUPPLY, - USER_DATA, - OPERATOR_DATA, - { from: holder } - ); - await shouldFail.reverting( - tempToken.contract.methods.operatorSend( - holder, - anotherAccount, - '15', - userData, - opData - ).send({ from: operator }) - ); - }); - - it('operator is the holder when from is address(0)', async function () { - const userData = '0xdeadbeef'; - const opData = '0xbabecafe'; - - this.token.contract.methods.send(operator, '100', userData).send({ from: holder }).then(async () => { - const { events } = await this.token.contract.methods.operatorSend( - ZERO_ADDRESS, - anotherAccount, - '100', - userData, - opData - ).send({ from: operator }); - - expectEvent.inEvents(events, 'Sent', { - operator: operator, - from: operator, - to: anotherAccount, - amount: '100', - data: userData, - operatorData: opData, - }); - }).catch(errors => {}); - }); - - describe('hooks', function () { - it('tokensToSend() hook is called when declared', async function () { - const userData = '0xdeadbeef'; - const opData = '0xbabecafe'; - - // deploy sender contract, declare operator and give tokens - await operatorTests[test].deploySender.call(this, holder, operator, true); - - await this.token.contract.methods.operatorSend( - this.sender.address, - anotherAccount, - '100', - userData, - opData - ).send({ from: operator }); - - const events = await this.sender.getPastEvents('TokensToSend'); - events.length.should.be.not.equal(0); - const event = events[0].returnValues; - event.operator.should.be.equal(operator); - event.from.should.be.equal(this.sender.address); - event.to.should.be.equal(anotherAccount); - event.amount.toString().should.be.equal('100'); - event.data.should.be.equal(userData); - event.operatorData.should.be.equal(opData); - }); - - it('tokensToSend() hook is not called when not declared', async function () { - const userData = '0xdeadbeef'; - const opData = '0xbabecafe'; - - // deploy sender contract, declare operator and give tokens - await operatorTests[test].deploySender.call(this, holder, operator, false); - - await this.token.contract.methods.operatorSend( - this.sender.address, - anotherAccount, - '100', - userData, - opData - ).send({ from: operator }); - - const events = await this.sender.getPastEvents('TokensToSend'); - // eslint-disable-next-line no-unused-expressions - expect(events.tokensToSend).to.not.exist; - }); - - it('tokensReceived() hook is called when declared', async function () { - const userData = '0xdeadbeef'; - const opData = '0xbabecafe'; - - const receiver = await ERC777TokensRecipient.new(true); - await this.token.contract.methods.operatorSend( - holder, - receiver.address, - '100', - userData, - opData - ).send({ from: operator }); - const events = await receiver.getPastEvents('TokensReceived'); - events.length.should.be.not.equal(0); - const event = events[0].returnValues; - event.operator.should.be.equal(operator); - event.from.should.be.equal(holder); - event.to.should.be.equal(receiver.address); - event.amount.toString().should.be.equal('100'); - event.data.should.be.equal(userData); - event.operatorData.should.be.equal(opData); - }); - - it('tokensReceived() hook is not called when not declared', async function () { - const userData = '0xdeadbeef'; - const opData = '0xbabecafe'; - - const receiver = await ERC777TokensRecipient.new(false); - await this.token.contract.methods.operatorSend( - holder, - receiver.address, - '100', - userData, - opData - ).send({ from: operator }); - - const events = await receiver.getPastEvents('TokensReceived'); - // eslint-disable-next-line no-unused-expressions - expect(events.tokensReceived).to.not.exist; - }); - }); - }); - }); - } - }); - - describe('burn()', function () { - const userData = '0xdeadbeef'; - - before('Deploy ERC777', async function () { - this.token = await ERC777.new( - 'Test777', - 'T77', - 1, - [], - INITIAL_SUPPLY, - USER_DATA, - OPERATOR_DATA, - { from: holder } - ); - }); - - it('Burned event is emitted when burning 0 token', async function () { - const { events } = await this.token.contract.methods.burn('0', userData).send({ from: holder }); - expectEvent.inEvents(events, 'Burned', { - operator: holder, - from: holder, - amount: '0', - data: userData, - }); - }); - - it('revert when burning an amount of token from an account with insufficient balance', async function () { - const amount = parseInt(INITIAL_SUPPLY, 10) + 100; - await shouldFail.reverting(this.token.contract.methods.burn(amount.toString(), userData).send({ from: holder })); - }); - - describe('burning an amount of token from an account with sufficient balance', function () { - it('Burned event is emitted', async function () { - const { events } = await this.token.contract.methods.burn('100', userData).send({ from: holder }); - expectEvent.inEvents(events, 'Burned', { - operator: holder, - from: holder, - amount: '100', - data: userData, - }); - }); - - it('holder balance is decreased', async function () { - const balance = parseInt(INITIAL_SUPPLY, 10) - 100; - (await this.token.balanceOf(holder)).toString().should.be.equal(balance.toString()); - }); - - it('balance of 0x0 is not increased', async function () { - (await this.token.balanceOf(ZERO_ADDRESS)).toString().should.be.equal('0'); - }); - - it('totalSupply is decreased', async function () { - const supply = parseInt(INITIAL_SUPPLY, 10) - 100; - (await this.token.totalSupply()).toString().should.be.equal(supply.toString()); - }); - - describe('hooks', function () { - it('tokensToSend() hook is called when declared, and data is 0x00', async function () { - // deploy sender contract and give tokens - const sender = await ERC777TokensSender.new(true, this.token.address); - await this.token.contract.methods.send( - sender.address, - '100', - web3.utils.asciiToHex('') - ).send({ from: holder }); - - const { events } = await sender.contract.methods.burnTokens('100', userData).send({ from: holder }); - expectEvent.inEvents(events, 'TokensToSend', { - operator: sender.address, - from: sender.address, - to: ZERO_ADDRESS, - amount: '100', - data: userData, - }); - }); - - it('tokensToSend() hook is not called when not declared', async function () { - // deploy sender contract and give tokens - const sender = await ERC777TokensSender.new(false, this.token.address); - await this.token.contract.methods.send( - sender.address, - '100', - web3.utils.asciiToHex('') - ).send({ from: holder }); - - const { events } = await sender.contract.methods.burnTokens('100', userData).send({ from: holder }); - // eslint-disable-next-line no-unused-expressions - expect(events.tokensToSend).to.not.exist; - }); - }); - - it('revert when sending an amount which is not a multiple of granularity', async function () { - const tempToken = await ERC777.new( - 'Test777', - 'T77', - 10, - [], - INITIAL_SUPPLY, - USER_DATA, - OPERATOR_DATA, - { from: holder } - ); - await shouldFail.reverting(tempToken.contract.methods.burn('15', userData).send({ from: holder })); - }); - }); - }); - - describe('operatorBurn()', function () { - const operatorTests = { - defaultOperatorTest: - { - name: 'default operator', - deployFn: async function (holder, operator) { - this.token = - await ERC777.new( - 'Test777', - 'T77', - 1, - [operator], - INITIAL_SUPPLY, - USER_DATA, - OPERATOR_DATA, - { from: holder } - ); - }, - deploySender: async function (holder, operator, declareInterface) { - // deploy sender contract and give tokens - this.sender = await ERC777TokensSender.new(declareInterface, this.token.address); - await this.token.contract.methods.send( - this.sender.address, - '100', - web3.utils.asciiToHex('') - ).send({ from: holder }); - }, - }, - nonDefaultOperatorTest: - { - name: 'non-default operator', - deployFn: async function (holder, operator) { - this.token = - await ERC777.new( - 'Test777', - 'T77', - 1, - [], - INITIAL_SUPPLY, - USER_DATA, - OPERATOR_DATA, - { from: holder } - ); - await this.token.authorizeOperator(operator, { from: holder }); - }, - deploySender: async function (holder, operator, declareInterface) { - // deploy sender contract and give tokens - this.sender = await ERC777TokensSender.new(declareInterface, this.token.address); - - await this.token.contract.methods.send( - this.sender.address, - '100', - web3.utils.asciiToHex('') - ).send({ from: holder }); - - // declare operator - await this.sender.contract.methods.authorizeOperator(operator).send({ from: holder }); - }, - }, - }; - - it('revert when msg.sender is not an operator', async function () { - const tempToken = await ERC777.new( - 'Test777', - 'T77', - 1, - [operator], - INITIAL_SUPPLY, - USER_DATA, - OPERATOR_DATA, - { from: holder } - ); - const opData = '0xbabecafe'; - const userData = '0xdeadbeef'; - await shouldFail.reverting( - tempToken.contract.methods.operatorBurn(holder, '100', userData, opData).send({ from: anotherAccount }) - ); - }); - - for (const test in operatorTests) { - describe('when operator is a ' + operatorTests[test].name, function () { - before('Deploy ERC777', async function () { - await operatorTests[test].deployFn.call(this, holder, operator); - }); - - it('Burned event is emitted when burning 0 token', async function () { - const opData = '0xbabecafe'; - const userData = '0xdeadbeef'; - - const { events } = await this.token.contract.methods.operatorBurn( - holder, - '0', - userData, - opData - ).send({ from: operator }); - - expectEvent.inEvents(events, 'Burned', { - operator: operator, - from: holder, - amount: '0', - data: userData, - operatorData: opData, - }); - }); - - it('revert when burning an amount of token from an account with insufficient balance', async function () { - const amount = parseInt(INITIAL_SUPPLY, 10) + 100; - const opData = '0xbabecafe'; - const userData = '0xdeadbeef'; - await shouldFail.reverting( - this.token.contract.methods.operatorBurn( - holder, - amount.toString(), - userData, - opData - ).send({ from: operator }) - ); - }); - - describe('burning an amount of token from an account with sufficient balance', function () { - it('Burned event is emitted', async function () { - const opData = '0xbabecafe'; - const userData = '0xdeadbeef'; - - const { events } = await this.token.contract.methods.operatorBurn( - holder, - '100', - userData, - opData - ).send({ from: operator }); - - expectEvent.inEvents(events, 'Burned', { - operator: operator, - from: holder, - amount: '100', - data: userData, - operatorData: opData, - }); - }); - - it('holder balance is decreased', async function () { - const balance = parseInt(INITIAL_SUPPLY, 10) - 100; - (await this.token.balanceOf(holder)).toString().should.be.equal(balance.toString()); - }); - - it('balance of 0x0 is not increased', async function () { - (await this.token.balanceOf(ZERO_ADDRESS)).toString().should.be.equal('0'); - }); - - it('totalSupply is decreased', async function () { - const supply = parseInt(INITIAL_SUPPLY, 10) - 100; - (await this.token.totalSupply()).toString().should.be.equal(supply.toString()); - }); - - it('revert when burning an amount which is not a multiple of granularity', async function () { - const opData = '0xbabecafe'; - const userData = '0xdeadbeef'; - const tempToken = await ERC777.new( - 'Test777', - 'T77', - 10, - [operator], - INITIAL_SUPPLY, - USER_DATA, - OPERATOR_DATA, - { from: holder } - ); - await shouldFail.reverting( - tempToken.contract.methods.operatorBurn(holder, '15', userData, opData).send({ from: operator }) - ); - }); - - it('operator is the holder when from is address(0)', async function () { - const opData = '0xbabecafe'; - const userData = '0xdeadbeef'; - - await this.token.contract.methods.send(operator, '100', web3.utils.asciiToHex('')).send({ from: holder }); - const { events } = await this.token.contract.methods.operatorBurn( - ZERO_ADDRESS, - '100', - userData, - opData - ).send({ from: operator }); - - expectEvent.inEvents(events, 'Burned', { - operator: operator, - from: operator, - amount: '100', - data: userData, - operatorData: opData, - }); - }); - - describe('hooks', function () { - it('tokensToSend() hook is called when declared', async function () { - const opData = '0xbabecafe'; - const userData = '0xdeadbeef'; - - // deploy sender contract, declare operator and give tokens - await operatorTests[test].deploySender.call(this, holder, operator, true); - - await this.token.contract.methods.operatorBurn( - this.sender.address, - '100', - userData, - opData - ).send({ from: operator }); - - const events = await this.sender.getPastEvents('TokensToSend'); - events.length.should.be.not.equal(0); - const event = events[0].returnValues; - event.operator.should.be.equal(operator); - event.from.should.be.equal(this.sender.address); - event.amount.toString().should.be.equal('100'); - event.data.should.be.equal(userData); - event.operatorData.should.be.equal(opData); - }); - - it('tokensToSend() hook is not called when not declared', async function () { - const opData = '0xbabecafe'; - const userData = '0xdeadbeef'; - - // deploy sender contract, declare operator and give tokens - await operatorTests[test].deploySender.call(this, holder, operator, false); - - await this.token.contract.methods.operatorBurn( - this.sender.address, - '100', - userData, - opData - ).send({ from: operator }); - - const events = await this.sender.getPastEvents('TokensToSend'); - // eslint-disable-next-line no-unused-expressions - expect(events.tokensToSend).to.not.exist; - }); - }); - }); - }); - } }); }); From 55387641139201e3c1e6ff40c907e945fe86c6d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Wed, 27 Mar 2019 17:51:46 -0300 Subject: [PATCH 29/64] Add basic 777 tests. --- contracts/mocks/ERC777Mock.sol | 16 ++++++ test/drafts/ERC777/ERC777.test.js | 96 +++++++++++++++++++++++++++++-- 2 files changed, 106 insertions(+), 6 deletions(-) create mode 100644 contracts/mocks/ERC777Mock.sol diff --git a/contracts/mocks/ERC777Mock.sol b/contracts/mocks/ERC777Mock.sol new file mode 100644 index 00000000000..1b1ebe64b17 --- /dev/null +++ b/contracts/mocks/ERC777Mock.sol @@ -0,0 +1,16 @@ +pragma solidity ^0.5.2; + +import "../drafts/ERC777/ERC777.sol"; + +contract ERC777Mock is ERC777 { + constructor ( + address initialHolder, + uint256 initialBalance, + string memory name, + string memory symbol, + uint256 granularity, + address[] memory defaultOperators + ) ERC777(name, symbol, granularity, defaultOperators) public { + _mint(msg.sender, initialHolder, initialBalance, "", ""); + } +} diff --git a/test/drafts/ERC777/ERC777.test.js b/test/drafts/ERC777/ERC777.test.js index 34cf5114b62..c6702907a5c 100644 --- a/test/drafts/ERC777/ERC777.test.js +++ b/test/drafts/ERC777/ERC777.test.js @@ -1,23 +1,27 @@ -const { BN, constants, shouldFail, singletons } = require('openzeppelin-test-helpers'); +const { BN, constants, expectEvent, shouldFail, singletons } = require('openzeppelin-test-helpers'); +const { ZERO_ADDRESS } = constants; -const ERC777 = artifacts.require('ERC777'); +const ERC777 = artifacts.require('ERC777Mock'); contract.only('ERC777', function ([_, registryFunder, initialHolder, defaultOperatorA, defaultOperatorB, operator, anyone]) { const initialSupply = new BN('10000'); const name = 'ERC777Test'; const symbol = '777T'; + const data = web3.utils.sha3('OZ777TestData'); + + const defaultOperators = [defaultOperatorA, defaultOperatorB]; before(async function () { this.erc1820 = await singletons.ERC1820Registry(registryFunder); }); it('reverts with a granularity of zero', async function () { - await shouldFail.reverting(ERC777.new(name, symbol, 0, [])); + await shouldFail.reverting(ERC777.new(initialHolder, initialSupply, name, symbol, 0, [])); }); context('with default operators', function () { beforeEach(async function () { - this.token = await ERC777.new(name, symbol, 1, [defaultOperatorA, defaultOperatorB]); + this.token = await ERC777.new(initialHolder, initialSupply, name, symbol, 1, defaultOperators); }); describe('basic information', function () { @@ -33,15 +37,95 @@ contract.only('ERC777', function ([_, registryFunder, initialHolder, defaultOper (await this.token.granularity()).should.be.bignumber.equal('1'); }); + it('returns the default operators', async function () { + (await this.token.defaultOperators()).should.deep.equal(defaultOperators); + }); + + it('default operators are operators for all accounts', async function () { + for (let operator of defaultOperators) { + (await this.token.isOperatorFor(operator, anyone)).should.equal(true); + } + }); + + it('returns thte total supply', async function () { + (await this.token.totalSupply()).should.be.bignumber.equal(initialSupply); + }); + it('is registered in the registry', async function () { - (await this.erc1820.getInterfaceImplementer(this.token.address, )).should.equal(this.token.address); + (await this.erc1820.getInterfaceImplementer(this.token.address, web3.utils.soliditySha3('ERC777Token'))) + .should.equal(this.token.address); + }); + }); + + function assertSendSuccess(from, to, amount, data) { + it(`can send an amount of ${amount}`, async function () { + const initialFromBalance = await this.token.balanceOf(from); + const initialToBalance = await this.token.balanceOf(to); + + const { logs } = await this.token.send(to, amount, data, { from }); + expectEvent.inLogs(logs, 'Sent', { + operator: from, + from, + to, + amount, + data, + operatorData: null, + }); + + const finalFromBalance = await this.token.balanceOf(from); + const finalToBalance = await this.token.balanceOf(to); + + finalToBalance.sub(initialToBalance).should.be.bignumber.equal(amount); + finalFromBalance.sub(initialFromBalance).should.be.bignumber.equal(amount.neg()); + }); + } + + describe('balanceOf', function () { + context('for an account with no tokens', function () { + it('returns zero', async function () { + (await this.token.balanceOf(anyone)).should.be.bignumber.equal('0'); + }); + }); + + context('for an account with tokens', function () { + it('returns their balance', async function () { + (await this.token.balanceOf(initialHolder)).should.be.bignumber.equal(initialSupply); + }); + }); + }); + + describe('send', function () { + context('when the sender has no tokens', async function () { + const from = anyone; + + assertSendSuccess(from, initialHolder, new BN('0'), data); + + it('reverts when sending a non-zero amount', async function () { + await shouldFail.reverting(this.token.send(initialHolder, new BN('1'), data, { from })); + }); + }); + + context('when the sender has tokens', async function () { + const from = initialHolder; + + assertSendSuccess(from, anyone, new BN('0'), data); + assertSendSuccess(from, anyone, new BN('1'), data); + + it('reverts when sending more than the balance', async function () { + const balance = await this.token.balanceOf(from); + await shouldFail.reverting(this.token.send(anyone, balance.addn(1), data, { from })); + }); + + it('reverts when sending to the zero address', async function () { + await shouldFail.reverting(this.token.send(ZERO_ADDRESS, new BN('1'), data, { from })); + }); }); }); }); context('with no default operators', function () { beforeEach(async function () { - await shouldFail.reverting(ERC777.new(name, symbol, 1, [])); + await shouldFail.reverting(ERC777.new(initialHolder, initialSupply, name, symbol, 1, [])); }); }); }); From e9936f7f1b6572869914edf038607fde53ca5dc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Wed, 27 Mar 2019 18:03:09 -0300 Subject: [PATCH 30/64] Add granularity send test. --- test/drafts/ERC777/ERC777.test.js | 68 ++++++++++++++++++++----------- 1 file changed, 45 insertions(+), 23 deletions(-) diff --git a/test/drafts/ERC777/ERC777.test.js b/test/drafts/ERC777/ERC777.test.js index c6702907a5c..4b58b700d43 100644 --- a/test/drafts/ERC777/ERC777.test.js +++ b/test/drafts/ERC777/ERC777.test.js @@ -11,6 +11,29 @@ contract.only('ERC777', function ([_, registryFunder, initialHolder, defaultOper const defaultOperators = [defaultOperatorA, defaultOperatorB]; + function assertSendSuccess(from, to, amount, data) { + it(`can send an amount of ${amount}`, async function () { + const initialFromBalance = await this.token.balanceOf(from); + const initialToBalance = await this.token.balanceOf(to); + + const { logs } = await this.token.send(to, amount, data, { from }); + expectEvent.inLogs(logs, 'Sent', { + operator: from, + from, + to, + amount, + data, + operatorData: null, + }); + + const finalFromBalance = await this.token.balanceOf(from); + const finalToBalance = await this.token.balanceOf(to); + + finalToBalance.sub(initialToBalance).should.be.bignumber.equal(amount); + finalFromBalance.sub(initialFromBalance).should.be.bignumber.equal(amount.neg()); + }); + } + before(async function () { this.erc1820 = await singletons.ERC1820Registry(registryFunder); }); @@ -57,29 +80,6 @@ contract.only('ERC777', function ([_, registryFunder, initialHolder, defaultOper }); }); - function assertSendSuccess(from, to, amount, data) { - it(`can send an amount of ${amount}`, async function () { - const initialFromBalance = await this.token.balanceOf(from); - const initialToBalance = await this.token.balanceOf(to); - - const { logs } = await this.token.send(to, amount, data, { from }); - expectEvent.inLogs(logs, 'Sent', { - operator: from, - from, - to, - amount, - data, - operatorData: null, - }); - - const finalFromBalance = await this.token.balanceOf(from); - const finalToBalance = await this.token.balanceOf(to); - - finalToBalance.sub(initialToBalance).should.be.bignumber.equal(amount); - finalFromBalance.sub(initialFromBalance).should.be.bignumber.equal(amount.neg()); - }); - } - describe('balanceOf', function () { context('for an account with no tokens', function () { it('returns zero', async function () { @@ -128,4 +128,26 @@ contract.only('ERC777', function ([_, registryFunder, initialHolder, defaultOper await shouldFail.reverting(ERC777.new(initialHolder, initialSupply, name, symbol, 1, [])); }); }); + + context('with granularity larger than 1', function () { + const granularity = new BN('4'); + + beforeEach(async function () { + initialSupply.mod(granularity).should.be.bignumber.equal('0'); + + this.token = await ERC777.new(initialHolder, initialSupply, name, symbol, granularity, defaultOperators); + }); + + context('when the sender has tokens', function () { + const from = initialHolder; + + assertSendSuccess(from, anyone, new BN('0'), data); + assertSendSuccess(from, anyone, granularity, data); + assertSendSuccess(from, anyone, granularity.muln(2), data); + + it('reverts when sending an amount non-multiple of the granularity', async function () { + await shouldFail.reverting(this.token.send(anyone, granularity.subn(1), data, { from })); + }); + }); + }); }); From 5c0ee8acc7008dfa3121a5aa5bc237bbca0bb3f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Wed, 27 Mar 2019 18:16:33 -0300 Subject: [PATCH 31/64] Add first operator send tests. --- test/drafts/ERC777/ERC777.test.js | 78 +++++++++++++++++++++++++++---- 1 file changed, 68 insertions(+), 10 deletions(-) diff --git a/test/drafts/ERC777/ERC777.test.js b/test/drafts/ERC777/ERC777.test.js index 4b58b700d43..1fe92baa9a6 100644 --- a/test/drafts/ERC777/ERC777.test.js +++ b/test/drafts/ERC777/ERC777.test.js @@ -8,6 +8,7 @@ contract.only('ERC777', function ([_, registryFunder, initialHolder, defaultOper const name = 'ERC777Test'; const symbol = '777T'; const data = web3.utils.sha3('OZ777TestData'); + const operatorData = web3.utils.sha3('OZ777TestOperatorData'); const defaultOperators = [defaultOperatorA, defaultOperatorB]; @@ -34,6 +35,29 @@ contract.only('ERC777', function ([_, registryFunder, initialHolder, defaultOper }); } + function assertOperatorSendSuccess(from, operator, to, amount, data, operatorData) { + it(`operator can send an amount of ${amount}`, async function () { + const initialFromBalance = await this.token.balanceOf(from); + const initialToBalance = await this.token.balanceOf(to); + + const { logs } = await this.token.operatorSend(from, to, amount, data, operatorData, { from: operator }); + expectEvent.inLogs(logs, 'Sent', { + operator, + from, + to, + amount, + data, + operatorData, + }); + + const finalFromBalance = await this.token.balanceOf(from); + const finalToBalance = await this.token.balanceOf(to); + + finalToBalance.sub(initialToBalance).should.be.bignumber.equal(amount); + finalFromBalance.sub(initialFromBalance).should.be.bignumber.equal(amount.neg()); + }); + } + before(async function () { this.erc1820 = await singletons.ERC1820Registry(registryFunder); }); @@ -98,26 +122,60 @@ contract.only('ERC777', function ([_, registryFunder, initialHolder, defaultOper context('when the sender has no tokens', async function () { const from = anyone; - assertSendSuccess(from, initialHolder, new BN('0'), data); + describe('direct send', function () { + assertSendSuccess(from, initialHolder, new BN('0'), data); - it('reverts when sending a non-zero amount', async function () { - await shouldFail.reverting(this.token.send(initialHolder, new BN('1'), data, { from })); + it('reverts when sending a non-zero amount', async function () { + await shouldFail.reverting(this.token.send(initialHolder, new BN('1'), data, { from })); + }); + }); + + describe('operator send', function () { + assertOperatorSendSuccess(from, defaultOperatorA, initialHolder, new BN('0'), data, operatorData); + + it('reverts when sending a non-zero amount', async function () { + await shouldFail.reverting( + this.token.operatorSend(from, initialHolder, new BN('1'), data, operatorData, { from: operator }) + ); + }); }); }); context('when the sender has tokens', async function () { const from = initialHolder; - assertSendSuccess(from, anyone, new BN('0'), data); - assertSendSuccess(from, anyone, new BN('1'), data); + describe('direct send', function () { + assertSendSuccess(from, anyone, new BN('0'), data); + assertSendSuccess(from, anyone, new BN('1'), data); + + it('reverts when sending more than the balance', async function () { + const balance = await this.token.balanceOf(from); + await shouldFail.reverting(this.token.send(anyone, balance.addn(1), data, { from })); + }); - it('reverts when sending more than the balance', async function () { - const balance = await this.token.balanceOf(from); - await shouldFail.reverting(this.token.send(anyone, balance.addn(1), data, { from })); + it('reverts when sending to the zero address', async function () { + await shouldFail.reverting(this.token.send(ZERO_ADDRESS, new BN('1'), data, { from })); + }); }); - it('reverts when sending to the zero address', async function () { - await shouldFail.reverting(this.token.send(ZERO_ADDRESS, new BN('1'), data, { from })); + describe('operator send', function () { + assertOperatorSendSuccess(from, defaultOperatorA, anyone, new BN('0'), data, operatorData); + assertOperatorSendSuccess(from, defaultOperatorB, anyone, new BN('1'), data, operatorData); + + it('reverts when sending more than the balance', async function () { + const balance = await this.token.balanceOf(from); + await shouldFail.reverting( + this.token.operatorSend(from, anyone, balance.addn(1), data, operatorData, { from: defaultOperatorA }) + ); + }); + + it('reverts when sending to the zero address', async function () { + await shouldFail.reverting( + this.token.operatorSend( + from, ZERO_ADDRESS, new BN('1'), data, operatorData, { from: defaultOperatorA } + ) + ); + }); }); }); }); From 824cb94a13179517f3933931a45e2f1266deca40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Wed, 27 Mar 2019 19:04:17 -0300 Subject: [PATCH 32/64] Add burn tests. --- test/drafts/ERC777/ERC777.test.js | 110 ++++++++++++++++++++++++++++-- 1 file changed, 105 insertions(+), 5 deletions(-) diff --git a/test/drafts/ERC777/ERC777.test.js b/test/drafts/ERC777/ERC777.test.js index 1fe92baa9a6..741fe6cc87d 100644 --- a/test/drafts/ERC777/ERC777.test.js +++ b/test/drafts/ERC777/ERC777.test.js @@ -3,7 +3,7 @@ const { ZERO_ADDRESS } = constants; const ERC777 = artifacts.require('ERC777Mock'); -contract.only('ERC777', function ([_, registryFunder, initialHolder, defaultOperatorA, defaultOperatorB, operator, anyone]) { +contract.only('ERC777', function ([_, registryFunder, initialHolder, defaultOperatorA, defaultOperatorB, newOperator, anyone]) { const initialSupply = new BN('10000'); const name = 'ERC777Test'; const symbol = '777T'; @@ -12,8 +12,9 @@ contract.only('ERC777', function ([_, registryFunder, initialHolder, defaultOper const defaultOperators = [defaultOperatorA, defaultOperatorB]; - function assertSendSuccess(from, to, amount, data) { + function assertSendSuccess (from, to, amount, data) { it(`can send an amount of ${amount}`, async function () { + const initialTotalSupply = await this.token.totalSupply(); const initialFromBalance = await this.token.balanceOf(from); const initialToBalance = await this.token.balanceOf(to); @@ -27,16 +28,19 @@ contract.only('ERC777', function ([_, registryFunder, initialHolder, defaultOper operatorData: null, }); + const finalTotalSupply = await this.token.totalSupply(); const finalFromBalance = await this.token.balanceOf(from); const finalToBalance = await this.token.balanceOf(to); + finalTotalSupply.should.be.bignumber.equal(initialTotalSupply); finalToBalance.sub(initialToBalance).should.be.bignumber.equal(amount); finalFromBalance.sub(initialFromBalance).should.be.bignumber.equal(amount.neg()); }); } - function assertOperatorSendSuccess(from, operator, to, amount, data, operatorData) { + function assertOperatorSendSuccess (from, operator, to, amount, data, operatorData) { it(`operator can send an amount of ${amount}`, async function () { + const initialTotalSupply = await this.token.totalSupply(); const initialFromBalance = await this.token.balanceOf(from); const initialToBalance = await this.token.balanceOf(to); @@ -50,14 +54,60 @@ contract.only('ERC777', function ([_, registryFunder, initialHolder, defaultOper operatorData, }); + const finalTotalSupply = await this.token.totalSupply(); const finalFromBalance = await this.token.balanceOf(from); const finalToBalance = await this.token.balanceOf(to); + finalTotalSupply.should.be.bignumber.equal(initialTotalSupply); finalToBalance.sub(initialToBalance).should.be.bignumber.equal(amount); finalFromBalance.sub(initialFromBalance).should.be.bignumber.equal(amount.neg()); }); } + function assertBurnSuccess (from, amount, data) { + it(`can burn an amount of ${amount}`, async function () { + const initialTotalSupply = await this.token.totalSupply(); + const initialFromBalance = await this.token.balanceOf(from); + + const { logs } = await this.token.burn(amount, data, { from }); + expectEvent.inLogs(logs, 'Burned', { + operator: from, + from, + amount, + data, + operatorData: null, + }); + + const finalTotalSupply = await this.token.totalSupply(); + const finalFromBalance = await this.token.balanceOf(from); + + finalTotalSupply.sub(initialTotalSupply).should.be.bignumber.equal(amount.neg()); + finalFromBalance.sub(initialFromBalance).should.be.bignumber.equal(amount.neg()); + }); + } + + function assertOperatorBurnSuccess (from, operator, amount, data, operatorData) { + it(`operator can burn an amount of ${amount}`, async function () { + const initialTotalSupply = await this.token.totalSupply(); + const initialFromBalance = await this.token.balanceOf(from); + + const { logs } = await this.token.operatorBurn(from, amount, data, operatorData, { from: operator }); + expectEvent.inLogs(logs, 'Burned', { + operator, + from, + amount, + data, + operatorData, + }); + + const finalTotalSupply = await this.token.totalSupply(); + const finalFromBalance = await this.token.balanceOf(from); + + finalTotalSupply.sub(initialTotalSupply).should.be.bignumber.equal(amount.neg()); + finalFromBalance.sub(initialFromBalance).should.be.bignumber.equal(amount.neg()); + }); + } + before(async function () { this.erc1820 = await singletons.ERC1820Registry(registryFunder); }); @@ -89,7 +139,7 @@ contract.only('ERC777', function ([_, registryFunder, initialHolder, defaultOper }); it('default operators are operators for all accounts', async function () { - for (let operator of defaultOperators) { + for (const operator of defaultOperators) { (await this.token.isOperatorFor(operator, anyone)).should.equal(true); } }); @@ -135,7 +185,7 @@ contract.only('ERC777', function ([_, registryFunder, initialHolder, defaultOper it('reverts when sending a non-zero amount', async function () { await shouldFail.reverting( - this.token.operatorSend(from, initialHolder, new BN('1'), data, operatorData, { from: operator }) + this.token.operatorSend(from, initialHolder, new BN('1'), data, operatorData, { from: defaultOperatorA }) ); }); }); @@ -179,6 +229,56 @@ contract.only('ERC777', function ([_, registryFunder, initialHolder, defaultOper }); }); }); + + describe('burn', function () { + context('when the sender has no tokens', async function () { + const from = anyone; + + describe('direct burn', function () { + assertBurnSuccess(from, new BN('0'), data); + + it('reverts when burning a non-zero amount', async function () { + await shouldFail.reverting(this.token.burn(new BN('1'), data, { from })); + }); + }); + + describe('operator burn', function () { + assertOperatorBurnSuccess(from, defaultOperatorA, new BN('0'), data, operatorData); + + it('reverts when burning a non-zero amount', async function () { + await shouldFail.reverting( + this.token.operatorBurn(from, new BN('1'), data, operatorData, { from: defaultOperatorA }) + ); + }); + }); + }); + + context('when the sender has tokens', async function () { + const from = initialHolder; + + describe('direct burn', function () { + assertBurnSuccess(from, new BN('0'), data); + assertBurnSuccess(from, new BN('1'), data); + + it('reverts when burning more than the balance', async function () { + const balance = await this.token.balanceOf(from); + await shouldFail.reverting(this.token.burn(balance.addn(1), data, { from })); + }); + }); + + describe('operator burn', function () { + assertOperatorBurnSuccess(from, defaultOperatorA, new BN('0'), data, operatorData); + assertOperatorBurnSuccess(from, defaultOperatorB, new BN('1'), data, operatorData); + + it('reverts when burning more than the balance', async function () { + const balance = await this.token.balanceOf(from); + await shouldFail.reverting( + this.token.operatorBurn(from, balance.addn(1), data, operatorData, { from: defaultOperatorA }) + ); + }); + }); + }); + }); }); context('with no default operators', function () { From de529bb12f919cb90a085d9eb36896d512557451 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Wed, 27 Mar 2019 20:30:59 -0300 Subject: [PATCH 33/64] Refactor send and burn tests. --- contracts/mocks/ERC777Mock.sol | 2 +- test/drafts/ERC777/ERC777.behavior.js | 230 ++++++++++++++++++++++++++ test/drafts/ERC777/ERC777.test.js | 225 +++---------------------- 3 files changed, 256 insertions(+), 201 deletions(-) create mode 100644 test/drafts/ERC777/ERC777.behavior.js diff --git a/contracts/mocks/ERC777Mock.sol b/contracts/mocks/ERC777Mock.sol index 1b1ebe64b17..0e2aa0a6d26 100644 --- a/contracts/mocks/ERC777Mock.sol +++ b/contracts/mocks/ERC777Mock.sol @@ -10,7 +10,7 @@ contract ERC777Mock is ERC777 { string memory symbol, uint256 granularity, address[] memory defaultOperators - ) ERC777(name, symbol, granularity, defaultOperators) public { + ) public ERC777(name, symbol, granularity, defaultOperators) { _mint(msg.sender, initialHolder, initialBalance, "", ""); } } diff --git a/test/drafts/ERC777/ERC777.behavior.js b/test/drafts/ERC777/ERC777.behavior.js new file mode 100644 index 00000000000..2eec3c509cc --- /dev/null +++ b/test/drafts/ERC777/ERC777.behavior.js @@ -0,0 +1,230 @@ +const { BN, constants, expectEvent, shouldFail } = require('openzeppelin-test-helpers'); +const { ZERO_ADDRESS } = constants; + +function shouldBehaveLikeERC777DirectSend (holder, nonHolder, recipient, data) { + describe('direct send', function () { + context('when the sender has no tokens', function () { + const from = nonHolder; + + shouldSendTokens(from, recipient, new BN('0'), data); + + it('reverts when sending a non-zero amount', async function () { + await shouldFail.reverting(this.token.send(recipient, new BN('1'), data, { from })); + }); + }); + + context('when the sender has tokens', function () { + const from = holder; + + shouldSendTokens(from, recipient, new BN('0'), data); + shouldSendTokens(from, recipient, new BN('1'), data); + + it('reverts when sending more than the balance', async function () { + const balance = await this.token.balanceOf(from); + await shouldFail.reverting(this.token.send(recipient, balance.addn(1), data, { from })); + }); + + it('reverts when sending to the zero address', async function () { + await shouldFail.reverting(this.token.send(ZERO_ADDRESS, new BN('1'), data, { from })); + }); + }); + }); +} + +function shouldBehaveLikeERC777OperatorSend (holder, nonHolder, recipient, operator, data, operatorData) { + describe('operator send', function () { + context('when the sender has no tokens', function () { + const from = nonHolder; + + shouldOperatorSendTokens(from, operator, recipient, new BN('0'), data, operatorData); + + it('reverts when sending a non-zero amount', async function () { + await shouldFail.reverting( + this.token.operatorSend(from, recipient, new BN('1'), data, operatorData, { from: operator }) + ); + }); + }); + + context('when the sender has tokens', async function () { + const from = holder; + + shouldOperatorSendTokens(from, operator, recipient, new BN('0'), data, operatorData); + shouldOperatorSendTokens(from, operator, recipient, new BN('1'), data, operatorData); + + it('reverts when sending more than the balance', async function () { + const balance = await this.token.balanceOf(from); + await shouldFail.reverting( + this.token.operatorSend(from, recipient, balance.addn(1), data, operatorData, { from: operator }) + ); + }); + + it('reverts when sending to the zero address', async function () { + await shouldFail.reverting( + this.token.operatorSend( + from, ZERO_ADDRESS, new BN('1'), data, operatorData, { from: operator } + ) + ); + }); + }); + }); +} + +function shouldBehaveLikeERC777DirectBurn (holder, nonHolder, data) { + describe('direct burn', function () { + context('when the sender has no tokens', function () { + const from = nonHolder; + + shouldBurnTokens(from, new BN('0'), data); + + it('reverts when burning a non-zero amount', async function () { + await shouldFail.reverting(this.token.burn(new BN('1'), data, { from })); + }); + }); + + context('when the sender has tokens', function () { + const from = holder; + + shouldBurnTokens(from, new BN('0'), data); + shouldBurnTokens(from, new BN('1'), data); + + it('reverts when burning more than the balance', async function () { + const balance = await this.token.balanceOf(from); + await shouldFail.reverting(this.token.burn(balance.addn(1), data, { from })); + }); + }); + }); +} + +function shouldBehaveLikeERC777OperatorBurn (holder, nonHolder, operator, data, operatorData) { + describe('operator burn', function () { + context('when the sender has no tokens', function () { + const from = nonHolder; + + shouldOperatorBurnTokens(from, operator, new BN('0'), data, operatorData); + + it('reverts when burning a non-zero amount', async function () { + await shouldFail.reverting( + this.token.operatorBurn(from, new BN('1'), data, operatorData, { from: operator }) + ); + }); + }); + + context('when the sender has tokens', async function () { + const from = holder; + + shouldOperatorBurnTokens(from, operator, new BN('0'), data, operatorData); + shouldOperatorBurnTokens(from, operator, new BN('1'), data, operatorData); + + it('reverts when burning more than the balance', async function () { + const balance = await this.token.balanceOf(from); + await shouldFail.reverting( + this.token.operatorBurn(from, balance.addn(1), data, operatorData, { from: operator }) + ); + }); + }); + }); +} + +function shouldSendTokens (from, to, amount, data) { + it(`can send an amount of ${amount}`, async function () { + const initialTotalSupply = await this.token.totalSupply(); + const initialFromBalance = await this.token.balanceOf(from); + const initialToBalance = await this.token.balanceOf(to); + + const { logs } = await this.token.send(to, amount, data, { from }); + expectEvent.inLogs(logs, 'Sent', { + operator: from, + from, + to, + amount, + data, + operatorData: null, + }); + + const finalTotalSupply = await this.token.totalSupply(); + const finalFromBalance = await this.token.balanceOf(from); + const finalToBalance = await this.token.balanceOf(to); + + finalTotalSupply.should.be.bignumber.equal(initialTotalSupply); + finalToBalance.sub(initialToBalance).should.be.bignumber.equal(amount); + finalFromBalance.sub(initialFromBalance).should.be.bignumber.equal(amount.neg()); + }); +} + +function shouldOperatorSendTokens (from, operator, to, amount, data, operatorData) { + it(`operator can send an amount of ${amount}`, async function () { + const initialTotalSupply = await this.token.totalSupply(); + const initialFromBalance = await this.token.balanceOf(from); + const initialToBalance = await this.token.balanceOf(to); + + const { logs } = await this.token.operatorSend(from, to, amount, data, operatorData, { from: operator }); + expectEvent.inLogs(logs, 'Sent', { + operator, + from, + to, + amount, + data, + operatorData, + }); + + const finalTotalSupply = await this.token.totalSupply(); + const finalFromBalance = await this.token.balanceOf(from); + const finalToBalance = await this.token.balanceOf(to); + + finalTotalSupply.should.be.bignumber.equal(initialTotalSupply); + finalToBalance.sub(initialToBalance).should.be.bignumber.equal(amount); + finalFromBalance.sub(initialFromBalance).should.be.bignumber.equal(amount.neg()); + }); +} + +function shouldBurnTokens (from, amount, data) { + it(`can burn an amount of ${amount}`, async function () { + const initialTotalSupply = await this.token.totalSupply(); + const initialFromBalance = await this.token.balanceOf(from); + + const { logs } = await this.token.burn(amount, data, { from }); + expectEvent.inLogs(logs, 'Burned', { + operator: from, + from, + amount, + data, + operatorData: null, + }); + + const finalTotalSupply = await this.token.totalSupply(); + const finalFromBalance = await this.token.balanceOf(from); + + finalTotalSupply.sub(initialTotalSupply).should.be.bignumber.equal(amount.neg()); + finalFromBalance.sub(initialFromBalance).should.be.bignumber.equal(amount.neg()); + }); +} + +function shouldOperatorBurnTokens (from, operator, amount, data, operatorData) { + it(`operator can burn an amount of ${amount}`, async function () { + const initialTotalSupply = await this.token.totalSupply(); + const initialFromBalance = await this.token.balanceOf(from); + + const { logs } = await this.token.operatorBurn(from, amount, data, operatorData, { from: operator }); + expectEvent.inLogs(logs, 'Burned', { + operator, + from, + amount, + data, + operatorData, + }); + + const finalTotalSupply = await this.token.totalSupply(); + const finalFromBalance = await this.token.balanceOf(from); + + finalTotalSupply.sub(initialTotalSupply).should.be.bignumber.equal(amount.neg()); + finalFromBalance.sub(initialFromBalance).should.be.bignumber.equal(amount.neg()); + }); +} + +module.exports = { + shouldBehaveLikeERC777DirectSend, + shouldBehaveLikeERC777OperatorSend, + shouldBehaveLikeERC777DirectBurn, + shouldBehaveLikeERC777OperatorBurn, + shouldSendTokens, +}; diff --git a/test/drafts/ERC777/ERC777.test.js b/test/drafts/ERC777/ERC777.test.js index 741fe6cc87d..b177261297a 100644 --- a/test/drafts/ERC777/ERC777.test.js +++ b/test/drafts/ERC777/ERC777.test.js @@ -1,9 +1,18 @@ -const { BN, constants, expectEvent, shouldFail, singletons } = require('openzeppelin-test-helpers'); -const { ZERO_ADDRESS } = constants; +const { BN, shouldFail, singletons } = require('openzeppelin-test-helpers'); + +const { + shouldBehaveLikeERC777DirectSend, + shouldBehaveLikeERC777OperatorSend, + shouldBehaveLikeERC777DirectBurn, + shouldBehaveLikeERC777OperatorBurn, + shouldSendTokens, +} = require('./ERC777.behavior'); const ERC777 = artifacts.require('ERC777Mock'); -contract.only('ERC777', function ([_, registryFunder, initialHolder, defaultOperatorA, defaultOperatorB, newOperator, anyone]) { +contract('ERC777', function ([ + _, registryFunder, initialHolder, nonHolder, defaultOperatorA, defaultOperatorB, newOperator, anyone, +]) { const initialSupply = new BN('10000'); const name = 'ERC777Test'; const symbol = '777T'; @@ -12,102 +21,6 @@ contract.only('ERC777', function ([_, registryFunder, initialHolder, defaultOper const defaultOperators = [defaultOperatorA, defaultOperatorB]; - function assertSendSuccess (from, to, amount, data) { - it(`can send an amount of ${amount}`, async function () { - const initialTotalSupply = await this.token.totalSupply(); - const initialFromBalance = await this.token.balanceOf(from); - const initialToBalance = await this.token.balanceOf(to); - - const { logs } = await this.token.send(to, amount, data, { from }); - expectEvent.inLogs(logs, 'Sent', { - operator: from, - from, - to, - amount, - data, - operatorData: null, - }); - - const finalTotalSupply = await this.token.totalSupply(); - const finalFromBalance = await this.token.balanceOf(from); - const finalToBalance = await this.token.balanceOf(to); - - finalTotalSupply.should.be.bignumber.equal(initialTotalSupply); - finalToBalance.sub(initialToBalance).should.be.bignumber.equal(amount); - finalFromBalance.sub(initialFromBalance).should.be.bignumber.equal(amount.neg()); - }); - } - - function assertOperatorSendSuccess (from, operator, to, amount, data, operatorData) { - it(`operator can send an amount of ${amount}`, async function () { - const initialTotalSupply = await this.token.totalSupply(); - const initialFromBalance = await this.token.balanceOf(from); - const initialToBalance = await this.token.balanceOf(to); - - const { logs } = await this.token.operatorSend(from, to, amount, data, operatorData, { from: operator }); - expectEvent.inLogs(logs, 'Sent', { - operator, - from, - to, - amount, - data, - operatorData, - }); - - const finalTotalSupply = await this.token.totalSupply(); - const finalFromBalance = await this.token.balanceOf(from); - const finalToBalance = await this.token.balanceOf(to); - - finalTotalSupply.should.be.bignumber.equal(initialTotalSupply); - finalToBalance.sub(initialToBalance).should.be.bignumber.equal(amount); - finalFromBalance.sub(initialFromBalance).should.be.bignumber.equal(amount.neg()); - }); - } - - function assertBurnSuccess (from, amount, data) { - it(`can burn an amount of ${amount}`, async function () { - const initialTotalSupply = await this.token.totalSupply(); - const initialFromBalance = await this.token.balanceOf(from); - - const { logs } = await this.token.burn(amount, data, { from }); - expectEvent.inLogs(logs, 'Burned', { - operator: from, - from, - amount, - data, - operatorData: null, - }); - - const finalTotalSupply = await this.token.totalSupply(); - const finalFromBalance = await this.token.balanceOf(from); - - finalTotalSupply.sub(initialTotalSupply).should.be.bignumber.equal(amount.neg()); - finalFromBalance.sub(initialFromBalance).should.be.bignumber.equal(amount.neg()); - }); - } - - function assertOperatorBurnSuccess (from, operator, amount, data, operatorData) { - it(`operator can burn an amount of ${amount}`, async function () { - const initialTotalSupply = await this.token.totalSupply(); - const initialFromBalance = await this.token.balanceOf(from); - - const { logs } = await this.token.operatorBurn(from, amount, data, operatorData, { from: operator }); - expectEvent.inLogs(logs, 'Burned', { - operator, - from, - amount, - data, - operatorData, - }); - - const finalTotalSupply = await this.token.totalSupply(); - const finalFromBalance = await this.token.balanceOf(from); - - finalTotalSupply.sub(initialTotalSupply).should.be.bignumber.equal(amount.neg()); - finalFromBalance.sub(initialFromBalance).should.be.bignumber.equal(amount.neg()); - }); - } - before(async function () { this.erc1820 = await singletons.ERC1820Registry(registryFunder); }); @@ -169,114 +82,26 @@ contract.only('ERC777', function ([_, registryFunder, initialHolder, defaultOper }); describe('send', function () { - context('when the sender has no tokens', async function () { - const from = anyone; + shouldBehaveLikeERC777DirectSend(initialHolder, nonHolder, anyone, data); - describe('direct send', function () { - assertSendSuccess(from, initialHolder, new BN('0'), data); - - it('reverts when sending a non-zero amount', async function () { - await shouldFail.reverting(this.token.send(initialHolder, new BN('1'), data, { from })); - }); - }); - - describe('operator send', function () { - assertOperatorSendSuccess(from, defaultOperatorA, initialHolder, new BN('0'), data, operatorData); - - it('reverts when sending a non-zero amount', async function () { - await shouldFail.reverting( - this.token.operatorSend(from, initialHolder, new BN('1'), data, operatorData, { from: defaultOperatorA }) - ); - }); - }); + context('with first default operator', function () { + shouldBehaveLikeERC777OperatorSend(initialHolder, nonHolder, anyone, defaultOperatorA, data, operatorData); }); - context('when the sender has tokens', async function () { - const from = initialHolder; - - describe('direct send', function () { - assertSendSuccess(from, anyone, new BN('0'), data); - assertSendSuccess(from, anyone, new BN('1'), data); - - it('reverts when sending more than the balance', async function () { - const balance = await this.token.balanceOf(from); - await shouldFail.reverting(this.token.send(anyone, balance.addn(1), data, { from })); - }); - - it('reverts when sending to the zero address', async function () { - await shouldFail.reverting(this.token.send(ZERO_ADDRESS, new BN('1'), data, { from })); - }); - }); - - describe('operator send', function () { - assertOperatorSendSuccess(from, defaultOperatorA, anyone, new BN('0'), data, operatorData); - assertOperatorSendSuccess(from, defaultOperatorB, anyone, new BN('1'), data, operatorData); - - it('reverts when sending more than the balance', async function () { - const balance = await this.token.balanceOf(from); - await shouldFail.reverting( - this.token.operatorSend(from, anyone, balance.addn(1), data, operatorData, { from: defaultOperatorA }) - ); - }); - - it('reverts when sending to the zero address', async function () { - await shouldFail.reverting( - this.token.operatorSend( - from, ZERO_ADDRESS, new BN('1'), data, operatorData, { from: defaultOperatorA } - ) - ); - }); - }); + context('with second default operator', function () { + shouldBehaveLikeERC777OperatorSend(initialHolder, nonHolder, anyone, defaultOperatorB, data, operatorData); }); }); describe('burn', function () { - context('when the sender has no tokens', async function () { - const from = anyone; - - describe('direct burn', function () { - assertBurnSuccess(from, new BN('0'), data); - - it('reverts when burning a non-zero amount', async function () { - await shouldFail.reverting(this.token.burn(new BN('1'), data, { from })); - }); - }); - - describe('operator burn', function () { - assertOperatorBurnSuccess(from, defaultOperatorA, new BN('0'), data, operatorData); + shouldBehaveLikeERC777DirectBurn(initialHolder, nonHolder, data); - it('reverts when burning a non-zero amount', async function () { - await shouldFail.reverting( - this.token.operatorBurn(from, new BN('1'), data, operatorData, { from: defaultOperatorA }) - ); - }); - }); + context('with first default operator', function () { + shouldBehaveLikeERC777OperatorBurn(initialHolder, nonHolder, defaultOperatorA, data, operatorData); }); - context('when the sender has tokens', async function () { - const from = initialHolder; - - describe('direct burn', function () { - assertBurnSuccess(from, new BN('0'), data); - assertBurnSuccess(from, new BN('1'), data); - - it('reverts when burning more than the balance', async function () { - const balance = await this.token.balanceOf(from); - await shouldFail.reverting(this.token.burn(balance.addn(1), data, { from })); - }); - }); - - describe('operator burn', function () { - assertOperatorBurnSuccess(from, defaultOperatorA, new BN('0'), data, operatorData); - assertOperatorBurnSuccess(from, defaultOperatorB, new BN('1'), data, operatorData); - - it('reverts when burning more than the balance', async function () { - const balance = await this.token.balanceOf(from); - await shouldFail.reverting( - this.token.operatorBurn(from, balance.addn(1), data, operatorData, { from: defaultOperatorA }) - ); - }); - }); + context('with second default operator', function () { + shouldBehaveLikeERC777OperatorBurn(initialHolder, nonHolder, defaultOperatorB, data, operatorData); }); }); }); @@ -299,9 +124,9 @@ contract.only('ERC777', function ([_, registryFunder, initialHolder, defaultOper context('when the sender has tokens', function () { const from = initialHolder; - assertSendSuccess(from, anyone, new BN('0'), data); - assertSendSuccess(from, anyone, granularity, data); - assertSendSuccess(from, anyone, granularity.muln(2), data); + shouldSendTokens(from, anyone, new BN('0'), data); + shouldSendTokens(from, anyone, granularity, data); + shouldSendTokens(from, anyone, granularity.muln(2), data); it('reverts when sending an amount non-multiple of the granularity', async function () { await shouldFail.reverting(this.token.send(anyone, granularity.subn(1), data, { from })); From ee159b4825cd810617d7d8a5db79a2a1b839b75c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Wed, 27 Mar 2019 20:47:44 -0300 Subject: [PATCH 34/64] Improve send burn refactor. --- test/drafts/ERC777/ERC777.behavior.js | 135 +++++++++++++------------- test/drafts/ERC777/ERC777.test.js | 8 +- 2 files changed, 69 insertions(+), 74 deletions(-) diff --git a/test/drafts/ERC777/ERC777.behavior.js b/test/drafts/ERC777/ERC777.behavior.js index 2eec3c509cc..46272df4ed4 100644 --- a/test/drafts/ERC777/ERC777.behavior.js +++ b/test/drafts/ERC777/ERC777.behavior.js @@ -6,7 +6,7 @@ function shouldBehaveLikeERC777DirectSend (holder, nonHolder, recipient, data) { context('when the sender has no tokens', function () { const from = nonHolder; - shouldSendTokens(from, recipient, new BN('0'), data); + shouldDirectSendTokens(from, recipient, new BN('0'), data); it('reverts when sending a non-zero amount', async function () { await shouldFail.reverting(this.token.send(recipient, new BN('1'), data, { from })); @@ -16,8 +16,8 @@ function shouldBehaveLikeERC777DirectSend (holder, nonHolder, recipient, data) { context('when the sender has tokens', function () { const from = holder; - shouldSendTokens(from, recipient, new BN('0'), data); - shouldSendTokens(from, recipient, new BN('1'), data); + shouldDirectSendTokens(from, recipient, new BN('0'), data); + shouldDirectSendTokens(from, recipient, new BN('1'), data); it('reverts when sending more than the balance', async function () { const balance = await this.token.balanceOf(from); @@ -74,7 +74,7 @@ function shouldBehaveLikeERC777DirectBurn (holder, nonHolder, data) { context('when the sender has no tokens', function () { const from = nonHolder; - shouldBurnTokens(from, new BN('0'), data); + shouldDirectBurnTokens(from, new BN('0'), data); it('reverts when burning a non-zero amount', async function () { await shouldFail.reverting(this.token.burn(new BN('1'), data, { from })); @@ -84,8 +84,8 @@ function shouldBehaveLikeERC777DirectBurn (holder, nonHolder, data) { context('when the sender has tokens', function () { const from = holder; - shouldBurnTokens(from, new BN('0'), data); - shouldBurnTokens(from, new BN('1'), data); + shouldDirectBurnTokens(from, new BN('0'), data); + shouldDirectBurnTokens(from, new BN('1'), data); it('reverts when burning more than the balance', async function () { const balance = await this.token.balanceOf(from); @@ -125,47 +125,43 @@ function shouldBehaveLikeERC777OperatorBurn (holder, nonHolder, operator, data, }); } -function shouldSendTokens (from, to, amount, data) { - it(`can send an amount of ${amount}`, async function () { - const initialTotalSupply = await this.token.totalSupply(); - const initialFromBalance = await this.token.balanceOf(from); - const initialToBalance = await this.token.balanceOf(to); - - const { logs } = await this.token.send(to, amount, data, { from }); - expectEvent.inLogs(logs, 'Sent', { - operator: from, - from, - to, - amount, - data, - operatorData: null, - }); - - const finalTotalSupply = await this.token.totalSupply(); - const finalFromBalance = await this.token.balanceOf(from); - const finalToBalance = await this.token.balanceOf(to); - - finalTotalSupply.should.be.bignumber.equal(initialTotalSupply); - finalToBalance.sub(initialToBalance).should.be.bignumber.equal(amount); - finalFromBalance.sub(initialFromBalance).should.be.bignumber.equal(amount.neg()); - }); +function shouldDirectSendTokens (from, to, amount, data) { + shouldSendTokens(from, null, to, amount, data, null); } function shouldOperatorSendTokens (from, operator, to, amount, data, operatorData) { - it(`operator can send an amount of ${amount}`, async function () { + shouldSendTokens(from, operator, to, amount, data, operatorData); +} + +function shouldSendTokens (from, operator, to, amount, data, operatorData) { + const operatorCall = operator !== null; + + it(`${operatorCall ? 'operator ' : ''}can send an amount of ${amount}`, async function () { const initialTotalSupply = await this.token.totalSupply(); const initialFromBalance = await this.token.balanceOf(from); const initialToBalance = await this.token.balanceOf(to); - const { logs } = await this.token.operatorSend(from, to, amount, data, operatorData, { from: operator }); - expectEvent.inLogs(logs, 'Sent', { - operator, - from, - to, - amount, - data, - operatorData, - }); + if (!operatorCall) { + const { logs } = await this.token.send(to, amount, data, { from }); + expectEvent.inLogs(logs, 'Sent', { + operator: from, + from, + to, + amount, + data, + operatorData: null, + }); + } else { + const { logs } = await this.token.operatorSend(from, to, amount, data, operatorData, { from: operator }); + expectEvent.inLogs(logs, 'Sent', { + operator, + from, + to, + amount, + data, + operatorData, + }); + } const finalTotalSupply = await this.token.totalSupply(); const finalFromBalance = await this.token.balanceOf(from); @@ -177,41 +173,40 @@ function shouldOperatorSendTokens (from, operator, to, amount, data, operatorDat }); } -function shouldBurnTokens (from, amount, data) { - it(`can burn an amount of ${amount}`, async function () { - const initialTotalSupply = await this.token.totalSupply(); - const initialFromBalance = await this.token.balanceOf(from); - - const { logs } = await this.token.burn(amount, data, { from }); - expectEvent.inLogs(logs, 'Burned', { - operator: from, - from, - amount, - data, - operatorData: null, - }); - - const finalTotalSupply = await this.token.totalSupply(); - const finalFromBalance = await this.token.balanceOf(from); - - finalTotalSupply.sub(initialTotalSupply).should.be.bignumber.equal(amount.neg()); - finalFromBalance.sub(initialFromBalance).should.be.bignumber.equal(amount.neg()); - }); +function shouldDirectBurnTokens (from, amount, data) { + shouldBurnTokens(from, null, amount, data, null); } function shouldOperatorBurnTokens (from, operator, amount, data, operatorData) { - it(`operator can burn an amount of ${amount}`, async function () { + shouldBurnTokens(from, operator, amount, data, operatorData); +} + +function shouldBurnTokens (from, operator, amount, data, operatorData) { + const operatorCall = operator !== null; + + it(`${operatorCall ? 'operator ' : ''}can burn an amount of ${amount}`, async function () { const initialTotalSupply = await this.token.totalSupply(); const initialFromBalance = await this.token.balanceOf(from); - const { logs } = await this.token.operatorBurn(from, amount, data, operatorData, { from: operator }); - expectEvent.inLogs(logs, 'Burned', { - operator, - from, - amount, - data, - operatorData, - }); + if (!operatorCall) { + const { logs } = await this.token.burn(amount, data, { from }); + expectEvent.inLogs(logs, 'Burned', { + operator: from, + from, + amount, + data, + operatorData: null, + }); + } else { + const { logs } = await this.token.operatorBurn(from, amount, data, operatorData, { from: operator }); + expectEvent.inLogs(logs, 'Burned', { + operator, + from, + amount, + data, + operatorData, + }); + } const finalTotalSupply = await this.token.totalSupply(); const finalFromBalance = await this.token.balanceOf(from); @@ -226,5 +221,5 @@ module.exports = { shouldBehaveLikeERC777OperatorSend, shouldBehaveLikeERC777DirectBurn, shouldBehaveLikeERC777OperatorBurn, - shouldSendTokens, + shouldDirectSendTokens, }; diff --git a/test/drafts/ERC777/ERC777.test.js b/test/drafts/ERC777/ERC777.test.js index b177261297a..3bd51506749 100644 --- a/test/drafts/ERC777/ERC777.test.js +++ b/test/drafts/ERC777/ERC777.test.js @@ -5,7 +5,7 @@ const { shouldBehaveLikeERC777OperatorSend, shouldBehaveLikeERC777DirectBurn, shouldBehaveLikeERC777OperatorBurn, - shouldSendTokens, + shouldDirectSendTokens, } = require('./ERC777.behavior'); const ERC777 = artifacts.require('ERC777Mock'); @@ -124,9 +124,9 @@ contract('ERC777', function ([ context('when the sender has tokens', function () { const from = initialHolder; - shouldSendTokens(from, anyone, new BN('0'), data); - shouldSendTokens(from, anyone, granularity, data); - shouldSendTokens(from, anyone, granularity.muln(2), data); + shouldDirectSendTokens(from, anyone, new BN('0'), data); + shouldDirectSendTokens(from, anyone, granularity, data); + shouldDirectSendTokens(from, anyone, granularity.muln(2), data); it('reverts when sending an amount non-multiple of the granularity', async function () { await shouldFail.reverting(this.token.send(anyone, granularity.subn(1), data, { from })); From f9ada948bb1e2f32cd44ecaee59851853525f661 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Thu, 28 Mar 2019 03:29:30 -0300 Subject: [PATCH 35/64] Greatly improve test module. --- test/drafts/ERC777/ERC777.behavior.js | 124 +++++++++++++------------- test/drafts/ERC777/ERC777.test.js | 34 ++++--- 2 files changed, 83 insertions(+), 75 deletions(-) diff --git a/test/drafts/ERC777/ERC777.behavior.js b/test/drafts/ERC777/ERC777.behavior.js index 46272df4ed4..5112e1e6d26 100644 --- a/test/drafts/ERC777/ERC777.behavior.js +++ b/test/drafts/ERC777/ERC777.behavior.js @@ -1,124 +1,117 @@ const { BN, constants, expectEvent, shouldFail } = require('openzeppelin-test-helpers'); const { ZERO_ADDRESS } = constants; +const OWNERLESS_ADDRESS = '0x0000000000000000000000000000000000000001'; -function shouldBehaveLikeERC777DirectSend (holder, nonHolder, recipient, data) { +function shouldBehaveLikeERC777DirectSend (holder, recipient, data) { describe('direct send', function () { - context('when the sender has no tokens', function () { - const from = nonHolder; - - shouldDirectSendTokens(from, recipient, new BN('0'), data); - - it('reverts when sending a non-zero amount', async function () { - await shouldFail.reverting(this.token.send(recipient, new BN('1'), data, { from })); - }); - }); - context('when the sender has tokens', function () { - const from = holder; - - shouldDirectSendTokens(from, recipient, new BN('0'), data); - shouldDirectSendTokens(from, recipient, new BN('1'), data); + shouldDirectSendTokens(holder, recipient, new BN('0'), data); + shouldDirectSendTokens(holder, recipient, new BN('1'), data); it('reverts when sending more than the balance', async function () { - const balance = await this.token.balanceOf(from); - await shouldFail.reverting(this.token.send(recipient, balance.addn(1), data, { from })); + const balance = await this.token.balanceOf(holder); + await shouldFail.reverting(this.token.send(recipient, balance.addn(1), data, { from: holder })); }); it('reverts when sending to the zero address', async function () { - await shouldFail.reverting(this.token.send(ZERO_ADDRESS, new BN('1'), data, { from })); + await shouldFail.reverting(this.token.send(ZERO_ADDRESS, new BN('1'), data, { from: holder })); }); }); - }); -} -function shouldBehaveLikeERC777OperatorSend (holder, nonHolder, recipient, operator, data, operatorData) { - describe('operator send', function () { context('when the sender has no tokens', function () { - const from = nonHolder; + removeBalance(holder); - shouldOperatorSendTokens(from, operator, recipient, new BN('0'), data, operatorData); + shouldDirectSendTokens(holder, recipient, new BN('0'), data); it('reverts when sending a non-zero amount', async function () { - await shouldFail.reverting( - this.token.operatorSend(from, recipient, new BN('1'), data, operatorData, { from: operator }) - ); + await shouldFail.reverting(this.token.send(recipient, new BN('1'), data, { from: holder })); }); }); + }); +} +function shouldBehaveLikeERC777OperatorSend (holder, recipient, operator, data, operatorData) { + describe('operator send', function () { context('when the sender has tokens', async function () { - const from = holder; - - shouldOperatorSendTokens(from, operator, recipient, new BN('0'), data, operatorData); - shouldOperatorSendTokens(from, operator, recipient, new BN('1'), data, operatorData); + shouldOperatorSendTokens(holder, operator, recipient, new BN('0'), data, operatorData); + shouldOperatorSendTokens(holder, operator, recipient, new BN('1'), data, operatorData); it('reverts when sending more than the balance', async function () { - const balance = await this.token.balanceOf(from); + const balance = await this.token.balanceOf(holder); await shouldFail.reverting( - this.token.operatorSend(from, recipient, balance.addn(1), data, operatorData, { from: operator }) + this.token.operatorSend(holder, recipient, balance.addn(1), data, operatorData, { from: operator }) ); }); it('reverts when sending to the zero address', async function () { await shouldFail.reverting( this.token.operatorSend( - from, ZERO_ADDRESS, new BN('1'), data, operatorData, { from: operator } + holder, ZERO_ADDRESS, new BN('1'), data, operatorData, { from: operator } ) ); }); }); - }); -} -function shouldBehaveLikeERC777DirectBurn (holder, nonHolder, data) { - describe('direct burn', function () { context('when the sender has no tokens', function () { - const from = nonHolder; + removeBalance(holder); - shouldDirectBurnTokens(from, new BN('0'), data); + shouldOperatorSendTokens(holder, operator, recipient, new BN('0'), data, operatorData); - it('reverts when burning a non-zero amount', async function () { - await shouldFail.reverting(this.token.burn(new BN('1'), data, { from })); + it('reverts when sending a non-zero amount', async function () { + await shouldFail.reverting( + this.token.operatorSend(holder, recipient, new BN('1'), data, operatorData, { from: operator }) + ); }); }); + }); +} +function shouldBehaveLikeERC777DirectBurn (holder, data) { + describe('direct burn', function () { context('when the sender has tokens', function () { - const from = holder; - - shouldDirectBurnTokens(from, new BN('0'), data); - shouldDirectBurnTokens(from, new BN('1'), data); + shouldDirectBurnTokens(holder, new BN('0'), data); + shouldDirectBurnTokens(holder, new BN('1'), data); it('reverts when burning more than the balance', async function () { - const balance = await this.token.balanceOf(from); - await shouldFail.reverting(this.token.burn(balance.addn(1), data, { from })); + const balance = await this.token.balanceOf(holder); + await shouldFail.reverting(this.token.burn(balance.addn(1), data, { from: holder })); }); }); - }); -} -function shouldBehaveLikeERC777OperatorBurn (holder, nonHolder, operator, data, operatorData) { - describe('operator burn', function () { context('when the sender has no tokens', function () { - const from = nonHolder; + removeBalance(holder); - shouldOperatorBurnTokens(from, operator, new BN('0'), data, operatorData); + shouldDirectBurnTokens(holder, new BN('0'), data); it('reverts when burning a non-zero amount', async function () { + await shouldFail.reverting(this.token.burn(new BN('1'), data, { from: holder })); + }); + }); + }); +} + +function shouldBehaveLikeERC777OperatorBurn (holder, operator, data, operatorData) { + describe('operator burn', function () { + context('when the sender has tokens', async function () { + shouldOperatorBurnTokens(holder, operator, new BN('0'), data, operatorData); + shouldOperatorBurnTokens(holder, operator, new BN('1'), data, operatorData); + + it('reverts when burning more than the balance', async function () { + const balance = await this.token.balanceOf(holder); await shouldFail.reverting( - this.token.operatorBurn(from, new BN('1'), data, operatorData, { from: operator }) + this.token.operatorBurn(holder, balance.addn(1), data, operatorData, { from: operator }) ); }); }); - context('when the sender has tokens', async function () { - const from = holder; + context('when the sender has no tokens', function () { + removeBalance(holder); - shouldOperatorBurnTokens(from, operator, new BN('0'), data, operatorData); - shouldOperatorBurnTokens(from, operator, new BN('1'), data, operatorData); + shouldOperatorBurnTokens(holder, operator, new BN('0'), data, operatorData); - it('reverts when burning more than the balance', async function () { - const balance = await this.token.balanceOf(from); + it('reverts when burning a non-zero amount', async function () { await shouldFail.reverting( - this.token.operatorBurn(from, balance.addn(1), data, operatorData, { from: operator }) + this.token.operatorBurn(holder, new BN('1'), data, operatorData, { from: operator }) ); }); }); @@ -216,6 +209,13 @@ function shouldBurnTokens (from, operator, amount, data, operatorData) { }); } +function removeBalance (holder) { + beforeEach(async function () { + await this.token.send(OWNERLESS_ADDRESS, await this.token.balanceOf(holder), '0x', { from: holder }); + (await this.token.balanceOf(holder)).should.be.bignumber.equal('0'); + }); +} + module.exports = { shouldBehaveLikeERC777DirectSend, shouldBehaveLikeERC777OperatorSend, diff --git a/test/drafts/ERC777/ERC777.test.js b/test/drafts/ERC777/ERC777.test.js index 3bd51506749..721a9e207cb 100644 --- a/test/drafts/ERC777/ERC777.test.js +++ b/test/drafts/ERC777/ERC777.test.js @@ -11,7 +11,7 @@ const { const ERC777 = artifacts.require('ERC777Mock'); contract('ERC777', function ([ - _, registryFunder, initialHolder, nonHolder, defaultOperatorA, defaultOperatorB, newOperator, anyone, + _, registryFunder, holder, defaultOperatorA, defaultOperatorB, newOperator, anyone, ]) { const initialSupply = new BN('10000'); const name = 'ERC777Test'; @@ -26,12 +26,12 @@ contract('ERC777', function ([ }); it('reverts with a granularity of zero', async function () { - await shouldFail.reverting(ERC777.new(initialHolder, initialSupply, name, symbol, 0, [])); + await shouldFail.reverting(ERC777.new(holder, initialSupply, name, symbol, 0, [])); }); context('with default operators', function () { beforeEach(async function () { - this.token = await ERC777.new(initialHolder, initialSupply, name, symbol, 1, defaultOperators); + this.token = await ERC777.new(holder, initialSupply, name, symbol, 1, defaultOperators); }); describe('basic information', function () { @@ -76,39 +76,47 @@ contract('ERC777', function ([ context('for an account with tokens', function () { it('returns their balance', async function () { - (await this.token.balanceOf(initialHolder)).should.be.bignumber.equal(initialSupply); + (await this.token.balanceOf(holder)).should.be.bignumber.equal(initialSupply); }); }); }); describe('send', function () { - shouldBehaveLikeERC777DirectSend(initialHolder, nonHolder, anyone, data); + shouldBehaveLikeERC777DirectSend(holder, anyone, data); + + context('with self operator', function () { + shouldBehaveLikeERC777OperatorSend(holder, anyone, holder, data, operatorData); + }); context('with first default operator', function () { - shouldBehaveLikeERC777OperatorSend(initialHolder, nonHolder, anyone, defaultOperatorA, data, operatorData); + shouldBehaveLikeERC777OperatorSend(holder, anyone, defaultOperatorA, data, operatorData); }); context('with second default operator', function () { - shouldBehaveLikeERC777OperatorSend(initialHolder, nonHolder, anyone, defaultOperatorB, data, operatorData); + shouldBehaveLikeERC777OperatorSend(holder, anyone, defaultOperatorB, data, operatorData); }); }); describe('burn', function () { - shouldBehaveLikeERC777DirectBurn(initialHolder, nonHolder, data); + shouldBehaveLikeERC777DirectBurn(holder, data); + + context('with self operator', function () { + shouldBehaveLikeERC777OperatorBurn(holder, holder, data, operatorData); + }); context('with first default operator', function () { - shouldBehaveLikeERC777OperatorBurn(initialHolder, nonHolder, defaultOperatorA, data, operatorData); + shouldBehaveLikeERC777OperatorBurn(holder, defaultOperatorA, data, operatorData); }); context('with second default operator', function () { - shouldBehaveLikeERC777OperatorBurn(initialHolder, nonHolder, defaultOperatorB, data, operatorData); + shouldBehaveLikeERC777OperatorBurn(holder, defaultOperatorB, data, operatorData); }); }); }); context('with no default operators', function () { beforeEach(async function () { - await shouldFail.reverting(ERC777.new(initialHolder, initialSupply, name, symbol, 1, [])); + await shouldFail.reverting(ERC777.new(holder, initialSupply, name, symbol, 1, [])); }); }); @@ -118,11 +126,11 @@ contract('ERC777', function ([ beforeEach(async function () { initialSupply.mod(granularity).should.be.bignumber.equal('0'); - this.token = await ERC777.new(initialHolder, initialSupply, name, symbol, granularity, defaultOperators); + this.token = await ERC777.new(holder, initialSupply, name, symbol, granularity, defaultOperators); }); context('when the sender has tokens', function () { - const from = initialHolder; + const from = holder; shouldDirectSendTokens(from, anyone, new BN('0'), data); shouldDirectSendTokens(from, anyone, granularity, data); From 37ad5d5b270f209cc072bdd2697a29c2c70f4723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Thu, 28 Mar 2019 15:14:49 -0300 Subject: [PATCH 36/64] Burn instead of send removed tokens. --- test/drafts/ERC777/ERC777.behavior.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/drafts/ERC777/ERC777.behavior.js b/test/drafts/ERC777/ERC777.behavior.js index 5112e1e6d26..aed3baa452c 100644 --- a/test/drafts/ERC777/ERC777.behavior.js +++ b/test/drafts/ERC777/ERC777.behavior.js @@ -1,6 +1,5 @@ const { BN, constants, expectEvent, shouldFail } = require('openzeppelin-test-helpers'); const { ZERO_ADDRESS } = constants; -const OWNERLESS_ADDRESS = '0x0000000000000000000000000000000000000001'; function shouldBehaveLikeERC777DirectSend (holder, recipient, data) { describe('direct send', function () { @@ -211,7 +210,7 @@ function shouldBurnTokens (from, operator, amount, data, operatorData) { function removeBalance (holder) { beforeEach(async function () { - await this.token.send(OWNERLESS_ADDRESS, await this.token.balanceOf(holder), '0x', { from: holder }); + await this.token.burn(await this.token.balanceOf(holder), '0x', { from: holder }); (await this.token.balanceOf(holder)).should.be.bignumber.equal('0'); }); } From a76a1cc7d787825c131d8828aada598a3a501a19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Thu, 28 Mar 2019 17:07:13 -0300 Subject: [PATCH 37/64] Add operator tests. --- test/drafts/ERC777/ERC777.behavior.js | 9 +++ test/drafts/ERC777/ERC777.test.js | 111 +++++++++++++++++++++++++- 2 files changed, 118 insertions(+), 2 deletions(-) diff --git a/test/drafts/ERC777/ERC777.behavior.js b/test/drafts/ERC777/ERC777.behavior.js index aed3baa452c..4e3353b75de 100644 --- a/test/drafts/ERC777/ERC777.behavior.js +++ b/test/drafts/ERC777/ERC777.behavior.js @@ -65,6 +65,14 @@ function shouldBehaveLikeERC777OperatorSend (holder, recipient, operator, data, }); } +function shouldBehaveLikeERC777UnauthorizedOperatorSend (holder, recipient, operator, data, operatorData) { + describe('operator send', function () { + it('reverts', async function () { + await shouldFail.reverting(this.token.operatorSend(holder, recipient, new BN('0'), data, operatorData)); + }); + }); +} + function shouldBehaveLikeERC777DirectBurn (holder, data) { describe('direct burn', function () { context('when the sender has tokens', function () { @@ -218,6 +226,7 @@ function removeBalance (holder) { module.exports = { shouldBehaveLikeERC777DirectSend, shouldBehaveLikeERC777OperatorSend, + shouldBehaveLikeERC777UnauthorizedOperatorSend, shouldBehaveLikeERC777DirectBurn, shouldBehaveLikeERC777OperatorBurn, shouldDirectSendTokens, diff --git a/test/drafts/ERC777/ERC777.test.js b/test/drafts/ERC777/ERC777.test.js index 721a9e207cb..d562dd3f849 100644 --- a/test/drafts/ERC777/ERC777.test.js +++ b/test/drafts/ERC777/ERC777.test.js @@ -1,8 +1,9 @@ -const { BN, shouldFail, singletons } = require('openzeppelin-test-helpers'); +const { BN, expectEvent, shouldFail, singletons } = require('openzeppelin-test-helpers'); const { shouldBehaveLikeERC777DirectSend, shouldBehaveLikeERC777OperatorSend, + shouldBehaveLikeERC777UnauthorizedOperatorSend, shouldBehaveLikeERC777DirectBurn, shouldBehaveLikeERC777OperatorBurn, shouldDirectSendTokens, @@ -95,6 +96,20 @@ contract('ERC777', function ([ context('with second default operator', function () { shouldBehaveLikeERC777OperatorSend(holder, anyone, defaultOperatorB, data, operatorData); }); + + describe('changing operators', function () { + context('before authorizing', function () { + shouldBehaveLikeERC777UnauthorizedOperatorSend(holder, anyone, newOperator, data, operatorData); + }); + + context('with authorization', function () { + beforeEach(async function () { + await this.token.authorizeOperator(newOperator, { from: holder }); + }); + + shouldBehaveLikeERC777OperatorSend(holder, anyone, newOperator, data, operatorData); + }); + }); }); describe('burn', function () { @@ -112,11 +127,103 @@ contract('ERC777', function ([ shouldBehaveLikeERC777OperatorBurn(holder, defaultOperatorB, data, operatorData); }); }); + + describe('operator management', function () { + it('accounts are their own operator', async function () { + (await this.token.isOperatorFor(holder, holder)).should.equal(true); + }); + + it('reverts when self-authorizing', async function () { + await shouldFail.reverting(this.token.authorizeOperator(holder, { from: holder })); + }); + + it('reverts when self-revoking', async function () { + await shouldFail.reverting(this.token.revokeOperator(holder, { from: holder })); + }); + + it('non-operators can be authorized', async function () { + (await this.token.isOperatorFor(newOperator, holder)).should.equal(false); + + const { logs } = await this.token.authorizeOperator(newOperator, { from: holder }); + expectEvent.inLogs(logs, 'AuthorizedOperator', { operator: newOperator, tokenHolder: holder }); + + (await this.token.isOperatorFor(newOperator, holder)).should.equal(true); + }); + + describe('new operators', function () { + beforeEach(async function () { + await this.token.authorizeOperator(newOperator, { from: holder }); + }); + + it('are not added to the default operators list', async function () { + (await this.token.defaultOperators()).should.deep.equal(defaultOperators); + }); + + it('can be re-authorized', async function () { + const { logs } = await this.token.authorizeOperator(newOperator, { from: holder }); + expectEvent.inLogs(logs, 'AuthorizedOperator', { operator: newOperator, tokenHolder: holder }); + + (await this.token.isOperatorFor(newOperator, holder)).should.equal(true); + }); + + it('can be revoked', async function () { + const { logs } = await this.token.revokeOperator(newOperator, { from: holder }); + expectEvent.inLogs(logs, 'RevokedOperator', { operator: newOperator, tokenHolder: holder }); + + (await this.token.isOperatorFor(newOperator, holder)).should.equal(false); + }); + }); + + describe('default operators', function () { + it('can be re-authorized', async function () { + const { logs } = await this.token.authorizeOperator(defaultOperatorA, { from: holder }); + expectEvent.inLogs(logs, 'AuthorizedOperator', { operator: defaultOperatorA, tokenHolder: holder }); + + (await this.token.isOperatorFor(defaultOperatorA, holder)).should.equal(true); + }); + + it('can be revoked', async function () { + const { logs } = await this.token.revokeOperator(defaultOperatorA, { from: holder }); + expectEvent.inLogs(logs, 'RevokedOperator', { operator: defaultOperatorA, tokenHolder: holder }); + + (await this.token.isOperatorFor(defaultOperatorA, holder)).should.equal(false); + }); + + context('with revoked default operator', function () { + beforeEach(async function () { + await this.token.revokeOperator(defaultOperatorA, { from: holder }); + }); + + it('default operator is not revoked for other holders', async function () { + (await this.token.isOperatorFor(defaultOperatorA, anyone)).should.equal(true); + }); + + it('other default operators are not revoked', async function () { + (await this.token.isOperatorFor(defaultOperatorB, holder)).should.equal(true); + }); + + it('default operators list is not modified', async function () { + (await this.token.defaultOperators()).should.deep.equal(defaultOperators); + }); + + it('revoked default operator can be re-authorized', async function () { + const { logs } = await this.token.authorizeOperator(defaultOperatorA, { from: holder }); + expectEvent.inLogs(logs, 'AuthorizedOperator', { operator: defaultOperatorA, tokenHolder: holder }); + + (await this.token.isOperatorFor(defaultOperatorA, holder)).should.equal(true); + }); + }); + }); + }); }); context('with no default operators', function () { beforeEach(async function () { - await shouldFail.reverting(ERC777.new(holder, initialSupply, name, symbol, 1, [])); + this.token = await ERC777.new(holder, initialSupply, name, symbol, 1, []); + }); + + it('default operators list is empty', async function () { + (await this.token.defaultOperators()).should.deep.equal([]); }); }); From 18231084372c7128da0af44bc93dd66bd78cbd7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Thu, 28 Mar 2019 17:15:24 -0300 Subject: [PATCH 38/64] Improve send tests under changing operators. --- test/drafts/ERC777/ERC777.test.js | 264 ++++++++++++++++-------------- 1 file changed, 137 insertions(+), 127 deletions(-) diff --git a/test/drafts/ERC777/ERC777.test.js b/test/drafts/ERC777/ERC777.test.js index d562dd3f849..ffefa47d81d 100644 --- a/test/drafts/ERC777/ERC777.test.js +++ b/test/drafts/ERC777/ERC777.test.js @@ -30,200 +30,210 @@ contract('ERC777', function ([ await shouldFail.reverting(ERC777.new(holder, initialSupply, name, symbol, 0, [])); }); - context('with default operators', function () { - beforeEach(async function () { - this.token = await ERC777.new(holder, initialSupply, name, symbol, 1, defaultOperators); - }); + context('with a granularity of one', function () { + const granularity = new BN('1'); - describe('basic information', function () { - it('returns the name', async function () { - (await this.token.name()).should.equal(name); + context('with default operators', function () { + beforeEach(async function () { + this.token = await ERC777.new(holder, initialSupply, name, symbol, 1, defaultOperators); }); - it('returns the symbol', async function () { - (await this.token.symbol()).should.equal(symbol); - }); + describe('basic information', function () { + it('returns the name', async function () { + (await this.token.name()).should.equal(name); + }); - it('returns the granularity', async function () { - (await this.token.granularity()).should.be.bignumber.equal('1'); - }); + it('returns the symbol', async function () { + (await this.token.symbol()).should.equal(symbol); + }); - it('returns the default operators', async function () { - (await this.token.defaultOperators()).should.deep.equal(defaultOperators); - }); + it('returns the granularity', async function () { + (await this.token.granularity()).should.be.bignumber.equal('1'); + }); - it('default operators are operators for all accounts', async function () { - for (const operator of defaultOperators) { - (await this.token.isOperatorFor(operator, anyone)).should.equal(true); - } - }); + it('returns the default operators', async function () { + (await this.token.defaultOperators()).should.deep.equal(defaultOperators); + }); - it('returns thte total supply', async function () { - (await this.token.totalSupply()).should.be.bignumber.equal(initialSupply); - }); + it('default operators are operators for all accounts', async function () { + for (const operator of defaultOperators) { + (await this.token.isOperatorFor(operator, anyone)).should.equal(true); + } + }); - it('is registered in the registry', async function () { - (await this.erc1820.getInterfaceImplementer(this.token.address, web3.utils.soliditySha3('ERC777Token'))) - .should.equal(this.token.address); - }); - }); + it('returns thte total supply', async function () { + (await this.token.totalSupply()).should.be.bignumber.equal(initialSupply); + }); - describe('balanceOf', function () { - context('for an account with no tokens', function () { - it('returns zero', async function () { - (await this.token.balanceOf(anyone)).should.be.bignumber.equal('0'); + it('is registered in the registry', async function () { + (await this.erc1820.getInterfaceImplementer(this.token.address, web3.utils.soliditySha3('ERC777Token'))) + .should.equal(this.token.address); }); }); - context('for an account with tokens', function () { - it('returns their balance', async function () { - (await this.token.balanceOf(holder)).should.be.bignumber.equal(initialSupply); + describe('balanceOf', function () { + context('for an account with no tokens', function () { + it('returns zero', async function () { + (await this.token.balanceOf(anyone)).should.be.bignumber.equal('0'); + }); + }); + + context('for an account with tokens', function () { + it('returns their balance', async function () { + (await this.token.balanceOf(holder)).should.be.bignumber.equal(initialSupply); + }); }); }); - }); - describe('send', function () { - shouldBehaveLikeERC777DirectSend(holder, anyone, data); + describe('send', function () { + shouldBehaveLikeERC777DirectSend(holder, anyone, data); - context('with self operator', function () { - shouldBehaveLikeERC777OperatorSend(holder, anyone, holder, data, operatorData); - }); + context('with self operator', function () { + shouldBehaveLikeERC777OperatorSend(holder, anyone, holder, data, operatorData); + }); - context('with first default operator', function () { - shouldBehaveLikeERC777OperatorSend(holder, anyone, defaultOperatorA, data, operatorData); - }); + context('with first default operator', function () { + shouldBehaveLikeERC777OperatorSend(holder, anyone, defaultOperatorA, data, operatorData); + }); - context('with second default operator', function () { - shouldBehaveLikeERC777OperatorSend(holder, anyone, defaultOperatorB, data, operatorData); - }); + context('with second default operator', function () { + shouldBehaveLikeERC777OperatorSend(holder, anyone, defaultOperatorB, data, operatorData); + }); - describe('changing operators', function () { - context('before authorizing', function () { + context('before authorizing a new operator', function () { shouldBehaveLikeERC777UnauthorizedOperatorSend(holder, anyone, newOperator, data, operatorData); }); - context('with authorization', function () { + context('with new authorized operator', function () { beforeEach(async function () { await this.token.authorizeOperator(newOperator, { from: holder }); }); shouldBehaveLikeERC777OperatorSend(holder, anyone, newOperator, data, operatorData); - }); - }); - }); - describe('burn', function () { - shouldBehaveLikeERC777DirectBurn(holder, data); + context('with revoked operator', function () { + beforeEach(async function () { + await this.token.revokeOperator(newOperator, { from: holder }); + }); - context('with self operator', function () { - shouldBehaveLikeERC777OperatorBurn(holder, holder, data, operatorData); + shouldBehaveLikeERC777UnauthorizedOperatorSend(holder, anyone, newOperator, data, operatorData); + }); + }); }); - context('with first default operator', function () { - shouldBehaveLikeERC777OperatorBurn(holder, defaultOperatorA, data, operatorData); - }); + describe('burn', function () { + shouldBehaveLikeERC777DirectBurn(holder, data); - context('with second default operator', function () { - shouldBehaveLikeERC777OperatorBurn(holder, defaultOperatorB, data, operatorData); - }); - }); - - describe('operator management', function () { - it('accounts are their own operator', async function () { - (await this.token.isOperatorFor(holder, holder)).should.equal(true); - }); + context('with self operator', function () { + shouldBehaveLikeERC777OperatorBurn(holder, holder, data, operatorData); + }); - it('reverts when self-authorizing', async function () { - await shouldFail.reverting(this.token.authorizeOperator(holder, { from: holder })); - }); + context('with first default operator', function () { + shouldBehaveLikeERC777OperatorBurn(holder, defaultOperatorA, data, operatorData); + }); - it('reverts when self-revoking', async function () { - await shouldFail.reverting(this.token.revokeOperator(holder, { from: holder })); + context('with second default operator', function () { + shouldBehaveLikeERC777OperatorBurn(holder, defaultOperatorB, data, operatorData); + }); }); - it('non-operators can be authorized', async function () { - (await this.token.isOperatorFor(newOperator, holder)).should.equal(false); - - const { logs } = await this.token.authorizeOperator(newOperator, { from: holder }); - expectEvent.inLogs(logs, 'AuthorizedOperator', { operator: newOperator, tokenHolder: holder }); - - (await this.token.isOperatorFor(newOperator, holder)).should.equal(true); - }); + describe('operator management', function () { + it('accounts are their own operator', async function () { + (await this.token.isOperatorFor(holder, holder)).should.equal(true); + }); - describe('new operators', function () { - beforeEach(async function () { - await this.token.authorizeOperator(newOperator, { from: holder }); + it('reverts when self-authorizing', async function () { + await shouldFail.reverting(this.token.authorizeOperator(holder, { from: holder })); }); - it('are not added to the default operators list', async function () { - (await this.token.defaultOperators()).should.deep.equal(defaultOperators); + it('reverts when self-revoking', async function () { + await shouldFail.reverting(this.token.revokeOperator(holder, { from: holder })); }); - it('can be re-authorized', async function () { + it('non-operators can be authorized', async function () { + (await this.token.isOperatorFor(newOperator, holder)).should.equal(false); + const { logs } = await this.token.authorizeOperator(newOperator, { from: holder }); expectEvent.inLogs(logs, 'AuthorizedOperator', { operator: newOperator, tokenHolder: holder }); (await this.token.isOperatorFor(newOperator, holder)).should.equal(true); }); - it('can be revoked', async function () { - const { logs } = await this.token.revokeOperator(newOperator, { from: holder }); - expectEvent.inLogs(logs, 'RevokedOperator', { operator: newOperator, tokenHolder: holder }); + describe('new operators', function () { + beforeEach(async function () { + await this.token.authorizeOperator(newOperator, { from: holder }); + }); - (await this.token.isOperatorFor(newOperator, holder)).should.equal(false); - }); - }); + it('are not added to the default operators list', async function () { + (await this.token.defaultOperators()).should.deep.equal(defaultOperators); + }); - describe('default operators', function () { - it('can be re-authorized', async function () { - const { logs } = await this.token.authorizeOperator(defaultOperatorA, { from: holder }); - expectEvent.inLogs(logs, 'AuthorizedOperator', { operator: defaultOperatorA, tokenHolder: holder }); + it('can be re-authorized', async function () { + const { logs } = await this.token.authorizeOperator(newOperator, { from: holder }); + expectEvent.inLogs(logs, 'AuthorizedOperator', { operator: newOperator, tokenHolder: holder }); - (await this.token.isOperatorFor(defaultOperatorA, holder)).should.equal(true); - }); + (await this.token.isOperatorFor(newOperator, holder)).should.equal(true); + }); - it('can be revoked', async function () { - const { logs } = await this.token.revokeOperator(defaultOperatorA, { from: holder }); - expectEvent.inLogs(logs, 'RevokedOperator', { operator: defaultOperatorA, tokenHolder: holder }); + it('can be revoked', async function () { + const { logs } = await this.token.revokeOperator(newOperator, { from: holder }); + expectEvent.inLogs(logs, 'RevokedOperator', { operator: newOperator, tokenHolder: holder }); - (await this.token.isOperatorFor(defaultOperatorA, holder)).should.equal(false); + (await this.token.isOperatorFor(newOperator, holder)).should.equal(false); + }); }); - context('with revoked default operator', function () { - beforeEach(async function () { - await this.token.revokeOperator(defaultOperatorA, { from: holder }); - }); + describe('default operators', function () { + it('can be re-authorized', async function () { + const { logs } = await this.token.authorizeOperator(defaultOperatorA, { from: holder }); + expectEvent.inLogs(logs, 'AuthorizedOperator', { operator: defaultOperatorA, tokenHolder: holder }); - it('default operator is not revoked for other holders', async function () { - (await this.token.isOperatorFor(defaultOperatorA, anyone)).should.equal(true); + (await this.token.isOperatorFor(defaultOperatorA, holder)).should.equal(true); }); - it('other default operators are not revoked', async function () { - (await this.token.isOperatorFor(defaultOperatorB, holder)).should.equal(true); - }); + it('can be revoked', async function () { + const { logs } = await this.token.revokeOperator(defaultOperatorA, { from: holder }); + expectEvent.inLogs(logs, 'RevokedOperator', { operator: defaultOperatorA, tokenHolder: holder }); - it('default operators list is not modified', async function () { - (await this.token.defaultOperators()).should.deep.equal(defaultOperators); + (await this.token.isOperatorFor(defaultOperatorA, holder)).should.equal(false); }); - it('revoked default operator can be re-authorized', async function () { - const { logs } = await this.token.authorizeOperator(defaultOperatorA, { from: holder }); - expectEvent.inLogs(logs, 'AuthorizedOperator', { operator: defaultOperatorA, tokenHolder: holder }); + context('with revoked default operator', function () { + beforeEach(async function () { + await this.token.revokeOperator(defaultOperatorA, { from: holder }); + }); - (await this.token.isOperatorFor(defaultOperatorA, holder)).should.equal(true); + it('default operator is not revoked for other holders', async function () { + (await this.token.isOperatorFor(defaultOperatorA, anyone)).should.equal(true); + }); + + it('other default operators are not revoked', async function () { + (await this.token.isOperatorFor(defaultOperatorB, holder)).should.equal(true); + }); + + it('default operators list is not modified', async function () { + (await this.token.defaultOperators()).should.deep.equal(defaultOperators); + }); + + it('revoked default operator can be re-authorized', async function () { + const { logs } = await this.token.authorizeOperator(defaultOperatorA, { from: holder }); + expectEvent.inLogs(logs, 'AuthorizedOperator', { operator: defaultOperatorA, tokenHolder: holder }); + + (await this.token.isOperatorFor(defaultOperatorA, holder)).should.equal(true); + }); }); }); }); }); - }); - context('with no default operators', function () { - beforeEach(async function () { - this.token = await ERC777.new(holder, initialSupply, name, symbol, 1, []); - }); + context('with no default operators', function () { + beforeEach(async function () { + this.token = await ERC777.new(holder, initialSupply, name, symbol, 1, []); + }); - it('default operators list is empty', async function () { - (await this.token.defaultOperators()).should.deep.equal([]); + it('default operators list is empty', async function () { + (await this.token.defaultOperators()).should.deep.equal([]); + }); }); }); From 0e78a624f9b22025b1ed22624cc2af2db51bf962 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Thu, 28 Mar 2019 17:26:50 -0300 Subject: [PATCH 39/64] Refactor and merge send and burn tests. --- test/drafts/ERC777/ERC777.behavior.js | 31 ++++++++++++++++---- test/drafts/ERC777/ERC777.test.js | 42 ++++++++------------------- 2 files changed, 38 insertions(+), 35 deletions(-) diff --git a/test/drafts/ERC777/ERC777.behavior.js b/test/drafts/ERC777/ERC777.behavior.js index 4e3353b75de..8464a49e328 100644 --- a/test/drafts/ERC777/ERC777.behavior.js +++ b/test/drafts/ERC777/ERC777.behavior.js @@ -1,6 +1,21 @@ const { BN, constants, expectEvent, shouldFail } = require('openzeppelin-test-helpers'); const { ZERO_ADDRESS } = constants; +function shouldBehaveLikeERC777DirectSendBurn (holder, recipient, data) { + shouldBehaveLikeERC777DirectSend(holder, recipient, data); + shouldBehaveLikeERC777DirectBurn(holder, data); +} + +function shouldBehaveLikeERC777OperatorSendBurn (holder, recipient, operator, data, operatorData) { + shouldBehaveLikeERC777OperatorSend(holder, recipient, operator, data, operatorData); + shouldBehaveLikeERC777OperatorBurn(holder, operator, data, operatorData); +} + +function shouldBehaveLikeERC777UnauthorizedOperatorSendBurn (holder, recipient, operator, data, operatorData) { + shouldBehaveLikeERC777UnauthorizedOperatorSend(holder, recipient, operator, data, operatorData); + shouldBehaveLikeERC777UnauthorizedOperatorBurn(holder, operator, data, operatorData); +} + function shouldBehaveLikeERC777DirectSend (holder, recipient, data) { describe('direct send', function () { context('when the sender has tokens', function () { @@ -125,6 +140,14 @@ function shouldBehaveLikeERC777OperatorBurn (holder, operator, data, operatorDat }); } +function shouldBehaveLikeERC777UnauthorizedOperatorBurn (holder, operator, data, operatorData) { + describe('operator burn', function () { + it('reverts', async function () { + await shouldFail.reverting(this.token.operatorBurn(holder, new BN('0'), data, operatorData)); + }); + }); +} + function shouldDirectSendTokens (from, to, amount, data) { shouldSendTokens(from, null, to, amount, data, null); } @@ -224,10 +247,8 @@ function removeBalance (holder) { } module.exports = { - shouldBehaveLikeERC777DirectSend, - shouldBehaveLikeERC777OperatorSend, - shouldBehaveLikeERC777UnauthorizedOperatorSend, - shouldBehaveLikeERC777DirectBurn, - shouldBehaveLikeERC777OperatorBurn, + shouldBehaveLikeERC777DirectSendBurn, + shouldBehaveLikeERC777OperatorSendBurn, + shouldBehaveLikeERC777UnauthorizedOperatorSendBurn, shouldDirectSendTokens, }; diff --git a/test/drafts/ERC777/ERC777.test.js b/test/drafts/ERC777/ERC777.test.js index ffefa47d81d..a84bf72a9df 100644 --- a/test/drafts/ERC777/ERC777.test.js +++ b/test/drafts/ERC777/ERC777.test.js @@ -1,11 +1,9 @@ const { BN, expectEvent, shouldFail, singletons } = require('openzeppelin-test-helpers'); const { - shouldBehaveLikeERC777DirectSend, - shouldBehaveLikeERC777OperatorSend, - shouldBehaveLikeERC777UnauthorizedOperatorSend, - shouldBehaveLikeERC777DirectBurn, - shouldBehaveLikeERC777OperatorBurn, + shouldBehaveLikeERC777DirectSendBurn, + shouldBehaveLikeERC777OperatorSendBurn, + shouldBehaveLikeERC777UnauthorizedOperatorSendBurn, shouldDirectSendTokens, } = require('./ERC777.behavior'); @@ -35,7 +33,7 @@ contract('ERC777', function ([ context('with default operators', function () { beforeEach(async function () { - this.token = await ERC777.new(holder, initialSupply, name, symbol, 1, defaultOperators); + this.token = await ERC777.new(holder, initialSupply, name, symbol, granularity, defaultOperators); }); describe('basic information', function () { @@ -85,23 +83,23 @@ contract('ERC777', function ([ }); }); - describe('send', function () { - shouldBehaveLikeERC777DirectSend(holder, anyone, data); + describe('send/burn', function () { + shouldBehaveLikeERC777DirectSendBurn(holder, anyone, data); context('with self operator', function () { - shouldBehaveLikeERC777OperatorSend(holder, anyone, holder, data, operatorData); + shouldBehaveLikeERC777OperatorSendBurn(holder, anyone, holder, data, operatorData); }); context('with first default operator', function () { - shouldBehaveLikeERC777OperatorSend(holder, anyone, defaultOperatorA, data, operatorData); + shouldBehaveLikeERC777OperatorSendBurn(holder, anyone, defaultOperatorA, data, operatorData); }); context('with second default operator', function () { - shouldBehaveLikeERC777OperatorSend(holder, anyone, defaultOperatorB, data, operatorData); + shouldBehaveLikeERC777OperatorSendBurn(holder, anyone, defaultOperatorB, data, operatorData); }); context('before authorizing a new operator', function () { - shouldBehaveLikeERC777UnauthorizedOperatorSend(holder, anyone, newOperator, data, operatorData); + shouldBehaveLikeERC777UnauthorizedOperatorSendBurn(holder, anyone, newOperator, data, operatorData); }); context('with new authorized operator', function () { @@ -109,34 +107,18 @@ contract('ERC777', function ([ await this.token.authorizeOperator(newOperator, { from: holder }); }); - shouldBehaveLikeERC777OperatorSend(holder, anyone, newOperator, data, operatorData); + shouldBehaveLikeERC777OperatorSendBurn(holder, anyone, newOperator, data, operatorData); context('with revoked operator', function () { beforeEach(async function () { await this.token.revokeOperator(newOperator, { from: holder }); }); - shouldBehaveLikeERC777UnauthorizedOperatorSend(holder, anyone, newOperator, data, operatorData); + shouldBehaveLikeERC777UnauthorizedOperatorSendBurn(holder, anyone, newOperator, data, operatorData); }); }); }); - describe('burn', function () { - shouldBehaveLikeERC777DirectBurn(holder, data); - - context('with self operator', function () { - shouldBehaveLikeERC777OperatorBurn(holder, holder, data, operatorData); - }); - - context('with first default operator', function () { - shouldBehaveLikeERC777OperatorBurn(holder, defaultOperatorA, data, operatorData); - }); - - context('with second default operator', function () { - shouldBehaveLikeERC777OperatorBurn(holder, defaultOperatorB, data, operatorData); - }); - }); - describe('operator management', function () { it('accounts are their own operator', async function () { (await this.token.isOperatorFor(holder, holder)).should.equal(true); From 6cdaa1f445a558c91a27e0b3ba9879e68428c3c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Thu, 4 Apr 2019 13:48:48 -0300 Subject: [PATCH 40/64] Add missing and not-implemented tests. --- test/drafts/ERC777/ERC777.behavior.js | 18 ++++++++++++++++++ test/drafts/ERC777/ERC777.test.js | 19 ++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/test/drafts/ERC777/ERC777.behavior.js b/test/drafts/ERC777/ERC777.behavior.js index 8464a49e328..7034fce8f05 100644 --- a/test/drafts/ERC777/ERC777.behavior.js +++ b/test/drafts/ERC777/ERC777.behavior.js @@ -76,6 +76,15 @@ function shouldBehaveLikeERC777OperatorSend (holder, recipient, operator, data, this.token.operatorSend(holder, recipient, new BN('1'), data, operatorData, { from: operator }) ); }); + + it.skip('reverts when sending from the zero address', async function () { + // This is not yet reflected in the spec + await shouldFail.reverting( + this.token.operatorSend( + ZERO_ADDRESS, recipient, new BN('0'), data, operatorData, { from: operator } + ) + ); + }); }); }); } @@ -136,6 +145,15 @@ function shouldBehaveLikeERC777OperatorBurn (holder, operator, data, operatorDat this.token.operatorBurn(holder, new BN('1'), data, operatorData, { from: operator }) ); }); + + it.skip('reverts when burning from the zero address', async function () { + // This is not yet reflected in the spec + await shouldFail.reverting( + this.token.operatorBurn( + ZERO_ADDRESS, new BN('0'), data, operatorData, { from: operator } + ) + ); + }); }); }); } diff --git a/test/drafts/ERC777/ERC777.test.js b/test/drafts/ERC777/ERC777.test.js index a84bf72a9df..891df5b4cfd 100644 --- a/test/drafts/ERC777/ERC777.test.js +++ b/test/drafts/ERC777/ERC777.test.js @@ -36,6 +36,10 @@ contract('ERC777', function ([ this.token = await ERC777.new(holder, initialSupply, name, symbol, granularity, defaultOperators); }); + it.skip('does not emit AuthorizedOperator events for default operators', async function () { + expectEvent.not.inConstructor(this.token, 'AuthorizedOperator'); // This helper needs to be implemented + }); + describe('basic information', function () { it('returns the name', async function () { (await this.token.name()).should.equal(name); @@ -132,6 +136,15 @@ contract('ERC777', function ([ await shouldFail.reverting(this.token.revokeOperator(holder, { from: holder })); }); + it('non-operators can be revoked', async function () { + (await this.token.isOperatorFor(newOperator, holder)).should.equal(false); + + const { logs } = await this.token.revokeOperator(newOperator, { from: holder }); + expectEvent.inLogs(logs, 'RevokedOperator', { operator: newOperator, tokenHolder: holder }); + + (await this.token.isOperatorFor(newOperator, holder)).should.equal(false); + }); + it('non-operators can be authorized', async function () { (await this.token.isOperatorFor(newOperator, holder)).should.equal(false); @@ -180,6 +193,10 @@ contract('ERC777', function ([ (await this.token.isOperatorFor(defaultOperatorA, holder)).should.equal(false); }); + it('cannot be revoked for themselves', async function () { + await shouldFail.reverting(this.token.revokeOperator(defaultOperatorA, { from: defaultOperatorA })); + }); + context('with revoked default operator', function () { beforeEach(async function () { await this.token.revokeOperator(defaultOperatorA, { from: holder }); @@ -210,7 +227,7 @@ contract('ERC777', function ([ context('with no default operators', function () { beforeEach(async function () { - this.token = await ERC777.new(holder, initialSupply, name, symbol, 1, []); + this.token = await ERC777.new(holder, initialSupply, name, symbol, granularity, []); }); it('default operators list is empty', async function () { From 29134fe42dc7edf7dd4a0d15fded59e5529652db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Thu, 4 Apr 2019 13:59:55 -0300 Subject: [PATCH 41/64] Make _burn private. --- contracts/drafts/ERC777/ERC777.sol | 62 +++++++++++++++--------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/contracts/drafts/ERC777/ERC777.sol b/contracts/drafts/ERC777/ERC777.sol index 7047b279bf3..9f9c58ef2c8 100644 --- a/contracts/drafts/ERC777/ERC777.sol +++ b/contracts/drafts/ERC777/ERC777.sol @@ -210,37 +210,6 @@ contract ERC777 is IERC777 { _operators[tokenHolder][operator]; } - /** - * @dev Burn tokens - * @param operator address operator requesting the operation - * @param from address token holder address - * @param amount uint256 amount of tokens to burn - * @param data bytes extra information provided by the token holder - * @param operatorData bytes extra information provided by the operator (if any) - */ - function _burn( - address operator, - address from, - uint256 amount, - bytes memory data, - bytes memory operatorData - ) - internal - { - require(from != address(0)); - require(isOperatorFor(msg.sender, from)); - require((amount % _granularity) == 0); - - _callTokensToSend(operator, from, address(0), amount, data, operatorData); - - // Update state variables - _totalSupply = _totalSupply.sub(amount); - _balances[from] = _balances[from].sub(amount); - assert((_balances[from] % _granularity) == 0); - - emit Burned(operator, from, amount, data, operatorData); - } - /** * @dev Mint tokens. Does not check authorization of operator * @dev the caller may ckeck that operator is authorized before calling @@ -345,6 +314,37 @@ contract ERC777 is IERC777 { emit Sent(operator, from, to, amount, userData, operatorData); } + /** + * @dev Burn tokens + * @param operator address operator requesting the operation + * @param from address token holder address + * @param amount uint256 amount of tokens to burn + * @param data bytes extra information provided by the token holder + * @param operatorData bytes extra information provided by the operator (if any) + */ + function _burn( + address operator, + address from, + uint256 amount, + bytes memory data, + bytes memory operatorData + ) + private + { + require(from != address(0)); + require(isOperatorFor(msg.sender, from)); + require((amount % _granularity) == 0); + + _callTokensToSend(operator, from, address(0), amount, data, operatorData); + + // Update state variables + _totalSupply = _totalSupply.sub(amount); + _balances[from] = _balances[from].sub(amount); + assert((_balances[from] % _granularity) == 0); + + emit Burned(operator, from, amount, data, operatorData); + } + /** * @dev Call from.tokensToSend() if the interface is registered * @param operator address operator requesting the transfer From d272f5b6ef1eff7a3bdc21f47f966d978c96fddb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Thu, 4 Apr 2019 14:59:14 -0300 Subject: [PATCH 42/64] Fix typo. --- contracts/drafts/ERC777/ERC777.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/drafts/ERC777/ERC777.sol b/contracts/drafts/ERC777/ERC777.sol index 9f9c58ef2c8..6b4827ca07e 100644 --- a/contracts/drafts/ERC777/ERC777.sol +++ b/contracts/drafts/ERC777/ERC777.sol @@ -27,7 +27,7 @@ contract ERC777 is IERC777 { uint256 private _granularity; - bytes32 constant private TOKENS_SENDER_INTEFACE_HASH = keccak256("ERC777TokensSender"); + bytes32 constant private TOKENS_SENDER_INTERFACE_HASH = keccak256("ERC777TokensSender"); bytes32 constant private TOKENS_RECIPIENT_INTERFACE_HASH = keccak256("ERC777TokensRecipient"); // This isn't ever read from - it's only used to respond to the defaultOperators query. @@ -364,7 +364,7 @@ contract ERC777 is IERC777 { ) private { - address implementer = _erc1820.getInterfaceImplementer(from, TOKENS_SENDER_INTEFACE_HASH); + address implementer = _erc1820.getInterfaceImplementer(from, TOKENS_SENDER_INTERFACE_HASH); if (implementer != address(0)) { IERC777Sender(implementer).tokensToSend(operator, from, to, amount, userData, operatorData); } From b39d65e6bf77c39f59442da69f0f47350c92046a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Fri, 5 Apr 2019 23:13:01 -0300 Subject: [PATCH 43/64] Greatly improve tokensToSend tests. --- contracts/mocks/ERC777SenderMock.sol | 121 ++++++------- test/drafts/ERC777/ERC777.test.js | 256 ++++++++++++++++++++++++--- 2 files changed, 283 insertions(+), 94 deletions(-) diff --git a/contracts/mocks/ERC777SenderMock.sol b/contracts/mocks/ERC777SenderMock.sol index 1ac564d4a8d..1339feb4615 100644 --- a/contracts/mocks/ERC777SenderMock.sol +++ b/contracts/mocks/ERC777SenderMock.sol @@ -3,96 +3,77 @@ pragma solidity ^0.5.2; import "../drafts/ERC777/IERC777.sol"; import "../drafts/ERC777/IERC777Sender.sol"; import "../drafts/IERC1820Registry.sol"; +import "../drafts/ERC1820Implementer.sol"; -/** - * @title ERC777TokensSenderMock a contract that implements tokensToSend() hook - * @author Bertrand Masius - * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-777.md - */ -contract ERC777SenderMock is IERC777Sender { - - IERC1820Registry private _erc1820 = IERC1820Registry(0x1820b744B33945482C17Dc37218C01D858EBc714); - IERC777 private _erc777; - - event TokensToSend( - address indexed operator, - address indexed from, - address indexed to, +contract ERC777SenderMock is IERC777Sender, ERC1820Implementer { + event TokensToSendCalled( + address operator, + address from, + address to, uint256 amount, bytes data, - bytes operatorData + bytes operatorData, + address token, + uint256 fromBalance, + uint256 toBalance ); - constructor(bool setInterface, IERC777 erc777) public { - _erc777 = erc777; - // register interface - if (setInterface) { - _erc1820.setInterfaceImplementer( - address(this), - keccak256("ERC777TokensSender"), - address(this) - ); - } - } - - /** - * @dev Send an amount of tokens from this contract to recipient - * @param to address recipient address - * @param amount uint256 amount of tokens to transfer - * @param data bytes extra information provided by the token holder (if any) - */ - function sendTokens( - address to, - uint amount, - bytes calldata data - ) external { - // solhint-disable-next-line check-send-result - _erc777.send(to, amount, data); - } + bool private _shouldRevert; + IERC1820Registry private _erc1820 = IERC1820Registry(0x1820b744B33945482C17Dc37218C01D858EBc714); - /** - * @dev Burn an amount of tokens from this contract - * @param amount uint256 amount of tokens to transfer - * @param data bytes extra information provided by the token holder (if any) - */ - function burnTokens(uint amount, bytes calldata data) external { - _erc777.burn(amount, data); - } + bytes32 constant private TOKENS_SENDER_INTERFACE_HASH = keccak256("ERC777TokensSender"); - /** - * @dev Authorize an operator - * @param operator address of operator - */ - function authorizeOperator(address operator) external { - _erc777.authorizeOperator(operator); + constructor(address account) public { + if (account != address(0)) { + _registerInterfaceForAddress(TOKENS_SENDER_INTERFACE_HASH, account); + } else { + address self = address(this); + _registerInterfaceForAddress(TOKENS_SENDER_INTERFACE_HASH, self); + _erc1820.setInterfaceImplementer(self, TOKENS_SENDER_INTERFACE_HASH, self); + } } - /** - * @dev tokensSender() hook - * @param operator address operator requesting the transfer - * @param from address token holder address - * @param to address recipient address - * @param amount uint256 amount of tokens to transfer - * @param userData bytes extra information provided by the token holder (if any) - * @param operatorData bytes extra information provided by the operator (if any) - */ function tokensToSend( address operator, address from, address to, - uint256 amount, + uint amount, bytes calldata userData, bytes calldata operatorData - ) - external - { - emit TokensToSend( + ) external { + if (_shouldRevert) { + revert(); + } + + IERC777 token = IERC777(msg.sender); + + uint256 fromBalance = token.balanceOf(from); + // when called due to burn, to will be the zero address, which will have a balance of 0 + uint256 toBalance = token.balanceOf(to); + + emit TokensToSendCalled( operator, from, to, amount, userData, - operatorData + operatorData, + address(token), + fromBalance, + toBalance ); } + + function setShouldRevert(bool shouldRevert) public { + _shouldRevert = shouldRevert; + } + + function send(IERC777 token, address to, uint256 amount, bytes memory data) public { + token.send(to, amount, data); + } + + function burn(IERC777 token, uint256 amount, bytes memory data) public { + token.burn(amount, data); + } } + diff --git a/test/drafts/ERC777/ERC777.test.js b/test/drafts/ERC777/ERC777.test.js index 891df5b4cfd..43f5fe0aae7 100644 --- a/test/drafts/ERC777/ERC777.test.js +++ b/test/drafts/ERC777/ERC777.test.js @@ -1,4 +1,5 @@ -const { BN, expectEvent, shouldFail, singletons } = require('openzeppelin-test-helpers'); +const { BN, constants, expectEvent, shouldFail, singletons } = require('openzeppelin-test-helpers'); +const { ZERO_ADDRESS } = constants; const { shouldBehaveLikeERC777DirectSendBurn, @@ -8,6 +9,7 @@ const { } = require('./ERC777.behavior'); const ERC777 = artifacts.require('ERC777Mock'); +const ERC777SenderMock = artifacts.require('ERC777SenderMock'); contract('ERC777', function ([ _, registryFunder, holder, defaultOperatorA, defaultOperatorB, newOperator, anyone, @@ -20,7 +22,7 @@ contract('ERC777', function ([ const defaultOperators = [defaultOperatorA, defaultOperatorB]; - before(async function () { + beforeEach(async function () { this.erc1820 = await singletons.ERC1820Registry(registryFunder); }); @@ -88,37 +90,39 @@ contract('ERC777', function ([ }); describe('send/burn', function () { - shouldBehaveLikeERC777DirectSendBurn(holder, anyone, data); + context('with no ERC777TokensSender and no ERC777TokensRecipient implementers', function () { + shouldBehaveLikeERC777DirectSendBurn(holder, anyone, data); - context('with self operator', function () { - shouldBehaveLikeERC777OperatorSendBurn(holder, anyone, holder, data, operatorData); - }); - - context('with first default operator', function () { - shouldBehaveLikeERC777OperatorSendBurn(holder, anyone, defaultOperatorA, data, operatorData); - }); - - context('with second default operator', function () { - shouldBehaveLikeERC777OperatorSendBurn(holder, anyone, defaultOperatorB, data, operatorData); - }); + context('with self operator', function () { + shouldBehaveLikeERC777OperatorSendBurn(holder, anyone, holder, data, operatorData); + }); - context('before authorizing a new operator', function () { - shouldBehaveLikeERC777UnauthorizedOperatorSendBurn(holder, anyone, newOperator, data, operatorData); - }); + context('with first default operator', function () { + shouldBehaveLikeERC777OperatorSendBurn(holder, anyone, defaultOperatorA, data, operatorData); + }); - context('with new authorized operator', function () { - beforeEach(async function () { - await this.token.authorizeOperator(newOperator, { from: holder }); + context('with second default operator', function () { + shouldBehaveLikeERC777OperatorSendBurn(holder, anyone, defaultOperatorB, data, operatorData); }); - shouldBehaveLikeERC777OperatorSendBurn(holder, anyone, newOperator, data, operatorData); + context('before authorizing a new operator', function () { + shouldBehaveLikeERC777UnauthorizedOperatorSendBurn(holder, anyone, newOperator, data, operatorData); + }); - context('with revoked operator', function () { + context('with new authorized operator', function () { beforeEach(async function () { - await this.token.revokeOperator(newOperator, { from: holder }); + await this.token.authorizeOperator(newOperator, { from: holder }); }); - shouldBehaveLikeERC777UnauthorizedOperatorSendBurn(holder, anyone, newOperator, data, operatorData); + shouldBehaveLikeERC777OperatorSendBurn(holder, anyone, newOperator, data, operatorData); + + context('with revoked operator', function () { + beforeEach(async function () { + await this.token.revokeOperator(newOperator, { from: holder }); + }); + + shouldBehaveLikeERC777UnauthorizedOperatorSendBurn(holder, anyone, newOperator, data, operatorData); + }); }); }); }); @@ -223,6 +227,210 @@ contract('ERC777', function ([ }); }); }); + + describe('tokensToSend hook', function () { + context('with ERC777TokensSender implementer', function () { + async function assertTokensToSendCalled (token, txHash, operator, from, to, amount, data, operatorData, fromBalance, toBalance='0') { + await expectEvent.inTransaction(txHash, ERC777SenderMock, 'TokensToSendCalled', { + operator, from, to, amount, data, operatorData, token: token.address, fromBalance, toBalance + }); + } + + async function sendFromHolder(token, holder, to, amount, data) { + if ((await web3.eth.getCode(holder)).length <= '0x'.length) { + return token.send(to, amount, data, { from: holder }); + + } else { + // assume holder is ERC777SenderMock contract + return (await ERC777SenderMock.at(holder)).send(token.address, to, amount, data); + } + } + + async function burnFromHolder(token, holder, amount, data) { + if ((await web3.eth.getCode(holder)).length <= '0x'.length) { + return token.burn(amount, data, { from: holder }); + + } else { + // assume holder is ERC777SenderMock contract + return (await ERC777SenderMock.at(holder)).burn(token.address, amount, data); + } + } + + context('with a contract as implementer for an externally owned account', function () { + const amount = new BN('1'); + const recipient = anyone; + const operator = defaultOperatorA; + const sender = holder; + + beforeEach(async function () { + this.tokensSenderImplementer = await ERC777SenderMock.new(holder); + await this.erc1820.setInterfaceImplementer(holder, web3.utils.soliditySha3('ERC777TokensSender'), this.tokensSenderImplementer.address, { from: holder }); + }); + + context('when TokensSender reverts', function () { + beforeEach(async function () { + await this.tokensSenderImplementer.setShouldRevert(true); + }); + + it('send reverts', async function () { + await shouldFail.reverting(sendFromHolder(this.token, sender, recipient, amount, data)); + }); + + it('operatorSend reverts', async function () { + await shouldFail.reverting( + this.token.operatorSend(sender, recipient, amount, data, operatorData, { from: operator }) + ); + }); + + it('burn reverts', async function () { + await shouldFail.reverting(burnFromHolder(this.token, sender, amount, data)); + }); + + it('operatorBurn reverts', async function () { + await shouldFail.reverting( + this.token.operatorBurn(sender, amount, data, operatorData, { from: operator }) + ); + }); + }); + + context('when TokensSender does not revert', function () { + beforeEach(async function () { + await this.tokensSenderImplementer.setShouldRevert(false); + }); + + it('TokensSender receives send data and is called before state mutation', async function () { + const preHolderBalance = await this.token.balanceOf(sender); + const preRecipientBalance = await this.token.balanceOf(recipient); + + const { tx } = await sendFromHolder(this.token, sender, recipient, amount, data); + + await assertTokensToSendCalled( + this.token, tx, sender, sender, recipient, amount, data, null, preHolderBalance, preRecipientBalance + ); + }); + + it('TokensSender receives operatorSend data and is called before state mutation', async function () { + const preHolderBalance = await this.token.balanceOf(sender); + const preRecipientBalance = await this.token.balanceOf(recipient); + + const { tx } = await this.token.operatorSend(sender, recipient, amount, data, operatorData, { from: operator }); + + await assertTokensToSendCalled( + this.token, tx, operator, sender, recipient, amount, data, operatorData, preHolderBalance, preRecipientBalance + ); + }); + + it('TokensSender receives burn data and is called before state mutation', async function () { + const preHolderBalance = await this.token.balanceOf(sender); + + const { tx } = await burnFromHolder(this.token, sender, amount, data, { from: sender }); + + await assertTokensToSendCalled( + this.token, tx, sender, sender, ZERO_ADDRESS, amount, data, null, preHolderBalance + ); + }); + + it('TokensSender receives operatorBurn data and is called before state mutation', async function () { + const preHolderBalance = await this.token.balanceOf(sender); + + const { tx } = await this.token.operatorBurn(sender, amount, data, operatorData, { from: operator }); + + await assertTokensToSendCalled( + this.token, tx, operator, sender, ZERO_ADDRESS, amount, data, operatorData, preHolderBalance + ); + }); + }); + }); + + context('with a contract as implementer for itself', function () { + const amount = new BN('1'); + const recipient = anyone; + const operator = defaultOperatorA; + let sender; + + beforeEach(async function () { + this.tokensSenderImplementer = await ERC777SenderMock.new(ZERO_ADDRESS); + + sender = this.tokensSenderImplementer.address; + await this.token.send(sender, amount, data, { from: holder }); + }); + + context('when TokensSender reverts', function () { + beforeEach(async function () { + await this.tokensSenderImplementer.setShouldRevert(true); + }); + + it('send reverts', async function () { + await shouldFail.reverting(sendFromHolder(this.token, sender, recipient, amount, data)); + }); + + it('operatorSend reverts', async function () { + await shouldFail.reverting( + this.token.operatorSend(sender, recipient, amount, data, operatorData, { from: operator }) + ); + }); + + it('burn reverts', async function () { + await shouldFail.reverting(burnFromHolder(this.token, sender, amount, data)); + }); + + it('operatorBurn reverts', async function () { + await shouldFail.reverting( + this.token.operatorBurn(sender, amount, data, operatorData, { from: operator }) + ); + }); + }); + + context('when TokensSender does not revert', function () { + beforeEach(async function () { + await this.tokensSenderImplementer.setShouldRevert(false); + }); + + it('TokensSender receives send data and is called before state mutation', async function () { + const preHolderBalance = await this.token.balanceOf(sender); + const preRecipientBalance = await this.token.balanceOf(recipient); + + const { tx } = await sendFromHolder(this.token, sender, recipient, amount, data); + + await assertTokensToSendCalled( + this.token, tx, sender, sender, recipient, amount, data, null, preHolderBalance, preRecipientBalance + ); + }); + + it('TokensSender receives operatorSend data and is called before state mutation', async function () { + const preHolderBalance = await this.token.balanceOf(sender); + const preRecipientBalance = await this.token.balanceOf(recipient); + + const { tx } = await this.token.operatorSend(sender, recipient, amount, data, operatorData, { from: operator }); + + await assertTokensToSendCalled( + this.token, tx, operator, sender, recipient, amount, data, operatorData, preHolderBalance, preRecipientBalance + ); + }); + + it('TokensSender receives burn data and is called before state mutation', async function () { + const preHolderBalance = await this.token.balanceOf(sender); + + const { tx } = await burnFromHolder(this.token, sender, amount, data, { from: sender }); + + await assertTokensToSendCalled( + this.token, tx, sender, sender, ZERO_ADDRESS, amount, data, null, preHolderBalance + ); + }); + + it('TokensSender receives operatorBurn data and is called before state mutation', async function () { + const preHolderBalance = await this.token.balanceOf(sender); + + const { tx } = await this.token.operatorBurn(sender, amount, data, operatorData, { from: operator }); + + await assertTokensToSendCalled( + this.token, tx, operator, sender, ZERO_ADDRESS, amount, data, operatorData, preHolderBalance + ); + }); + }); + }); + }); + }); }); context('with no default operators', function () { From a6d39ce1e2a3e52769729741c1312216e584a342 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Sat, 6 Apr 2019 01:24:05 -0300 Subject: [PATCH 44/64] Refactor hook tests. --- test/drafts/ERC777/ERC777.behavior.js | 105 ++++++++++++++ test/drafts/ERC777/ERC777.test.js | 188 ++------------------------ 2 files changed, 113 insertions(+), 180 deletions(-) diff --git a/test/drafts/ERC777/ERC777.behavior.js b/test/drafts/ERC777/ERC777.behavior.js index 7034fce8f05..8371a51d075 100644 --- a/test/drafts/ERC777/ERC777.behavior.js +++ b/test/drafts/ERC777/ERC777.behavior.js @@ -1,6 +1,8 @@ const { BN, constants, expectEvent, shouldFail } = require('openzeppelin-test-helpers'); const { ZERO_ADDRESS } = constants; +const ERC777SenderMock = artifacts.require('ERC777SenderMock'); + function shouldBehaveLikeERC777DirectSendBurn (holder, recipient, data) { shouldBehaveLikeERC777DirectSend(holder, recipient, data); shouldBehaveLikeERC777DirectBurn(holder, data); @@ -257,6 +259,82 @@ function shouldBurnTokens (from, operator, amount, data, operatorData) { }); } +function shouldBehaveLikeERC777SendBurnWithHook (sender, recipient, operator, amount, data, operatorData) { + context('when TokensSender reverts', function () { + beforeEach(async function () { + await this.tokensSenderImplementer.setShouldRevert(true); + }); + + it('send reverts', async function () { + await shouldFail.reverting(sendFromHolder(this.token, sender, recipient, amount, data)); + }); + + it('operatorSend reverts', async function () { + await shouldFail.reverting( + this.token.operatorSend(sender, recipient, amount, data, operatorData, { from: operator }) + ); + }); + + it('burn reverts', async function () { + await shouldFail.reverting(burnFromHolder(this.token, sender, amount, data)); + }); + + it('operatorBurn reverts', async function () { + await shouldFail.reverting( + this.token.operatorBurn(sender, amount, data, operatorData, { from: operator }) + ); + }); + }); + + context('when TokensSender does not revert', function () { + beforeEach(async function () { + await this.tokensSenderImplementer.setShouldRevert(false); + }); + + it('TokensSender receives send data and is called before state mutation', async function () { + const preHolderBalance = await this.token.balanceOf(sender); + const preRecipientBalance = await this.token.balanceOf(recipient); + + const { tx } = await sendFromHolder(this.token, sender, recipient, amount, data); + + await assertTokensToSendCalled( + this.token, tx, sender, sender, recipient, amount, data, null, preHolderBalance, preRecipientBalance + ); + }); + + it('TokensSender receives operatorSend data and is called before state mutation', async function () { + const preHolderBalance = await this.token.balanceOf(sender); + const preRecipientBalance = await this.token.balanceOf(recipient); + + const { tx } = await this.token.operatorSend(sender, recipient, amount, data, operatorData, { from: operator }); + + await assertTokensToSendCalled( + this.token, tx, operator, sender, recipient, amount, data, operatorData, preHolderBalance, preRecipientBalance + ); + }); + + it('TokensSender receives burn data and is called before state mutation', async function () { + const preHolderBalance = await this.token.balanceOf(sender); + + const { tx } = await burnFromHolder(this.token, sender, amount, data, { from: sender }); + + await assertTokensToSendCalled( + this.token, tx, sender, sender, ZERO_ADDRESS, amount, data, null, preHolderBalance + ); + }); + + it('TokensSender receives operatorBurn data and is called before state mutation', async function () { + const preHolderBalance = await this.token.balanceOf(sender); + + const { tx } = await this.token.operatorBurn(sender, amount, data, operatorData, { from: operator }); + + await assertTokensToSendCalled( + this.token, tx, operator, sender, ZERO_ADDRESS, amount, data, operatorData, preHolderBalance + ); + }); + }); +} + function removeBalance (holder) { beforeEach(async function () { await this.token.burn(await this.token.balanceOf(holder), '0x', { from: holder }); @@ -264,9 +342,36 @@ function removeBalance (holder) { }); } +async function assertTokensToSendCalled (token, txHash, operator, from, to, amount, data, operatorData, fromBalance, toBalance='0') { + await expectEvent.inTransaction(txHash, ERC777SenderMock, 'TokensToSendCalled', { + operator, from, to, amount, data, operatorData, token: token.address, fromBalance, toBalance + }); +} + +async function sendFromHolder(token, holder, to, amount, data) { + if ((await web3.eth.getCode(holder)).length <= '0x'.length) { + return token.send(to, amount, data, { from: holder }); + + } else { + // assume holder is ERC777SenderMock contract + return (await ERC777SenderMock.at(holder)).send(token.address, to, amount, data); + } +} + +async function burnFromHolder(token, holder, amount, data) { + if ((await web3.eth.getCode(holder)).length <= '0x'.length) { + return token.burn(amount, data, { from: holder }); + + } else { + // assume holder is ERC777SenderMock contract + return (await ERC777SenderMock.at(holder)).burn(token.address, amount, data); + } +} + module.exports = { shouldBehaveLikeERC777DirectSendBurn, shouldBehaveLikeERC777OperatorSendBurn, shouldBehaveLikeERC777UnauthorizedOperatorSendBurn, shouldDirectSendTokens, + shouldBehaveLikeERC777SendBurnWithHook, }; diff --git a/test/drafts/ERC777/ERC777.test.js b/test/drafts/ERC777/ERC777.test.js index 43f5fe0aae7..29e12a485a8 100644 --- a/test/drafts/ERC777/ERC777.test.js +++ b/test/drafts/ERC777/ERC777.test.js @@ -6,6 +6,7 @@ const { shouldBehaveLikeERC777OperatorSendBurn, shouldBehaveLikeERC777UnauthorizedOperatorSendBurn, shouldDirectSendTokens, + shouldBehaveLikeERC777SendBurnWithHook, } = require('./ERC777.behavior'); const ERC777 = artifacts.require('ERC777Mock'); @@ -230,124 +231,23 @@ contract('ERC777', function ([ describe('tokensToSend hook', function () { context('with ERC777TokensSender implementer', function () { - async function assertTokensToSendCalled (token, txHash, operator, from, to, amount, data, operatorData, fromBalance, toBalance='0') { - await expectEvent.inTransaction(txHash, ERC777SenderMock, 'TokensToSendCalled', { - operator, from, to, amount, data, operatorData, token: token.address, fromBalance, toBalance - }); - } - - async function sendFromHolder(token, holder, to, amount, data) { - if ((await web3.eth.getCode(holder)).length <= '0x'.length) { - return token.send(to, amount, data, { from: holder }); - - } else { - // assume holder is ERC777SenderMock contract - return (await ERC777SenderMock.at(holder)).send(token.address, to, amount, data); - } - } - - async function burnFromHolder(token, holder, amount, data) { - if ((await web3.eth.getCode(holder)).length <= '0x'.length) { - return token.burn(amount, data, { from: holder }); - - } else { - // assume holder is ERC777SenderMock contract - return (await ERC777SenderMock.at(holder)).burn(token.address, amount, data); - } - } + const amount = new BN('1'); + const recipient = anyone; + const operator = defaultOperatorA; + let sender; context('with a contract as implementer for an externally owned account', function () { - const amount = new BN('1'); - const recipient = anyone; - const operator = defaultOperatorA; - const sender = holder; + sender = holder; beforeEach(async function () { this.tokensSenderImplementer = await ERC777SenderMock.new(holder); await this.erc1820.setInterfaceImplementer(holder, web3.utils.soliditySha3('ERC777TokensSender'), this.tokensSenderImplementer.address, { from: holder }); }); - context('when TokensSender reverts', function () { - beforeEach(async function () { - await this.tokensSenderImplementer.setShouldRevert(true); - }); - - it('send reverts', async function () { - await shouldFail.reverting(sendFromHolder(this.token, sender, recipient, amount, data)); - }); - - it('operatorSend reverts', async function () { - await shouldFail.reverting( - this.token.operatorSend(sender, recipient, amount, data, operatorData, { from: operator }) - ); - }); - - it('burn reverts', async function () { - await shouldFail.reverting(burnFromHolder(this.token, sender, amount, data)); - }); - - it('operatorBurn reverts', async function () { - await shouldFail.reverting( - this.token.operatorBurn(sender, amount, data, operatorData, { from: operator }) - ); - }); - }); - - context('when TokensSender does not revert', function () { - beforeEach(async function () { - await this.tokensSenderImplementer.setShouldRevert(false); - }); - - it('TokensSender receives send data and is called before state mutation', async function () { - const preHolderBalance = await this.token.balanceOf(sender); - const preRecipientBalance = await this.token.balanceOf(recipient); - - const { tx } = await sendFromHolder(this.token, sender, recipient, amount, data); - - await assertTokensToSendCalled( - this.token, tx, sender, sender, recipient, amount, data, null, preHolderBalance, preRecipientBalance - ); - }); - - it('TokensSender receives operatorSend data and is called before state mutation', async function () { - const preHolderBalance = await this.token.balanceOf(sender); - const preRecipientBalance = await this.token.balanceOf(recipient); - - const { tx } = await this.token.operatorSend(sender, recipient, amount, data, operatorData, { from: operator }); - - await assertTokensToSendCalled( - this.token, tx, operator, sender, recipient, amount, data, operatorData, preHolderBalance, preRecipientBalance - ); - }); - - it('TokensSender receives burn data and is called before state mutation', async function () { - const preHolderBalance = await this.token.balanceOf(sender); - - const { tx } = await burnFromHolder(this.token, sender, amount, data, { from: sender }); - - await assertTokensToSendCalled( - this.token, tx, sender, sender, ZERO_ADDRESS, amount, data, null, preHolderBalance - ); - }); - - it('TokensSender receives operatorBurn data and is called before state mutation', async function () { - const preHolderBalance = await this.token.balanceOf(sender); - - const { tx } = await this.token.operatorBurn(sender, amount, data, operatorData, { from: operator }); - - await assertTokensToSendCalled( - this.token, tx, operator, sender, ZERO_ADDRESS, amount, data, operatorData, preHolderBalance - ); - }); - }); + shouldBehaveLikeERC777SendBurnWithHook(sender, recipient, operator, amount, data, operatorData); }); context('with a contract as implementer for itself', function () { - const amount = new BN('1'); - const recipient = anyone; - const operator = defaultOperatorA; - let sender; - beforeEach(async function () { this.tokensSenderImplementer = await ERC777SenderMock.new(ZERO_ADDRESS); @@ -355,79 +255,7 @@ contract('ERC777', function ([ await this.token.send(sender, amount, data, { from: holder }); }); - context('when TokensSender reverts', function () { - beforeEach(async function () { - await this.tokensSenderImplementer.setShouldRevert(true); - }); - - it('send reverts', async function () { - await shouldFail.reverting(sendFromHolder(this.token, sender, recipient, amount, data)); - }); - - it('operatorSend reverts', async function () { - await shouldFail.reverting( - this.token.operatorSend(sender, recipient, amount, data, operatorData, { from: operator }) - ); - }); - - it('burn reverts', async function () { - await shouldFail.reverting(burnFromHolder(this.token, sender, amount, data)); - }); - - it('operatorBurn reverts', async function () { - await shouldFail.reverting( - this.token.operatorBurn(sender, amount, data, operatorData, { from: operator }) - ); - }); - }); - - context('when TokensSender does not revert', function () { - beforeEach(async function () { - await this.tokensSenderImplementer.setShouldRevert(false); - }); - - it('TokensSender receives send data and is called before state mutation', async function () { - const preHolderBalance = await this.token.balanceOf(sender); - const preRecipientBalance = await this.token.balanceOf(recipient); - - const { tx } = await sendFromHolder(this.token, sender, recipient, amount, data); - - await assertTokensToSendCalled( - this.token, tx, sender, sender, recipient, amount, data, null, preHolderBalance, preRecipientBalance - ); - }); - - it('TokensSender receives operatorSend data and is called before state mutation', async function () { - const preHolderBalance = await this.token.balanceOf(sender); - const preRecipientBalance = await this.token.balanceOf(recipient); - - const { tx } = await this.token.operatorSend(sender, recipient, amount, data, operatorData, { from: operator }); - - await assertTokensToSendCalled( - this.token, tx, operator, sender, recipient, amount, data, operatorData, preHolderBalance, preRecipientBalance - ); - }); - - it('TokensSender receives burn data and is called before state mutation', async function () { - const preHolderBalance = await this.token.balanceOf(sender); - - const { tx } = await burnFromHolder(this.token, sender, amount, data, { from: sender }); - - await assertTokensToSendCalled( - this.token, tx, sender, sender, ZERO_ADDRESS, amount, data, null, preHolderBalance - ); - }); - - it('TokensSender receives operatorBurn data and is called before state mutation', async function () { - const preHolderBalance = await this.token.balanceOf(sender); - - const { tx } = await this.token.operatorBurn(sender, amount, data, operatorData, { from: operator }); - - await assertTokensToSendCalled( - this.token, tx, operator, sender, ZERO_ADDRESS, amount, data, operatorData, preHolderBalance - ); - }); - }); + shouldBehaveLikeERC777SendBurnWithHook(sender, recipient, operator, amount, data, operatorData); }); }); }); From 71c8698effd8da37c014c41b7a6ab4d5c2feffe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Mon, 8 Apr 2019 21:39:15 -0300 Subject: [PATCH 45/64] Fix hook tests. --- contracts/mocks/ERC777SenderMock.sol | 3 +- test/drafts/ERC777/ERC777.behavior.js | 57 ++++++++++++++++----------- test/drafts/ERC777/ERC777.test.js | 21 +++++----- 3 files changed, 48 insertions(+), 33 deletions(-) diff --git a/contracts/mocks/ERC777SenderMock.sol b/contracts/mocks/ERC777SenderMock.sol index 1339feb4615..1ea1b3e3648 100644 --- a/contracts/mocks/ERC777SenderMock.sol +++ b/contracts/mocks/ERC777SenderMock.sol @@ -69,7 +69,8 @@ contract ERC777SenderMock is IERC777Sender, ERC1820Implementer { } function send(IERC777 token, address to, uint256 amount, bytes memory data) public { - token.send(to, amount, data); + // This is 777's send function, not the Solidity send function + token.send(to, amount, data); // solhint-disable-line check-send-result } function burn(IERC777 token, uint256 amount, bytes memory data) public { diff --git a/test/drafts/ERC777/ERC777.behavior.js b/test/drafts/ERC777/ERC777.behavior.js index 8371a51d075..95b2e8d7ff6 100644 --- a/test/drafts/ERC777/ERC777.behavior.js +++ b/test/drafts/ERC777/ERC777.behavior.js @@ -259,29 +259,29 @@ function shouldBurnTokens (from, operator, amount, data, operatorData) { }); } -function shouldBehaveLikeERC777SendBurnWithHook (sender, recipient, operator, amount, data, operatorData) { +function shouldBehaveLikeERC777SendBurnWithHook (recipient, operator, amount, data, operatorData) { context('when TokensSender reverts', function () { beforeEach(async function () { await this.tokensSenderImplementer.setShouldRevert(true); }); it('send reverts', async function () { - await shouldFail.reverting(sendFromHolder(this.token, sender, recipient, amount, data)); + await shouldFail.reverting(sendFromHolder(this.token, this.sender, recipient, amount, data)); }); it('operatorSend reverts', async function () { await shouldFail.reverting( - this.token.operatorSend(sender, recipient, amount, data, operatorData, { from: operator }) + this.token.operatorSend(this.sender, recipient, amount, data, operatorData, { from: operator }) ); }); it('burn reverts', async function () { - await shouldFail.reverting(burnFromHolder(this.token, sender, amount, data)); + await shouldFail.reverting(burnFromHolder(this.token, this.sender, amount, data)); }); it('operatorBurn reverts', async function () { await shouldFail.reverting( - this.token.operatorBurn(sender, amount, data, operatorData, { from: operator }) + this.token.operatorBurn(this.sender, amount, data, operatorData, { from: operator }) ); }); }); @@ -292,44 +292,56 @@ function shouldBehaveLikeERC777SendBurnWithHook (sender, recipient, operator, am }); it('TokensSender receives send data and is called before state mutation', async function () { - const preHolderBalance = await this.token.balanceOf(sender); + const preHolderBalance = await this.token.balanceOf(this.sender); const preRecipientBalance = await this.token.balanceOf(recipient); - const { tx } = await sendFromHolder(this.token, sender, recipient, amount, data); + const { tx } = await sendFromHolder(this.token, this.sender, recipient, amount, data); await assertTokensToSendCalled( - this.token, tx, sender, sender, recipient, amount, data, null, preHolderBalance, preRecipientBalance + this.token, tx, this.sender, this.sender, recipient, amount, data, null, preHolderBalance, preRecipientBalance ); }); it('TokensSender receives operatorSend data and is called before state mutation', async function () { - const preHolderBalance = await this.token.balanceOf(sender); + const preHolderBalance = await this.token.balanceOf(this.sender); const preRecipientBalance = await this.token.balanceOf(recipient); - const { tx } = await this.token.operatorSend(sender, recipient, amount, data, operatorData, { from: operator }); + const { tx } = await this.token.operatorSend( + this.sender, recipient, amount, data, operatorData, + { from: operator }, + ); await assertTokensToSendCalled( - this.token, tx, operator, sender, recipient, amount, data, operatorData, preHolderBalance, preRecipientBalance + this.token, + tx, + operator, + this.sender, + recipient, + amount, + data, + operatorData, + preHolderBalance, + preRecipientBalance, ); }); it('TokensSender receives burn data and is called before state mutation', async function () { - const preHolderBalance = await this.token.balanceOf(sender); + const preHolderBalance = await this.token.balanceOf(this.sender); - const { tx } = await burnFromHolder(this.token, sender, amount, data, { from: sender }); + const { tx } = await burnFromHolder(this.token, this.sender, amount, data, { from: this.sender }); await assertTokensToSendCalled( - this.token, tx, sender, sender, ZERO_ADDRESS, amount, data, null, preHolderBalance + this.token, tx, this.sender, this.sender, ZERO_ADDRESS, amount, data, null, preHolderBalance ); }); it('TokensSender receives operatorBurn data and is called before state mutation', async function () { - const preHolderBalance = await this.token.balanceOf(sender); + const preHolderBalance = await this.token.balanceOf(this.sender); - const { tx } = await this.token.operatorBurn(sender, amount, data, operatorData, { from: operator }); + const { tx } = await this.token.operatorBurn(this.sender, amount, data, operatorData, { from: operator }); await assertTokensToSendCalled( - this.token, tx, operator, sender, ZERO_ADDRESS, amount, data, operatorData, preHolderBalance + this.token, tx, operator, this.sender, ZERO_ADDRESS, amount, data, operatorData, preHolderBalance ); }); }); @@ -342,26 +354,25 @@ function removeBalance (holder) { }); } -async function assertTokensToSendCalled (token, txHash, operator, from, to, amount, data, operatorData, fromBalance, toBalance='0') { +async function assertTokensToSendCalled (token, txHash, operator, from, to, amount, data, operatorData, fromBalance, + toBalance = '0') { await expectEvent.inTransaction(txHash, ERC777SenderMock, 'TokensToSendCalled', { - operator, from, to, amount, data, operatorData, token: token.address, fromBalance, toBalance + operator, from, to, amount, data, operatorData, token: token.address, fromBalance, toBalance, }); } -async function sendFromHolder(token, holder, to, amount, data) { +async function sendFromHolder (token, holder, to, amount, data) { if ((await web3.eth.getCode(holder)).length <= '0x'.length) { return token.send(to, amount, data, { from: holder }); - } else { // assume holder is ERC777SenderMock contract return (await ERC777SenderMock.at(holder)).send(token.address, to, amount, data); } } -async function burnFromHolder(token, holder, amount, data) { +async function burnFromHolder (token, holder, amount, data) { if ((await web3.eth.getCode(holder)).length <= '0x'.length) { return token.burn(amount, data, { from: holder }); - } else { // assume holder is ERC777SenderMock contract return (await ERC777SenderMock.at(holder)).burn(token.address, amount, data); diff --git a/test/drafts/ERC777/ERC777.test.js b/test/drafts/ERC777/ERC777.test.js index 29e12a485a8..dfcda7b440c 100644 --- a/test/drafts/ERC777/ERC777.test.js +++ b/test/drafts/ERC777/ERC777.test.js @@ -234,28 +234,31 @@ contract('ERC777', function ([ const amount = new BN('1'); const recipient = anyone; const operator = defaultOperatorA; - let sender; + // sender is stored inside 'this', since for some tests its address is determined dynamically context('with a contract as implementer for an externally owned account', function () { - sender = holder; - beforeEach(async function () { - this.tokensSenderImplementer = await ERC777SenderMock.new(holder); - await this.erc1820.setInterfaceImplementer(holder, web3.utils.soliditySha3('ERC777TokensSender'), this.tokensSenderImplementer.address, { from: holder }); + this.sender = holder; + this.tokensSenderImplementer = await ERC777SenderMock.new(this.sender); + await this.erc1820.setInterfaceImplementer( + this.sender, + web3.utils.soliditySha3('ERC777TokensSender'), this.tokensSenderImplementer.address, + { from: this.sender }, + ); }); - shouldBehaveLikeERC777SendBurnWithHook(sender, recipient, operator, amount, data, operatorData); + shouldBehaveLikeERC777SendBurnWithHook(recipient, operator, amount, data, operatorData); }); context('with a contract as implementer for itself', function () { beforeEach(async function () { this.tokensSenderImplementer = await ERC777SenderMock.new(ZERO_ADDRESS); - sender = this.tokensSenderImplementer.address; - await this.token.send(sender, amount, data, { from: holder }); + this.sender = this.tokensSenderImplementer.address; + await this.token.send(this.sender, amount, data, { from: holder }); }); - shouldBehaveLikeERC777SendBurnWithHook(sender, recipient, operator, amount, data, operatorData); + shouldBehaveLikeERC777SendBurnWithHook(recipient, operator, amount, data, operatorData); }); }); }); From 060119f973149114ba13395fc96d2756c8c71528 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Wed, 10 Apr 2019 21:29:49 -0300 Subject: [PATCH 46/64] Update openzeppelin-test-helpers and ERC1820 address. --- contracts/drafts/ERC777/ERC777.sol | 2 +- contracts/mocks/ERC777ReceiverMock.sol | 2 +- contracts/mocks/ERC777SenderMock.sol | 2 +- package-lock.json | 54 +++++++++++++++++++------- package.json | 2 +- 5 files changed, 45 insertions(+), 17 deletions(-) diff --git a/contracts/drafts/ERC777/ERC777.sol b/contracts/drafts/ERC777/ERC777.sol index 6b4827ca07e..1ff6513cc69 100644 --- a/contracts/drafts/ERC777/ERC777.sol +++ b/contracts/drafts/ERC777/ERC777.sol @@ -15,7 +15,7 @@ contract ERC777 is IERC777 { using SafeMath for uint256; using Address for address; - IERC1820Registry private _erc1820 = IERC1820Registry(0x1820b744B33945482C17Dc37218C01D858EBc714); + IERC1820Registry private _erc1820 = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24); string private _name; diff --git a/contracts/mocks/ERC777ReceiverMock.sol b/contracts/mocks/ERC777ReceiverMock.sol index 7ee852969d1..8d5af398261 100644 --- a/contracts/mocks/ERC777ReceiverMock.sol +++ b/contracts/mocks/ERC777ReceiverMock.sol @@ -10,7 +10,7 @@ import "../drafts/IERC1820Registry.sol"; */ contract ERC777ReceiverMock is IERC777Recipient { - IERC1820Registry private _erc1820 = IERC1820Registry(0x1820b744B33945482C17Dc37218C01D858EBc714); + IERC1820Registry private _erc1820 = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24); event TokensReceived( address indexed operator, diff --git a/contracts/mocks/ERC777SenderMock.sol b/contracts/mocks/ERC777SenderMock.sol index 1ea1b3e3648..e75b8bc8894 100644 --- a/contracts/mocks/ERC777SenderMock.sol +++ b/contracts/mocks/ERC777SenderMock.sol @@ -19,7 +19,7 @@ contract ERC777SenderMock is IERC777Sender, ERC1820Implementer { ); bool private _shouldRevert; - IERC1820Registry private _erc1820 = IERC1820Registry(0x1820b744B33945482C17Dc37218C01D858EBc714); + IERC1820Registry private _erc1820 = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24); bytes32 constant private TOKENS_SENDER_INTERFACE_HASH = keccak256("ERC777TokensSender"); diff --git a/package-lock.json b/package-lock.json index 90aff2bb223..42830c06857 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6608,9 +6608,9 @@ } }, "openzeppelin-test-helpers": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/openzeppelin-test-helpers/-/openzeppelin-test-helpers-0.3.0.tgz", - "integrity": "sha512-+UC7/HHCzaBLbVy1Y/IlNFI3hqbiw5PuBGoQXbmduzh5QNrbiNbQOT1WlVTjoSDUCIDnHpFjnY5hJKF0kzitUg==", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/openzeppelin-test-helpers/-/openzeppelin-test-helpers-0.3.2.tgz", + "integrity": "sha512-PFTIzyYswBt5IiZu/qayIjnS1HJ+Mr0ekVzLfube/qcUGvoA4Ru5SJdit2FYKljaPdiyvLD1jYJJecA50A2RtA==", "dev": true, "requires": { "ansi-colors": "^3.2.3", @@ -6621,9 +6621,9 @@ }, "dependencies": { "semver": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", "dev": true } } @@ -8960,16 +8960,17 @@ "dev": true }, "truffle-contract": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/truffle-contract/-/truffle-contract-4.0.9.tgz", - "integrity": "sha512-416CbvnoR111mMspzyi4lLM5aNdypICiU6FfeSr/OBZekn7zdX432+fwUmFC+T4n+ncMEQuKkmIhxzrg7JR86w==", + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/truffle-contract/-/truffle-contract-4.0.11.tgz", + "integrity": "sha512-lzKFdLngTSt7MQMOvsUhOEPUjagSbGVkhQm7rSant4Y/VSWIppL3GXqpTOzdcOJMHgL9iYlMEm42+pHXq6DZxg==", "dev": true, "requires": { "bignumber.js": "^7.2.1", "ethers": "^4.0.0-beta.1", "truffle-blockchain-utils": "^0.0.8", - "truffle-contract-schema": "^3.0.3", + "truffle-contract-schema": "^3.0.6", "truffle-error": "^0.0.4", + "truffle-interface-adapter": "^0.1.2", "web3": "1.0.0-beta.37", "web3-core-promievent": "1.0.0-beta.37", "web3-eth-abi": "1.0.0-beta.37", @@ -8994,9 +8995,9 @@ } }, "truffle-contract-schema": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/truffle-contract-schema/-/truffle-contract-schema-3.0.3.tgz", - "integrity": "sha512-u7glieUcBcj5+o8aOppRLgViiI1CZI1wOWaniZ5eehCa11/HFW8Fow4mZDGeBTYX2xVUJJLCLEz3NsiY9yYWqA==", + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/truffle-contract-schema/-/truffle-contract-schema-3.0.6.tgz", + "integrity": "sha512-oAMPr/ecr06ViJMSatfp1VpbDNul0Q1dSrFkWSF4/6WWK4orhNL90A8uhtEt61doLz5n0Yjf59KWE0p7qToPXw==", "dev": true, "requires": { "ajv": "^5.1.1", @@ -9033,6 +9034,33 @@ "integrity": "sha512-hER0TNR4alBIhUp7SNrZRRiZtM/MBx+xBdM9qXP0tC3YASFmhNAxPuOyB8JDHFRNbDx12K7nvaqmyYGsI5c8BQ==", "dev": true }, + "truffle-interface-adapter": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/truffle-interface-adapter/-/truffle-interface-adapter-0.1.2.tgz", + "integrity": "sha512-1+pZprFU94mN8ydy4wVI2reW4iELDmsUADpa2ti++HwsX/T02yHK5+GxK3wQ9lXglRiI/B694fKFbHcv3t+Vxg==", + "dev": true, + "requires": { + "bn.js": "^4.11.8", + "web3": "1.0.0-beta.37" + }, + "dependencies": { + "web3": { + "version": "1.0.0-beta.37", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.0.0-beta.37.tgz", + "integrity": "sha512-8XLgUspdzicC/xHG82TLrcF/Fxzj2XYNJ1KTYnepOI77bj5rvpsxxwHYBWQ6/JOjk0HkZqoBfnXWgcIHCDhZhQ==", + "dev": true, + "requires": { + "web3-bzz": "1.0.0-beta.37", + "web3-core": "1.0.0-beta.37", + "web3-eth": "1.0.0-beta.37", + "web3-eth-personal": "1.0.0-beta.37", + "web3-net": "1.0.0-beta.37", + "web3-shh": "1.0.0-beta.37", + "web3-utils": "1.0.0-beta.37" + } + } + } + }, "tslib": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", diff --git a/package.json b/package.json index 6812aea85cb..6ba304ce5a8 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "ethjs-abi": "^0.2.1", "ganache-cli": "^6.4.1", "ganache-cli-coverage": "github:Agusx1211/ganache-cli#c462b3fc48fe9b16756f7799885c0741114d9ed3", - "openzeppelin-test-helpers": "^0.3.0", + "openzeppelin-test-helpers": "^0.3.2", "pify": "^4.0.1", "solhint": "^1.5.0", "solidity-coverage": "github:rotcivegaf/solidity-coverage#5875f5b7bc74d447f3312c9c0e9fc7814b482477", From 01c74fbb85406cdc9152b3e8310cc05c4fef1e1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Wed, 10 Apr 2019 21:33:53 -0300 Subject: [PATCH 47/64] Fix natspec indentation. --- contracts/drafts/ERC777/ERC777.sol | 116 ++++++++++++++--------------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/contracts/drafts/ERC777/ERC777.sol b/contracts/drafts/ERC777/ERC777.sol index 1ff6513cc69..e15457d7994 100644 --- a/contracts/drafts/ERC777/ERC777.sol +++ b/contracts/drafts/ERC777/ERC777.sol @@ -62,22 +62,22 @@ contract ERC777 is IERC777 { } /** - * @dev Send the amount of tokens from the address msg.sender to the address to - * @param to address recipient address - * @param amount uint256 amount of tokens to transfer - * @param data bytes information attached to the send, and intended for the recipient (to) + * @dev Send the amount of tokens from the address msg.sender to the address to + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param data bytes information attached to the send, and intended for the recipient (to) */ function send(address to, uint256 amount, bytes calldata data) external { _send(msg.sender, msg.sender, to, amount, data, ""); } /** - * @dev Send the amount of tokens on behalf of the address from to the address to - * @param from address token holder address. Set to 0x0 to use msg.sender as token holder - * @param to address recipient address - * @param amount uint256 amount of tokens to transfer - * @param data bytes information attached to the send, and intended for the recipient (to) - * @param operatorData bytes extra information provided by the operator (if any) + * @dev Send the amount of tokens on behalf of the address from to the address to + * @param from address token holder address. Set to 0x0 to use msg.sender as token holder + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param data bytes information attached to the send, and intended for the recipient (to) + * @param operatorData bytes extra information provided by the operator (if any) */ function operatorSend( address from, @@ -100,20 +100,20 @@ contract ERC777 is IERC777 { } /** - * @dev Burn the amount of tokens from the address msg.sender - * @param amount uint256 amount of tokens to transfer - * @param data bytes extra information provided by the token holder + * @dev Burn the amount of tokens from the address msg.sender + * @param amount uint256 amount of tokens to transfer + * @param data bytes extra information provided by the token holder */ function burn(uint256 amount, bytes calldata data) external { _burn(msg.sender, msg.sender, amount, data, ""); } /** - * @dev Burn the amount of tokens on behalf of the address from - * @param from address token holder address. Set to 0x0 to use msg.sender as token holder - * @param amount uint256 amount of tokens to transfer - * @param data bytes extra information provided by the token holder - * @param operatorData bytes extra information provided by the operator (if any) + * @dev Burn the amount of tokens on behalf of the address from + * @param from address token holder address. Set to 0x0 to use msg.sender as token holder + * @param amount uint256 amount of tokens to transfer + * @param data bytes extra information provided by the token holder + * @param operatorData bytes extra information provided by the operator (if any) */ function operatorBurn(address from, uint256 amount, bytes calldata data, bytes calldata operatorData) external { address holder = from == address(0) ? msg.sender : from; @@ -121,15 +121,15 @@ contract ERC777 is IERC777 { } /** - * @return the name of the token. - */ + * @return the name of the token. + * / function name() public view returns (string memory) { return _name; } /** - * @return the symbol of the token. - */ + * @return the symbol of the token. + * / function symbol() public view returns (string memory) { return _symbol; } @@ -142,8 +142,8 @@ contract ERC777 is IERC777 { } /** - * @dev Gets the balance of the specified address. - * @param tokenHolder The address to query the balance of. + * @dev Gets the balance of the specified address. + * @param tokenHolder The address to query the balance of. * @return uint256 representing the amount owned by the specified address. */ function balanceOf(address tokenHolder) public view returns (uint256) { @@ -151,26 +151,26 @@ contract ERC777 is IERC777 { } /** - * @dev Gets the token's granularity, - * i.e. the smallest number of tokens (in the basic unit) - * which may be minted, sent or burned at any time - * @return uint256 granularity + * @dev Gets the token's granularity, + * i.e. the smallest number of tokens (in the basic unit) + * which may be minted, sent or burned at any time + * @return uint256 granularity */ function granularity() public view returns (uint256) { return _granularity; } /** - * @dev Get the list of default operators as defined by the token contract. - * @return address[] default operators - */ + * @dev Get the list of default operators as defined by the token contract. + * @return address[] default operators + * / function defaultOperators() public view returns (address[] memory) { return _defaultOperatorsArray; } /** - * @dev Authorize an operator for the sender - * @param operator address to be authorized as operator + * @dev Authorize an operator for the sender + * @param operator address to be authorized as operator */ function authorizeOperator(address operator) public { require(msg.sender != operator); @@ -195,11 +195,11 @@ contract ERC777 is IERC777 { } /** - * @dev Indicate whether an address - * is an operator of the tokenHolder address - * @param operator address which may be an operator of tokenHolder - * @param tokenHolder address of a token holder which may have the operator - * address as an operator. + * @dev Indicate whether an address + * is an operator of the tokenHolder address + * @param operator address which may be an operator of tokenHolder + * @param tokenHolder address of a token holder which may have the operator + * address as an operator. */ function isOperatorFor( address operator, @@ -243,8 +243,8 @@ contract ERC777 is IERC777 { } /** - * @dev Authorize an operator for the sender - * @param operator address to be authorized as operator + * @dev Authorize an operator for the sender + * @param operator address to be authorized as operator */ function _authorizeOperator(address operator) private { _operators[msg.sender][operator] = true; @@ -252,8 +252,8 @@ contract ERC777 is IERC777 { } /** - * @dev Re-authorize a previously revoked default operator - * @param operator address to be re-authorized as operator + * @dev Re-authorize a previously revoked default operator + * @param operator address to be re-authorized as operator */ function _reAuthorizeDefaultOperator(address operator) private { delete _revokedDefaultOperators[msg.sender][operator]; @@ -261,18 +261,18 @@ contract ERC777 is IERC777 { } /** - * @dev Revoke operator rights from one of the default operators - * @param operator address to revoke operator rights from - */ + * @dev Revoke operator rights from one of the default operators + * @param operator address to revoke operator rights from + */ function _revokeDefaultOperator(address operator) private { _revokedDefaultOperators[msg.sender][operator] = true; emit RevokedOperator(operator, msg.sender); } /** - * @dev Revoke an operator for the sender - * @param operator address to revoke operator rights from - */ + * @dev Revoke an operator for the sender + * @param operator address to revoke operator rights from + */ function _revokeOperator(address operator) private { delete _operators[msg.sender][operator]; emit RevokedOperator(operator, msg.sender); @@ -371,16 +371,16 @@ contract ERC777 is IERC777 { } /** - * @dev Call to.tokensReceived() if the interface is registered - * @param operator address operator requesting the transfer - * @param from address token holder address - * @param to address recipient address - * @param amount uint256 amount of tokens to transfer - * @param userData bytes extra information provided by the token holder (if any) - * @param operatorData bytes extra information provided by the operator (if any) - * @return false if the recipient is a contract but tokensReceived() was not - * registered for the recipient - */ + * @dev Call to.tokensReceived() if the interface is registered + * @param operator address operator requesting the transfer + * @param from address token holder address + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param userData bytes extra information provided by the token holder (if any) + * @param operatorData bytes extra information provided by the operator (if any) + * @return false if the recipient is a contract but tokensReceived() was not + * registered for the recipient + */ function _callTokensReceived( address operator, address from, From 100a1cba64be30aa65bbdc09dc2f2189218bb6d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Wed, 10 Apr 2019 21:36:29 -0300 Subject: [PATCH 48/64] Make interface functions external. --- contracts/drafts/ERC777/ERC777.sol | 58 +++++++++++++++--------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/contracts/drafts/ERC777/ERC777.sol b/contracts/drafts/ERC777/ERC777.sol index e15457d7994..f7441ebb222 100644 --- a/contracts/drafts/ERC777/ERC777.sol +++ b/contracts/drafts/ERC777/ERC777.sol @@ -120,16 +120,42 @@ contract ERC777 is IERC777 { _burn(msg.sender, holder, amount, data, operatorData); } + /** + * @dev Authorize an operator for the sender + * @param operator address to be authorized as operator + */ + function authorizeOperator(address operator) external { + require(msg.sender != operator); + if (_defaultOperators[operator]) { + _reAuthorizeDefaultOperator(operator); + } else { + _authorizeOperator(operator); + } + } + + /** + * @dev Revoke operator rights from one of the default operators + * @param operator address to revoke operator rights from + */ + function revokeOperator(address operator) external { + require(operator != msg.sender); + if (_defaultOperators[operator]) { + _revokeDefaultOperator(operator); + } else { + _revokeOperator(operator); + } + } + /** * @return the name of the token. - * / + */ function name() public view returns (string memory) { return _name; } /** * @return the symbol of the token. - * / + */ function symbol() public view returns (string memory) { return _symbol; } @@ -163,37 +189,11 @@ contract ERC777 is IERC777 { /** * @dev Get the list of default operators as defined by the token contract. * @return address[] default operators - * / + */ function defaultOperators() public view returns (address[] memory) { return _defaultOperatorsArray; } - /** - * @dev Authorize an operator for the sender - * @param operator address to be authorized as operator - */ - function authorizeOperator(address operator) public { - require(msg.sender != operator); - if (_defaultOperators[operator]) { - _reAuthorizeDefaultOperator(operator); - } else { - _authorizeOperator(operator); - } - } - - /** - * @dev Revoke operator rights from one of the default operators - * @param operator address to revoke operator rights from - */ - function revokeOperator(address operator) public { - require(operator != msg.sender); - if (_defaultOperators[operator]) { - _revokeDefaultOperator(operator); - } else { - _revokeOperator(operator); - } - } - /** * @dev Indicate whether an address * is an operator of the tokenHolder address From b17f6c5da9a4e73bef12c6d0f0f6d9af98c69253 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Wed, 10 Apr 2019 21:49:22 -0300 Subject: [PATCH 49/64] Remove redundant private revoke and authorize functions. --- contracts/drafts/ERC777/ERC777.sol | 50 ++++++------------------------ 1 file changed, 10 insertions(+), 40 deletions(-) diff --git a/contracts/drafts/ERC777/ERC777.sol b/contracts/drafts/ERC777/ERC777.sol index f7441ebb222..62aba2d8b1b 100644 --- a/contracts/drafts/ERC777/ERC777.sol +++ b/contracts/drafts/ERC777/ERC777.sol @@ -126,11 +126,14 @@ contract ERC777 is IERC777 { */ function authorizeOperator(address operator) external { require(msg.sender != operator); + if (_defaultOperators[operator]) { - _reAuthorizeDefaultOperator(operator); + delete _revokedDefaultOperators[msg.sender][operator]; } else { - _authorizeOperator(operator); + _operators[msg.sender][operator] = true; } + + emit AuthorizedOperator(operator, msg.sender); } /** @@ -139,11 +142,14 @@ contract ERC777 is IERC777 { */ function revokeOperator(address operator) external { require(operator != msg.sender); + if (_defaultOperators[operator]) { - _revokeDefaultOperator(operator); + _revokedDefaultOperators[msg.sender][operator] = true; } else { - _revokeOperator(operator); + delete _operators[msg.sender][operator]; } + + emit RevokedOperator(operator, msg.sender); } /** @@ -242,42 +248,6 @@ contract ERC777 is IERC777 { emit Minted(operator, to, amount, userData, operatorData); } - /** - * @dev Authorize an operator for the sender - * @param operator address to be authorized as operator - */ - function _authorizeOperator(address operator) private { - _operators[msg.sender][operator] = true; - emit AuthorizedOperator(operator, msg.sender); - } - - /** - * @dev Re-authorize a previously revoked default operator - * @param operator address to be re-authorized as operator - */ - function _reAuthorizeDefaultOperator(address operator) private { - delete _revokedDefaultOperators[msg.sender][operator]; - emit AuthorizedOperator(operator, msg.sender); - } - - /** - * @dev Revoke operator rights from one of the default operators - * @param operator address to revoke operator rights from - */ - function _revokeDefaultOperator(address operator) private { - _revokedDefaultOperators[msg.sender][operator] = true; - emit RevokedOperator(operator, msg.sender); - } - - /** - * @dev Revoke an operator for the sender - * @param operator address to revoke operator rights from - */ - function _revokeOperator(address operator) private { - delete _operators[msg.sender][operator]; - emit RevokedOperator(operator, msg.sender); - } - /** * @dev Send tokens * @param operator address operator requesting the transfer From 294546338758a7d9c4a618b9e5754041302f6e79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Wed, 10 Apr 2019 21:49:49 -0300 Subject: [PATCH 50/64] Improved readability of if statement. --- contracts/drafts/ERC777/ERC777.sol | 2 +- test/drafts/ERC777/ERC777.test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/drafts/ERC777/ERC777.sol b/contracts/drafts/ERC777/ERC777.sol index 62aba2d8b1b..a208cf78744 100644 --- a/contracts/drafts/ERC777/ERC777.sol +++ b/contracts/drafts/ERC777/ERC777.sol @@ -212,7 +212,7 @@ contract ERC777 is IERC777 { address tokenHolder ) public view returns (bool) { return operator == tokenHolder || - _defaultOperators[operator] && !_revokedDefaultOperators[tokenHolder][operator] || + (_defaultOperators[operator] && !_revokedDefaultOperators[tokenHolder][operator]) || _operators[tokenHolder][operator]; } diff --git a/test/drafts/ERC777/ERC777.test.js b/test/drafts/ERC777/ERC777.test.js index dfcda7b440c..a6c019e6937 100644 --- a/test/drafts/ERC777/ERC777.test.js +++ b/test/drafts/ERC777/ERC777.test.js @@ -12,7 +12,7 @@ const { const ERC777 = artifacts.require('ERC777Mock'); const ERC777SenderMock = artifacts.require('ERC777SenderMock'); -contract('ERC777', function ([ +contract.only('ERC777', function ([ _, registryFunder, holder, defaultOperatorA, defaultOperatorB, newOperator, anyone, ]) { const initialSupply = new BN('10000'); From 029a021f6a02da602d0d1bbd22804c92e1c74e0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Wed, 10 Apr 2019 21:53:25 -0300 Subject: [PATCH 51/64] Remove unnecessary asserts. --- contracts/drafts/ERC777/ERC777.sol | 4 ---- 1 file changed, 4 deletions(-) diff --git a/contracts/drafts/ERC777/ERC777.sol b/contracts/drafts/ERC777/ERC777.sol index a208cf78744..d3db692e83d 100644 --- a/contracts/drafts/ERC777/ERC777.sol +++ b/contracts/drafts/ERC777/ERC777.sol @@ -243,7 +243,6 @@ contract ERC777 is IERC777 { // Update state variables _totalSupply = _totalSupply.add(amount); _balances[to] = _balances[to].add(amount); - assert((_balances[to] % _granularity) == 0); emit Minted(operator, to, amount, userData, operatorData); } @@ -276,8 +275,6 @@ contract ERC777 is IERC777 { // Update state variables _balances[from] = _balances[from].sub(amount); _balances[to] = _balances[to].add(amount); - assert((_balances[from] % _granularity) == 0); - assert((_balances[to] % _granularity) == 0); _callTokensReceived(operator, from, to, amount, userData, operatorData); @@ -310,7 +307,6 @@ contract ERC777 is IERC777 { // Update state variables _totalSupply = _totalSupply.sub(amount); _balances[from] = _balances[from].sub(amount); - assert((_balances[from] % _granularity) == 0); emit Burned(operator, from, amount, data, operatorData); } From db2b2f5fc6da817f12ac894f69923812f166bdb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Wed, 10 Apr 2019 21:55:32 -0300 Subject: [PATCH 52/64] Add non-one granularity test. --- test/drafts/ERC777/ERC777.test.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/drafts/ERC777/ERC777.test.js b/test/drafts/ERC777/ERC777.test.js index a6c019e6937..3bd4046bf05 100644 --- a/test/drafts/ERC777/ERC777.test.js +++ b/test/drafts/ERC777/ERC777.test.js @@ -12,7 +12,7 @@ const { const ERC777 = artifacts.require('ERC777Mock'); const ERC777SenderMock = artifacts.require('ERC777SenderMock'); -contract.only('ERC777', function ([ +contract('ERC777', function ([ _, registryFunder, holder, defaultOperatorA, defaultOperatorB, newOperator, anyone, ]) { const initialSupply = new BN('10000'); @@ -53,7 +53,7 @@ contract.only('ERC777', function ([ }); it('returns the granularity', async function () { - (await this.token.granularity()).should.be.bignumber.equal('1'); + (await this.token.granularity()).should.be.bignumber.equal(granularity); }); it('returns the default operators', async function () { @@ -284,6 +284,10 @@ contract.only('ERC777', function ([ this.token = await ERC777.new(holder, initialSupply, name, symbol, granularity, defaultOperators); }); + it('returns the granularity', async function () { + (await this.token.granularity()).should.be.bignumber.equal(granularity); + }); + context('when the sender has tokens', function () { const from = holder; From 35185258cd5f6cbb6d121d3b904a5b2c27cf16d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Wed, 10 Apr 2019 21:59:16 -0300 Subject: [PATCH 53/64] Fix hook call order in _mint. --- contracts/drafts/ERC777/ERC777.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/drafts/ERC777/ERC777.sol b/contracts/drafts/ERC777/ERC777.sol index d3db692e83d..5660393cc73 100644 --- a/contracts/drafts/ERC777/ERC777.sol +++ b/contracts/drafts/ERC777/ERC777.sol @@ -237,13 +237,13 @@ contract ERC777 is IERC777 { require(to != address(0)); require((amount % _granularity) == 0); - // revert if 'to' is a contract not implementing tokensReceived() - require(_callTokensReceived(operator, address(0), to, amount, userData, operatorData)); - // Update state variables _totalSupply = _totalSupply.add(amount); _balances[to] = _balances[to].add(amount); + // revert if 'to' is a contract not implementing tokensReceived() + require(_callTokensReceived(operator, address(0), to, amount, userData, operatorData)); + emit Minted(operator, to, amount, userData, operatorData); } From 7e91c3f353eec479e8f5bcf4d8657d48e038cbd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Wed, 10 Apr 2019 22:03:07 -0300 Subject: [PATCH 54/64] Fix _mint not reverting on failure to implement tokensReceived. --- contracts/drafts/ERC777/ERC777.sol | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/contracts/drafts/ERC777/ERC777.sol b/contracts/drafts/ERC777/ERC777.sol index 5660393cc73..63851245af6 100644 --- a/contracts/drafts/ERC777/ERC777.sol +++ b/contracts/drafts/ERC777/ERC777.sol @@ -241,8 +241,7 @@ contract ERC777 is IERC777 { _totalSupply = _totalSupply.add(amount); _balances[to] = _balances[to].add(amount); - // revert if 'to' is a contract not implementing tokensReceived() - require(_callTokensReceived(operator, address(0), to, amount, userData, operatorData)); + _callTokensReceived(operator, address(0), to, amount, userData, operatorData); emit Minted(operator, to, amount, userData, operatorData); } @@ -337,15 +336,14 @@ contract ERC777 is IERC777 { } /** - * @dev Call to.tokensReceived() if the interface is registered + * @dev Call to.tokensReceived() if the interface is registered. Reverts if the recipient is a contract but + * tokensReceived() was not registered for the recipient * @param operator address operator requesting the transfer * @param from address token holder address * @param to address recipient address * @param amount uint256 amount of tokens to transfer * @param userData bytes extra information provided by the token holder (if any) * @param operatorData bytes extra information provided by the operator (if any) - * @return false if the recipient is a contract but tokensReceived() was not - * registered for the recipient */ function _callTokensReceived( address operator, @@ -356,13 +354,12 @@ contract ERC777 is IERC777 { bytes memory operatorData ) private - returns(bool) { address implementer = _erc1820.getInterfaceImplementer(to, TOKENS_RECIPIENT_INTERFACE_HASH); - if (implementer == address(0)) { - return(!to.isContract()); + if (implementer != address(0)) { + IERC777Recipient(implementer).tokensReceived(operator, from, to, amount, userData, operatorData); + } else { + require(!to.isContract()); } - IERC777Recipient(implementer).tokensReceived(operator, from, to, amount, userData, operatorData); - return true; } } From 2cff2cea9e7eb7086dcd3e87804b1e86ab87ea8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Thu, 11 Apr 2019 01:34:31 -0300 Subject: [PATCH 55/64] Remove special case in operatorFn when from is 0. --- contracts/drafts/ERC777/ERC777.sol | 20 ++++++-------------- test/drafts/ERC777/ERC777.behavior.js | 4 ++-- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/contracts/drafts/ERC777/ERC777.sol b/contracts/drafts/ERC777/ERC777.sol index 63851245af6..dee73d7a829 100644 --- a/contracts/drafts/ERC777/ERC777.sol +++ b/contracts/drafts/ERC777/ERC777.sol @@ -73,7 +73,7 @@ contract ERC777 is IERC777 { /** * @dev Send the amount of tokens on behalf of the address from to the address to - * @param from address token holder address. Set to 0x0 to use msg.sender as token holder + * @param from address token holder address. * @param to address recipient address * @param amount uint256 amount of tokens to transfer * @param data bytes information attached to the send, and intended for the recipient (to) @@ -88,15 +88,8 @@ contract ERC777 is IERC777 { ) external { - address holder; - if (from == address(0)) { - holder = msg.sender; - } else { - holder = from; - require(isOperatorFor(msg.sender, holder)); - } - - _send(msg.sender, holder, to, amount, data, operatorData); + require(isOperatorFor(msg.sender, from)); + _send(msg.sender, from, to, amount, data, operatorData); } /** @@ -110,14 +103,14 @@ contract ERC777 is IERC777 { /** * @dev Burn the amount of tokens on behalf of the address from - * @param from address token holder address. Set to 0x0 to use msg.sender as token holder + * @param from address token holder address. * @param amount uint256 amount of tokens to transfer * @param data bytes extra information provided by the token holder * @param operatorData bytes extra information provided by the operator (if any) */ function operatorBurn(address from, uint256 amount, bytes calldata data, bytes calldata operatorData) external { - address holder = from == address(0) ? msg.sender : from; - _burn(msg.sender, holder, amount, data, operatorData); + require(isOperatorFor(msg.sender, from)); + _burn(msg.sender, from, amount, data, operatorData); } /** @@ -298,7 +291,6 @@ contract ERC777 is IERC777 { private { require(from != address(0)); - require(isOperatorFor(msg.sender, from)); require((amount % _granularity) == 0); _callTokensToSend(operator, from, address(0), amount, data, operatorData); diff --git a/test/drafts/ERC777/ERC777.behavior.js b/test/drafts/ERC777/ERC777.behavior.js index 95b2e8d7ff6..3051c199648 100644 --- a/test/drafts/ERC777/ERC777.behavior.js +++ b/test/drafts/ERC777/ERC777.behavior.js @@ -79,7 +79,7 @@ function shouldBehaveLikeERC777OperatorSend (holder, recipient, operator, data, ); }); - it.skip('reverts when sending from the zero address', async function () { + it('reverts when sending from the zero address', async function () { // This is not yet reflected in the spec await shouldFail.reverting( this.token.operatorSend( @@ -148,7 +148,7 @@ function shouldBehaveLikeERC777OperatorBurn (holder, operator, data, operatorDat ); }); - it.skip('reverts when burning from the zero address', async function () { + it('reverts when burning from the zero address', async function () { // This is not yet reflected in the spec await shouldFail.reverting( this.token.operatorBurn( From cec8ebe978ad41de0551a14f58917f8a92432d85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Thu, 11 Apr 2019 12:10:44 -0300 Subject: [PATCH 56/64] Refactor ERC777SenderMock. --- ...Mock.sol => ERC777SenderRecipientMock.sol} | 73 +++++++++++++++++-- test/drafts/ERC777/ERC777.behavior.js | 16 ++-- test/drafts/ERC777/ERC777.test.js | 9 ++- 3 files changed, 81 insertions(+), 17 deletions(-) rename contracts/mocks/{ERC777SenderMock.sol => ERC777SenderRecipientMock.sol} (50%) diff --git a/contracts/mocks/ERC777SenderMock.sol b/contracts/mocks/ERC777SenderRecipientMock.sol similarity index 50% rename from contracts/mocks/ERC777SenderMock.sol rename to contracts/mocks/ERC777SenderRecipientMock.sol index e75b8bc8894..152c0ba987e 100644 --- a/contracts/mocks/ERC777SenderMock.sol +++ b/contracts/mocks/ERC777SenderRecipientMock.sol @@ -2,10 +2,11 @@ pragma solidity ^0.5.2; import "../drafts/ERC777/IERC777.sol"; import "../drafts/ERC777/IERC777Sender.sol"; +import "../drafts/ERC777/IERC777Recipient.sol"; import "../drafts/IERC1820Registry.sol"; import "../drafts/ERC1820Implementer.sol"; -contract ERC777SenderMock is IERC777Sender, ERC1820Implementer { +contract ERC777SenderRecipientMock is IERC777Sender, IERC777Recipient, ERC1820Implementer { event TokensToSendCalled( address operator, address from, @@ -18,12 +19,27 @@ contract ERC777SenderMock is IERC777Sender, ERC1820Implementer { uint256 toBalance ); - bool private _shouldRevert; + event TokensReceivedCalled( + address operator, + address from, + address to, + uint256 amount, + bytes data, + bytes operatorData, + address token, + uint256 fromBalance, + uint256 toBalance + ); + + bool private _shouldRevertSend; + bool private _shouldRevertReceive; + IERC1820Registry private _erc1820 = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24); bytes32 constant private TOKENS_SENDER_INTERFACE_HASH = keccak256("ERC777TokensSender"); + bytes32 constant private TOKENS_RECIPIENT_INTERFACE_HASH = keccak256("ERC777TokensRecipient"); - constructor(address account) public { + function senderFor(address account) public { if (account != address(0)) { _registerInterfaceForAddress(TOKENS_SENDER_INTERFACE_HASH, account); } else { @@ -33,6 +49,16 @@ contract ERC777SenderMock is IERC777Sender, ERC1820Implementer { } } + function recipientFor(address account) public { + if (account != address(0)) { + _registerInterfaceForAddress(TOKENS_RECIPIENT_INTERFACE_HASH, account); + } else { + address self = address(this); + _registerInterfaceForAddress(TOKENS_RECIPIENT_INTERFACE_HASH, self); + _erc1820.setInterfaceImplementer(self, TOKENS_RECIPIENT_INTERFACE_HASH, self); + } + } + function tokensToSend( address operator, address from, @@ -41,7 +67,7 @@ contract ERC777SenderMock is IERC777Sender, ERC1820Implementer { bytes calldata userData, bytes calldata operatorData ) external { - if (_shouldRevert) { + if (_shouldRevertSend) { revert(); } @@ -64,8 +90,43 @@ contract ERC777SenderMock is IERC777Sender, ERC1820Implementer { ); } - function setShouldRevert(bool shouldRevert) public { - _shouldRevert = shouldRevert; + function tokensReceived( + address operator, + address from, + address to, + uint amount, + bytes calldata userData, + bytes calldata operatorData + ) external{ + if (_shouldRevertReceive) { + revert(); + } + + IERC777 token = IERC777(msg.sender); + + uint256 fromBalance = token.balanceOf(from); + // when called due to burn, to will be the zero address, which will have a balance of 0 + uint256 toBalance = token.balanceOf(to); + + emit TokensReceivedCalled( + operator, + from, + to, + amount, + userData, + operatorData, + address(token), + fromBalance, + toBalance + ); + } + + function setShouldRevertSend(bool shouldRevert) public { + _shouldRevertSend = shouldRevert; + } + + function setShouldRevertReceive(bool shouldRevert) public { + _shouldRevertReceive = shouldRevert; } function send(IERC777 token, address to, uint256 amount, bytes memory data) public { diff --git a/test/drafts/ERC777/ERC777.behavior.js b/test/drafts/ERC777/ERC777.behavior.js index 3051c199648..d1f7d293acb 100644 --- a/test/drafts/ERC777/ERC777.behavior.js +++ b/test/drafts/ERC777/ERC777.behavior.js @@ -1,7 +1,7 @@ const { BN, constants, expectEvent, shouldFail } = require('openzeppelin-test-helpers'); const { ZERO_ADDRESS } = constants; -const ERC777SenderMock = artifacts.require('ERC777SenderMock'); +const ERC777SenderRecipientMock = artifacts.require('ERC777SenderRecipientMock'); function shouldBehaveLikeERC777DirectSendBurn (holder, recipient, data) { shouldBehaveLikeERC777DirectSend(holder, recipient, data); @@ -262,7 +262,7 @@ function shouldBurnTokens (from, operator, amount, data, operatorData) { function shouldBehaveLikeERC777SendBurnWithHook (recipient, operator, amount, data, operatorData) { context('when TokensSender reverts', function () { beforeEach(async function () { - await this.tokensSenderImplementer.setShouldRevert(true); + await this.tokensSenderImplementer.setShouldRevertSend(true); }); it('send reverts', async function () { @@ -288,7 +288,7 @@ function shouldBehaveLikeERC777SendBurnWithHook (recipient, operator, amount, da context('when TokensSender does not revert', function () { beforeEach(async function () { - await this.tokensSenderImplementer.setShouldRevert(false); + await this.tokensSenderImplementer.setShouldRevertSend(false); }); it('TokensSender receives send data and is called before state mutation', async function () { @@ -356,7 +356,7 @@ function removeBalance (holder) { async function assertTokensToSendCalled (token, txHash, operator, from, to, amount, data, operatorData, fromBalance, toBalance = '0') { - await expectEvent.inTransaction(txHash, ERC777SenderMock, 'TokensToSendCalled', { + await expectEvent.inTransaction(txHash, ERC777SenderRecipientMock, 'TokensToSendCalled', { operator, from, to, amount, data, operatorData, token: token.address, fromBalance, toBalance, }); } @@ -365,8 +365,8 @@ async function sendFromHolder (token, holder, to, amount, data) { if ((await web3.eth.getCode(holder)).length <= '0x'.length) { return token.send(to, amount, data, { from: holder }); } else { - // assume holder is ERC777SenderMock contract - return (await ERC777SenderMock.at(holder)).send(token.address, to, amount, data); + // assume holder is ERC777SenderRecipientMock contract + return (await ERC777SenderRecipientMock.at(holder)).send(token.address, to, amount, data); } } @@ -374,8 +374,8 @@ async function burnFromHolder (token, holder, amount, data) { if ((await web3.eth.getCode(holder)).length <= '0x'.length) { return token.burn(amount, data, { from: holder }); } else { - // assume holder is ERC777SenderMock contract - return (await ERC777SenderMock.at(holder)).burn(token.address, amount, data); + // assume holder is ERC777SenderRecipientMock contract + return (await ERC777SenderRecipientMock.at(holder)).burn(token.address, amount, data); } } diff --git a/test/drafts/ERC777/ERC777.test.js b/test/drafts/ERC777/ERC777.test.js index 3bd4046bf05..77d6e90b365 100644 --- a/test/drafts/ERC777/ERC777.test.js +++ b/test/drafts/ERC777/ERC777.test.js @@ -10,7 +10,7 @@ const { } = require('./ERC777.behavior'); const ERC777 = artifacts.require('ERC777Mock'); -const ERC777SenderMock = artifacts.require('ERC777SenderMock'); +const ERC777SenderRecipientMock = artifacts.require('ERC777SenderRecipientMock'); contract('ERC777', function ([ _, registryFunder, holder, defaultOperatorA, defaultOperatorB, newOperator, anyone, @@ -239,7 +239,9 @@ contract('ERC777', function ([ context('with a contract as implementer for an externally owned account', function () { beforeEach(async function () { this.sender = holder; - this.tokensSenderImplementer = await ERC777SenderMock.new(this.sender); + this.tokensSenderImplementer = await ERC777SenderRecipientMock.new(); + await this.tokensSenderImplementer.senderFor(this.sender); + await this.erc1820.setInterfaceImplementer( this.sender, web3.utils.soliditySha3('ERC777TokensSender'), this.tokensSenderImplementer.address, @@ -252,7 +254,8 @@ contract('ERC777', function ([ context('with a contract as implementer for itself', function () { beforeEach(async function () { - this.tokensSenderImplementer = await ERC777SenderMock.new(ZERO_ADDRESS); + this.tokensSenderImplementer = await ERC777SenderRecipientMock.new(); + await this.tokensSenderImplementer.senderFor(ZERO_ADDRESS); this.sender = this.tokensSenderImplementer.address; await this.token.send(this.sender, amount, data, { from: holder }); From 8e2af46d501c01f335f1b450b48e4da870bda63b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Thu, 11 Apr 2019 13:56:19 -0300 Subject: [PATCH 57/64] Add tokensReceived tests. --- contracts/mocks/ERC777ReceiverMock.sol | 63 --------- contracts/mocks/ERC777SenderRecipientMock.sol | 30 +++-- test/drafts/ERC777/ERC777.behavior.js | 109 +++++++++++++--- test/drafts/ERC777/ERC777.test.js | 123 ++++++++++++++++-- 4 files changed, 221 insertions(+), 104 deletions(-) delete mode 100644 contracts/mocks/ERC777ReceiverMock.sol diff --git a/contracts/mocks/ERC777ReceiverMock.sol b/contracts/mocks/ERC777ReceiverMock.sol deleted file mode 100644 index 8d5af398261..00000000000 --- a/contracts/mocks/ERC777ReceiverMock.sol +++ /dev/null @@ -1,63 +0,0 @@ -pragma solidity ^0.5.2; - -import "../drafts/ERC777/IERC777Recipient.sol"; -import "../drafts/IERC1820Registry.sol"; - -/** - * @title ERC777TokensRecipientMock a contract that implements tokensReceived() hook - * @author Bertrand Masius - * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-777.md - */ -contract ERC777ReceiverMock is IERC777Recipient { - - IERC1820Registry private _erc1820 = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24); - - event TokensReceived( - address indexed operator, - address indexed from, - address indexed to, - uint256 amount, - bytes data, - bytes operatorData - ); - - constructor(bool setInterface) public { - // register interface - if (setInterface) { - _erc1820.setInterfaceImplementer( - address(this), - keccak256("ERC777TokensRecipient"), - address(this) - ); - } - } - - /** - * @dev tokensReceived() hook - * @param operator address operator requesting the transfer - * @param from address token holder address - * @param to address recipient address - * @param amount uint256 amount of tokens to transfer - * @param userData bytes extra information provided by the token holder (if any) - * @param operatorData bytes extra information provided by the operator (if any) - */ - function tokensReceived( - address operator, - address from, - address to, - uint256 amount, - bytes calldata userData, - bytes calldata operatorData - ) - external - { - emit TokensReceived( - operator, - from, - to, - amount, - userData, - operatorData - ); - } -} diff --git a/contracts/mocks/ERC777SenderRecipientMock.sol b/contracts/mocks/ERC777SenderRecipientMock.sol index 152c0ba987e..e93bfbda2f7 100644 --- a/contracts/mocks/ERC777SenderRecipientMock.sol +++ b/contracts/mocks/ERC777SenderRecipientMock.sol @@ -40,25 +40,31 @@ contract ERC777SenderRecipientMock is IERC777Sender, IERC777Recipient, ERC1820Im bytes32 constant private TOKENS_RECIPIENT_INTERFACE_HASH = keccak256("ERC777TokensRecipient"); function senderFor(address account) public { - if (account != address(0)) { - _registerInterfaceForAddress(TOKENS_SENDER_INTERFACE_HASH, account); - } else { - address self = address(this); - _registerInterfaceForAddress(TOKENS_SENDER_INTERFACE_HASH, self); - _erc1820.setInterfaceImplementer(self, TOKENS_SENDER_INTERFACE_HASH, self); + _registerInterfaceForAddress(TOKENS_SENDER_INTERFACE_HASH, account); + + address self = address(this); + if (account == self) { + registerSender(self); } } + function registerSender(address sender) public { + _erc1820.setInterfaceImplementer(address(this), TOKENS_SENDER_INTERFACE_HASH, sender); + } + function recipientFor(address account) public { - if (account != address(0)) { - _registerInterfaceForAddress(TOKENS_RECIPIENT_INTERFACE_HASH, account); - } else { - address self = address(this); - _registerInterfaceForAddress(TOKENS_RECIPIENT_INTERFACE_HASH, self); - _erc1820.setInterfaceImplementer(self, TOKENS_RECIPIENT_INTERFACE_HASH, self); + _registerInterfaceForAddress(TOKENS_RECIPIENT_INTERFACE_HASH, account); + + address self = address(this); + if (account == self) { + registerRecipient(self); } } + function registerRecipient(address recipient) public { + _erc1820.setInterfaceImplementer(address(this), TOKENS_RECIPIENT_INTERFACE_HASH, recipient); + } + function tokensToSend( address operator, address from, diff --git a/test/drafts/ERC777/ERC777.behavior.js b/test/drafts/ERC777/ERC777.behavior.js index d1f7d293acb..93320cb9b1d 100644 --- a/test/drafts/ERC777/ERC777.behavior.js +++ b/test/drafts/ERC777/ERC777.behavior.js @@ -259,19 +259,86 @@ function shouldBurnTokens (from, operator, amount, data, operatorData) { }); } -function shouldBehaveLikeERC777SendBurnWithHook (recipient, operator, amount, data, operatorData) { +function shouldBehaveLikeERC777SendBurnWithReceiveHook (operator, amount, data, operatorData) { + context('when TokensRecipient reverts', function () { + beforeEach(async function () { + await this.tokensRecipientImplementer.setShouldRevertReceive(true); + }); + + it('send reverts', async function () { + await shouldFail.reverting(sendFromHolder(this.token, this.sender, this.recipient, amount, data)); + }); + + it('operatorSend reverts', async function () { + await shouldFail.reverting( + this.token.operatorSend(this.sender, this.recipient, amount, data, operatorData, { from: operator }) + ); + }); + }); + + context('when TokensRecipient does not revert', function () { + beforeEach(async function () { + await this.tokensRecipientImplementer.setShouldRevertSend(false); + }); + + it('TokensRecipient receives send data and is called after state mutation', async function () { + const { tx } = await sendFromHolder(this.token, this.sender, this.recipient, amount, data); + + const postSenderBalance = await this.token.balanceOf(this.sender); + const postRecipientBalance = await this.token.balanceOf(this.recipient); + + await assertTokensReceivedCalled( + this.token, + tx, + this.sender, + this.sender, + this.recipient, + amount, + data, + null, + postSenderBalance, + postRecipientBalance, + ); + }); + + it('TokensRecipient receives operatorSend data and is called after state mutation', async function () { + const { tx } = await this.token.operatorSend( + this.sender, this.recipient, amount, data, operatorData, + { from: operator }, + ); + + const postSenderBalance = await this.token.balanceOf(this.sender); + const postRecipientBalance = await this.token.balanceOf(this.recipient); + + await assertTokensReceivedCalled( + this.token, + tx, + operator, + this.sender, + this.recipient, + amount, + data, + operatorData, + postSenderBalance, + postRecipientBalance, + ); + }); + }); +} + +function shouldBehaveLikeERC777SendBurnWithSendHook (operator, amount, data, operatorData) { context('when TokensSender reverts', function () { beforeEach(async function () { await this.tokensSenderImplementer.setShouldRevertSend(true); }); it('send reverts', async function () { - await shouldFail.reverting(sendFromHolder(this.token, this.sender, recipient, amount, data)); + await shouldFail.reverting(sendFromHolder(this.token, this.sender, this.recipient, amount, data)); }); it('operatorSend reverts', async function () { await shouldFail.reverting( - this.token.operatorSend(this.sender, recipient, amount, data, operatorData, { from: operator }) + this.token.operatorSend(this.sender, this.recipient, amount, data, operatorData, { from: operator }) ); }); @@ -292,22 +359,22 @@ function shouldBehaveLikeERC777SendBurnWithHook (recipient, operator, amount, da }); it('TokensSender receives send data and is called before state mutation', async function () { - const preHolderBalance = await this.token.balanceOf(this.sender); - const preRecipientBalance = await this.token.balanceOf(recipient); + const preSenderBalance = await this.token.balanceOf(this.sender); + const preRecipientBalance = await this.token.balanceOf(this.recipient); - const { tx } = await sendFromHolder(this.token, this.sender, recipient, amount, data); + const { tx } = await sendFromHolder(this.token, this.sender, this.recipient, amount, data); await assertTokensToSendCalled( - this.token, tx, this.sender, this.sender, recipient, amount, data, null, preHolderBalance, preRecipientBalance + this.token, tx, this.sender, this.sender, this.recipient, amount, data, null, preSenderBalance, preRecipientBalance ); }); it('TokensSender receives operatorSend data and is called before state mutation', async function () { - const preHolderBalance = await this.token.balanceOf(this.sender); - const preRecipientBalance = await this.token.balanceOf(recipient); + const preSenderBalance = await this.token.balanceOf(this.sender); + const preRecipientBalance = await this.token.balanceOf(this.recipient); const { tx } = await this.token.operatorSend( - this.sender, recipient, amount, data, operatorData, + this.sender, this.recipient, amount, data, operatorData, { from: operator }, ); @@ -316,32 +383,32 @@ function shouldBehaveLikeERC777SendBurnWithHook (recipient, operator, amount, da tx, operator, this.sender, - recipient, + this.recipient, amount, data, operatorData, - preHolderBalance, + preSenderBalance, preRecipientBalance, ); }); it('TokensSender receives burn data and is called before state mutation', async function () { - const preHolderBalance = await this.token.balanceOf(this.sender); + const preSenderBalance = await this.token.balanceOf(this.sender); const { tx } = await burnFromHolder(this.token, this.sender, amount, data, { from: this.sender }); await assertTokensToSendCalled( - this.token, tx, this.sender, this.sender, ZERO_ADDRESS, amount, data, null, preHolderBalance + this.token, tx, this.sender, this.sender, ZERO_ADDRESS, amount, data, null, preSenderBalance ); }); it('TokensSender receives operatorBurn data and is called before state mutation', async function () { - const preHolderBalance = await this.token.balanceOf(this.sender); + const preSenderBalance = await this.token.balanceOf(this.sender); const { tx } = await this.token.operatorBurn(this.sender, amount, data, operatorData, { from: operator }); await assertTokensToSendCalled( - this.token, tx, operator, this.sender, ZERO_ADDRESS, amount, data, operatorData, preHolderBalance + this.token, tx, operator, this.sender, ZERO_ADDRESS, amount, data, operatorData, preSenderBalance ); }); }); @@ -354,6 +421,13 @@ function removeBalance (holder) { }); } +async function assertTokensReceivedCalled (token, txHash, operator, from, to, amount, data, operatorData, fromBalance, + toBalance = '0') { + await expectEvent.inTransaction(txHash, ERC777SenderRecipientMock, 'TokensReceivedCalled', { + operator, from, to, amount, data, operatorData, token: token.address, fromBalance, toBalance, + }); +} + async function assertTokensToSendCalled (token, txHash, operator, from, to, amount, data, operatorData, fromBalance, toBalance = '0') { await expectEvent.inTransaction(txHash, ERC777SenderRecipientMock, 'TokensToSendCalled', { @@ -384,5 +458,6 @@ module.exports = { shouldBehaveLikeERC777OperatorSendBurn, shouldBehaveLikeERC777UnauthorizedOperatorSendBurn, shouldDirectSendTokens, - shouldBehaveLikeERC777SendBurnWithHook, + shouldBehaveLikeERC777SendBurnWithReceiveHook, + shouldBehaveLikeERC777SendBurnWithSendHook, }; diff --git a/test/drafts/ERC777/ERC777.test.js b/test/drafts/ERC777/ERC777.test.js index 77d6e90b365..78acd09f245 100644 --- a/test/drafts/ERC777/ERC777.test.js +++ b/test/drafts/ERC777/ERC777.test.js @@ -6,7 +6,8 @@ const { shouldBehaveLikeERC777OperatorSendBurn, shouldBehaveLikeERC777UnauthorizedOperatorSendBurn, shouldDirectSendTokens, - shouldBehaveLikeERC777SendBurnWithHook, + shouldBehaveLikeERC777SendBurnWithReceiveHook, + shouldBehaveLikeERC777SendBurnWithSendHook, } = require('./ERC777.behavior'); const ERC777 = artifacts.require('ERC777Mock'); @@ -229,17 +230,91 @@ contract('ERC777', function ([ }); }); - describe('tokensToSend hook', function () { - context('with ERC777TokensSender implementer', function () { - const amount = new BN('1'); - const recipient = anyone; - const operator = defaultOperatorA; - // sender is stored inside 'this', since for some tests its address is determined dynamically + describe('send and receive hooks', function () { + const amount = new BN('1'); + const operator = defaultOperatorA; + // sender and recipient are stored inside 'this', since for some tests their addresses are determined dynamically + + describe('tokensReceived', function () { + beforeEach(async function () { + this.sender = holder; + }); + + context('with no ERC777TokensRecipient implementer', function () { + context('with contract recipient', function () { + beforeEach(async function () { + this.tokensRecipientImplementer = await ERC777SenderRecipientMock.new(); + this.recipient = this.tokensRecipientImplementer.address; + + // Note that tokensRecipientImplementer doesn't implement the recipient interface for the recipient + }); + + it('send reverts', async function () { + await shouldFail.reverting(this.token.send(this.recipient, amount, data)); + }); + + it('operatorSend reverts', async function () { + await shouldFail.reverting( + this.token.operatorSend(this.sender, this.recipient, amount, data, operatorData, { from: operator }) + ); + }); + }); + }); + + context('with ERC777TokensRecipient implementer', function () { + context('with contract as implementer for an externally owned account', function () { + beforeEach(async function () { + this.tokensRecipientImplementer = await ERC777SenderRecipientMock.new(); + this.recipient = anyone; + + await this.tokensRecipientImplementer.recipientFor(this.recipient); + + await this.erc1820.setInterfaceImplementer( + this.recipient, + web3.utils.soliditySha3('ERC777TokensRecipient'), this.tokensRecipientImplementer.address, + { from: this.recipient }, + ); + }); + + shouldBehaveLikeERC777SendBurnWithReceiveHook(operator, amount, data, operatorData); + }); + + context('with contract as implementer for another contract', function () { + beforeEach(async function () { + this.recipientContract = await ERC777SenderRecipientMock.new(); + this.recipient = this.recipientContract.address; + + this.tokensRecipientImplementer = await ERC777SenderRecipientMock.new(); + await this.tokensRecipientImplementer.recipientFor(this.recipient); + await this.recipientContract.registerRecipient(this.tokensRecipientImplementer.address); + }); + + shouldBehaveLikeERC777SendBurnWithReceiveHook(operator, amount, data, operatorData); + }); + + context('with contract as implementer for itself', function () { + beforeEach(async function () { + this.tokensRecipientImplementer = await ERC777SenderRecipientMock.new(); + this.recipient = this.tokensRecipientImplementer.address; + + await this.tokensRecipientImplementer.recipientFor(this.recipient); + }); + + shouldBehaveLikeERC777SendBurnWithReceiveHook(operator, amount, data, operatorData); + }); + }); + }); + + describe('tokensToSend', function () { + beforeEach(async function () { + this.recipient = anyone; + }); context('with a contract as implementer for an externally owned account', function () { beforeEach(async function () { - this.sender = holder; this.tokensSenderImplementer = await ERC777SenderRecipientMock.new(); + this.sender = holder; + await this.tokensSenderImplementer.senderFor(this.sender); await this.erc1820.setInterfaceImplementer( @@ -249,19 +324,43 @@ contract('ERC777', function ([ ); }); - shouldBehaveLikeERC777SendBurnWithHook(recipient, operator, amount, data, operatorData); + shouldBehaveLikeERC777SendBurnWithSendHook(operator, amount, data, operatorData); }); - context('with a contract as implementer for itself', function () { + context('with contract as implementer for another contract', function () { beforeEach(async function () { + this.senderContract = await ERC777SenderRecipientMock.new(); + this.sender = this.senderContract.address; + this.tokensSenderImplementer = await ERC777SenderRecipientMock.new(); - await this.tokensSenderImplementer.senderFor(ZERO_ADDRESS); + await this.tokensSenderImplementer.senderFor(this.sender); + await this.senderContract.registerSender(this.tokensSenderImplementer.address); + + // For the contract to be able to receive tokens (that it can later send), it must also implement the + // recipient interface. + + await this.senderContract.recipientFor(this.sender); + await this.token.send(this.sender, amount, data, { from: holder }); + }); + + shouldBehaveLikeERC777SendBurnWithSendHook(operator, amount, data, operatorData); + }); + context('with a contract as implementer for itself', function () { + beforeEach(async function () { + this.tokensSenderImplementer = await ERC777SenderRecipientMock.new(); this.sender = this.tokensSenderImplementer.address; + + await this.tokensSenderImplementer.senderFor(this.sender); + + // For the contract to be able to receive tokens (that it can later send), it must also implement the + // recipient interface. + + await this.tokensSenderImplementer.recipientFor(this.sender); await this.token.send(this.sender, amount, data, { from: holder }); }); - shouldBehaveLikeERC777SendBurnWithHook(recipient, operator, amount, data, operatorData); + shouldBehaveLikeERC777SendBurnWithSendHook(operator, amount, data, operatorData); }); }); }); From ad40a9278a27f5dcfafe7620ca6654238f638314 Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Sat, 6 Apr 2019 03:50:11 -0300 Subject: [PATCH 58/64] switch to updated ganache-cli-coverage fork --- package-lock.json | 6027 +++++++++------------------------------------ package.json | 2 +- 2 files changed, 1220 insertions(+), 4809 deletions(-) diff --git a/package-lock.json b/package-lock.json index 42830c06857..bbc326ff60f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -61,32 +61,6 @@ } } }, - "@babel/runtime": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.3.4.tgz", - "integrity": "sha512-IvfvnMdSaLBateu0jfsYIpZTxAc2cKEXEMiezGGN75QcBcecDUKd3PgLAncT0oOgxKy8dd8hrJKj9MfzgfZd6g==", - "dev": true, - "requires": { - "regenerator-runtime": "^0.12.0" - }, - "dependencies": { - "regenerator-runtime": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", - "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==", - "dev": true - } - } - }, - "@types/bn.js": { - "version": "4.11.4", - "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.4.tgz", - "integrity": "sha512-AO8WW+aRcKWKQAYTfKLzwnpL6U+TfPqS+haRrhCy5ff04Da8WZud3ZgVjspQXaEXJDcTlsjUEVvL39wegDek5w==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, "@types/node": { "version": "10.14.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.1.tgz", @@ -99,15 +73,6 @@ "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", "dev": true }, - "abstract-leveldown": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-3.0.0.tgz", - "integrity": "sha512-KUWx9UWGQD12zsmLNj64/pndaz4iJh/Pj7nopgkfDG6RlCcbMZvT6+9l7dchK4idog2Is8VdC/PvNbFuFmalIQ==", - "dev": true, - "requires": { - "xtend": "~4.0.0" - } - }, "accepts": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", @@ -294,15 +259,6 @@ "lodash": "^4.17.11" } }, - "async-eventemitter": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/async-eventemitter/-/async-eventemitter-0.2.4.tgz", - "integrity": "sha512-pd20BwL7Yt1zwDFy+8MX8F1+WCT8aQeKj0kQnTrH9WaeRETlRamVhD0JtRPmrV4GfOJ2F9CvdQkZeZhnh2TuHw==", - "dev": true, - "requires": { - "async": "^2.4.0" - } - }, "async-limiter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", @@ -338,2022 +294,1041 @@ "js-tokens": "^3.0.0" } }, - "babel-core": { - "version": "6.26.3", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", - "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base64-js": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", + "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", "dev": true, + "optional": true, "requires": { - "babel-code-frame": "^6.26.0", - "babel-generator": "^6.26.0", - "babel-helpers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-register": "^6.26.0", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "convert-source-map": "^1.5.1", - "debug": "^2.6.9", - "json5": "^0.5.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.4", - "path-is-absolute": "^1.0.1", - "private": "^0.1.8", - "slash": "^1.0.0", - "source-map": "^0.5.7" - }, - "dependencies": { - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" - } - } + "tweetnacl": "^0.14.3" + } + }, + "bignumber.js": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz", + "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ==", + "dev": true + }, + "bindings": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.3.1.tgz", + "integrity": "sha512-i47mqjF9UbjxJhxGf+pZ6kSxrnI3wBLlnGI2ArWJ4r0VrvDS7ZYXkprq/pLaBWYq4GM0r4zdHY+NNRqEMU7uew==", + "dev": true + }, + "bip66": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/bip66/-/bip66-1.1.5.tgz", + "integrity": "sha1-AfqHSHhcpwlV1QESF9GzE5lpyiI=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" } }, - "babel-generator": { - "version": "6.26.1", - "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", - "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", + "bl": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", + "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", "dev": true, "requires": { - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "detect-indent": "^4.0.0", - "jsesc": "^1.3.0", - "lodash": "^4.17.4", - "source-map": "^0.5.7", - "trim-right": "^1.0.1" + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" }, "dependencies": { - "jsesc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", - "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "dev": true + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } } } }, - "babel-helper-builder-binary-assignment-operator-visitor": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz", - "integrity": "sha1-zORReto1b0IgvK6KAsKzRvmlZmQ=", + "block-stream": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", "dev": true, "requires": { - "babel-helper-explode-assignable-expression": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" + "inherits": "~2.0.0" } }, - "babel-helper-call-delegate": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", - "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", - "dev": true, - "requires": { - "babel-helper-hoist-variables": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } + "bluebird": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz", + "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==", + "dev": true }, - "babel-helper-define-map": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz", - "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", - "dev": true, - "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" - } + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "dev": true }, - "babel-helper-explode-assignable-expression": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz", - "integrity": "sha1-8luCz33BBDPFX3BZLVdGQArCLKo=", + "body-parser": { + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", + "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", "dev": true, "requires": { - "babel-runtime": "^6.22.0", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" + "bytes": "3.0.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "~1.6.3", + "iconv-lite": "0.4.23", + "on-finished": "~2.3.0", + "qs": "6.5.2", + "raw-body": "2.3.3", + "type-is": "~1.6.16" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + } } }, - "babel-helper-function-name": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", - "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", + "brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", "dev": true, "requires": { - "babel-helper-get-function-arity": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "babel-helper-get-function-arity": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", - "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "browser-stdout": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", + "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", + "dev": true }, - "babel-helper-hoist-variables": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", - "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", + "browserify-aes": { + "version": "1.2.0", + "resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "dev": true, "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, - "babel-helper-optimise-call-expression": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", - "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", "dev": true, "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" } }, - "babel-helper-regex": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz", - "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", "dev": true, "requires": { - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } } }, - "babel-helper-remap-async-to-generator": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz", - "integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=", + "browserify-rsa": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", "dev": true, "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" + "bn.js": "^4.1.0", + "randombytes": "^2.0.1" } }, - "babel-helper-replace-supers": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", - "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", + "browserify-sha3": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/browserify-sha3/-/browserify-sha3-0.0.4.tgz", + "integrity": "sha1-CGxHuMgjFsnUcCLCYYWVRXbdjiY=", "dev": true, "requires": { - "babel-helper-optimise-call-expression": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" + "js-sha3": "^0.6.1", + "safe-buffer": "^5.1.1" } }, - "babel-helpers": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", - "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", + "browserify-sign": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", + "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", "dev": true, "requires": { - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" + "bn.js": "^4.1.1", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.2", + "elliptic": "^6.0.0", + "inherits": "^2.0.1", + "parse-asn1": "^5.0.0" } }, - "babel-messages": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", - "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", + "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" } }, - "babel-plugin-check-es2015-constants": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", - "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", + "buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" } }, - "babel-plugin-syntax-async-functions": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", - "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=", + "buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", "dev": true }, - "babel-plugin-syntax-exponentiation-operator": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", - "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=", + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", "dev": true }, - "babel-plugin-syntax-trailing-function-commas": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz", - "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=", + "buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=", "dev": true }, - "babel-plugin-transform-async-to-generator": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz", - "integrity": "sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=", - "dev": true, - "requires": { - "babel-helper-remap-async-to-generator": "^6.24.1", - "babel-plugin-syntax-async-functions": "^6.8.0", - "babel-runtime": "^6.22.0" - } + "buffer-from": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz", + "integrity": "sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ==", + "dev": true }, - "babel-plugin-transform-es2015-arrow-functions": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", - "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } + "buffer-to-arraybuffer": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz", + "integrity": "sha1-YGSkD6dutDxyOrqe+PbhIW0QURo=", + "dev": true }, - "babel-plugin-transform-es2015-block-scoped-functions": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", - "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true }, - "babel-plugin-transform-es2015-block-scoping": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", - "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" - } + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true }, - "babel-plugin-transform-es2015-classes": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", - "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", - "dev": true, - "requires": { - "babel-helper-define-map": "^6.24.1", - "babel-helper-function-name": "^6.24.1", - "babel-helper-optimise-call-expression": "^6.24.1", - "babel-helper-replace-supers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "dev": true }, - "babel-plugin-transform-es2015-computed-properties": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", - "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", + "caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", "dev": true, "requires": { - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" + "callsites": "^0.2.0" } }, - "babel-plugin-transform-es2015-destructuring": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", - "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } + "callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "dev": true }, - "babel-plugin-transform-es2015-duplicate-keys": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", - "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true }, - "babel-plugin-transform-es2015-for-of": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", - "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", + "chai": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.1.2.tgz", + "integrity": "sha1-D2RYS6ZC8PKs4oBiefTwbKI61zw=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "assertion-error": "^1.0.1", + "check-error": "^1.0.1", + "deep-eql": "^3.0.0", + "get-func-name": "^2.0.0", + "pathval": "^1.0.0", + "type-detect": "^4.0.0" } }, - "babel-plugin-transform-es2015-function-name": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", - "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", - "dev": true, - "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } + "chai-bn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/chai-bn/-/chai-bn-0.1.1.tgz", + "integrity": "sha512-e1npVXt3cQfZ6oQET9oP38vNj/4HeJ4ojeUpuC8YzhVbTJpIDqANVt7TKi7Dq9yKlHySk2FqbmiMih35iT4DYg==", + "dev": true }, - "babel-plugin-transform-es2015-literals": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", - "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" } }, - "babel-plugin-transform-es2015-modules-amd": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz", - "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", - "dev": true, - "requires": { - "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } + "chardet": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", + "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", + "dev": true }, - "babel-plugin-transform-es2015-modules-commonjs": { - "version": "6.26.2", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz", - "integrity": "sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==", - "dev": true, - "requires": { - "babel-plugin-transform-strict-mode": "^6.24.1", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-types": "^6.26.0" - } + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true }, - "babel-plugin-transform-es2015-modules-systemjs": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz", - "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", "dev": true, "requires": { - "babel-helper-hoist-variables": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, - "babel-plugin-transform-es2015-modules-umd": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz", - "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", - "dev": true, - "requires": { - "babel-plugin-transform-es2015-modules-amd": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } + "circular-json": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", + "dev": true }, - "babel-plugin-transform-es2015-object-super": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", - "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", "dev": true, "requires": { - "babel-helper-replace-supers": "^6.24.1", - "babel-runtime": "^6.22.0" + "restore-cursor": "^2.0.0" } }, - "babel-plugin-transform-es2015-parameters": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", - "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", - "dev": true, - "requires": { - "babel-helper-call-delegate": "^6.24.1", - "babel-helper-get-function-arity": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true }, - "babel-plugin-transform-es2015-shorthand-properties": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", - "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true }, - "babel-plugin-transform-es2015-spread": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", - "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true }, - "babel-plugin-transform-es2015-sticky-regex": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", - "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", + "color-convert": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", + "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", "dev": true, "requires": { - "babel-helper-regex": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" + "color-name": "^1.1.1" } }, - "babel-plugin-transform-es2015-template-literals": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", - "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true }, - "babel-plugin-transform-es2015-typeof-symbol": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", - "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", + "combined-stream": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", + "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "delayed-stream": "~1.0.0" } }, - "babel-plugin-transform-es2015-unicode-regex": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", - "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", - "dev": true, - "requires": { - "babel-helper-regex": "^6.24.1", - "babel-runtime": "^6.22.0", - "regexpu-core": "^2.0.0" - } + "commander": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", + "dev": true }, - "babel-plugin-transform-exponentiation-operator": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz", - "integrity": "sha1-KrDJx/MJj6SJB3cruBP+QejeOg4=", - "dev": true, - "requires": { - "babel-helper-builder-binary-assignment-operator-visitor": "^6.24.1", - "babel-plugin-syntax-exponentiation-operator": "^6.8.0", - "babel-runtime": "^6.22.0" - } + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true }, - "babel-plugin-transform-regenerator": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", - "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=", + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", "dev": true, "requires": { - "regenerator-transform": "^0.10.0" + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" } }, - "babel-plugin-transform-strict-mode": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", - "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true }, - "babel-preset-env": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.7.0.tgz", - "integrity": "sha512-9OR2afuKDneX2/q2EurSftUYM0xGu4O2D9adAhVfADDhrYDaxXV0rBbevVYoY9n6nyX1PmQW/0jtpJvUNr9CHg==", - "dev": true, - "requires": { - "babel-plugin-check-es2015-constants": "^6.22.0", - "babel-plugin-syntax-trailing-function-commas": "^6.22.0", - "babel-plugin-transform-async-to-generator": "^6.22.0", - "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", - "babel-plugin-transform-es2015-block-scoped-functions": "^6.22.0", - "babel-plugin-transform-es2015-block-scoping": "^6.23.0", - "babel-plugin-transform-es2015-classes": "^6.23.0", - "babel-plugin-transform-es2015-computed-properties": "^6.22.0", - "babel-plugin-transform-es2015-destructuring": "^6.23.0", - "babel-plugin-transform-es2015-duplicate-keys": "^6.22.0", - "babel-plugin-transform-es2015-for-of": "^6.23.0", - "babel-plugin-transform-es2015-function-name": "^6.22.0", - "babel-plugin-transform-es2015-literals": "^6.22.0", - "babel-plugin-transform-es2015-modules-amd": "^6.22.0", - "babel-plugin-transform-es2015-modules-commonjs": "^6.23.0", - "babel-plugin-transform-es2015-modules-systemjs": "^6.23.0", - "babel-plugin-transform-es2015-modules-umd": "^6.23.0", - "babel-plugin-transform-es2015-object-super": "^6.22.0", - "babel-plugin-transform-es2015-parameters": "^6.23.0", - "babel-plugin-transform-es2015-shorthand-properties": "^6.22.0", - "babel-plugin-transform-es2015-spread": "^6.22.0", - "babel-plugin-transform-es2015-sticky-regex": "^6.22.0", - "babel-plugin-transform-es2015-template-literals": "^6.22.0", - "babel-plugin-transform-es2015-typeof-symbol": "^6.23.0", - "babel-plugin-transform-es2015-unicode-regex": "^6.22.0", - "babel-plugin-transform-exponentiation-operator": "^6.22.0", - "babel-plugin-transform-regenerator": "^6.22.0", - "browserslist": "^3.2.6", - "invariant": "^2.2.2", - "semver": "^5.3.0" - } - }, - "babel-register": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", - "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", - "dev": true, - "requires": { - "babel-core": "^6.26.0", - "babel-runtime": "^6.26.0", - "core-js": "^2.5.0", - "home-or-tmp": "^2.0.0", - "lodash": "^4.17.4", - "mkdirp": "^0.5.1", - "source-map-support": "^0.4.15" - }, - "dependencies": { - "source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", - "dev": true, - "requires": { - "source-map": "^0.5.6" - } - } - } + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=", + "dev": true + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "dev": true + }, + "cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==", + "dev": true }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", "dev": true, "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" + "object-assign": "^4", + "vary": "^1" } }, - "babel-template": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", - "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "coveralls": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.0.1.tgz", + "integrity": "sha512-FAzXwiDOYLGDWH+zgoIA+8GbWv50hlx+kpEJyvzLKOdnIBv9uWoVl4DhqGgyUHpiRjAlF8KYZSipWXYtllWH6Q==", "dev": true, "requires": { - "babel-runtime": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "lodash": "^4.17.4" + "js-yaml": "^3.6.1", + "lcov-parse": "^0.0.10", + "log-driver": "^1.2.5", + "minimist": "^1.2.0", + "request": "^2.79.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } } }, - "babel-traverse": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", - "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "create-ecdh": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", + "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", "dev": true, "requires": { - "babel-code-frame": "^6.26.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" - }, - "dependencies": { - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" - } - } + "bn.js": "^4.1.0", + "elliptic": "^6.0.0" } }, - "babel-types": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "create-hash": { + "version": "1.2.0", + "resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "dev": true, "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" } }, - "babelify": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", - "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", + "create-hmac": { + "version": "1.1.7", + "resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "dev": true, "requires": { - "babel-core": "^6.0.14", - "object-assign": "^4.0.0" + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" } }, - "babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", - "dev": true + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "lru-cache": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", + "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + } + } }, - "backoff": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/backoff/-/backoff-2.5.0.tgz", - "integrity": "sha1-9hbtqdPktmuMp/ynn2lXIsX44m8=", + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", "dev": true, "requires": { - "precond": "0.2" + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" } }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "crypto-js": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.1.8.tgz", + "integrity": "sha1-cV8HC/YBTyrpkqmLOSkli3E/CNU=", "dev": true }, - "base-x": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.5.tgz", - "integrity": "sha512-C3picSgzPSLE+jW3tcBzJoGwitOtazb5B+5YmAxZm2ybmTi9LNgAtDO/jjVEBZwHoXmDBZ9m/IELj3elJVRBcA==", + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "dev": true, - "optional": true, "requires": { - "safe-buffer": "^5.0.1" + "assert-plus": "^1.0.0" } }, - "base64-js": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", - "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==", + "death": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/death/-/death-1.1.0.tgz", + "integrity": "sha1-AaqcQB7dknUFFEcLgmY5DGbGcxg=", "dev": true }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", - "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "optional": true, "requires": { - "tweetnacl": "^0.14.3" + "ms": "2.0.0" } }, - "bignumber.js": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz", - "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ==", + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, - "bindings": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.3.1.tgz", - "integrity": "sha512-i47mqjF9UbjxJhxGf+pZ6kSxrnI3wBLlnGI2ArWJ4r0VrvDS7ZYXkprq/pLaBWYq4GM0r4zdHY+NNRqEMU7uew==", + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", "dev": true }, - "bip39": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/bip39/-/bip39-2.5.0.tgz", - "integrity": "sha512-xwIx/8JKoT2+IPJpFEfXoWdYwP7UVAoUxxLNfGCfVowaJE7yg1Y5B1BVPqlUNsBq5/nGwmFkwRJ8xDW4sX8OdA==", + "decompress": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.0.tgz", + "integrity": "sha1-eu3YVCflqS2s/lVnSnxQXpbQH50=", "dev": true, "requires": { - "create-hash": "^1.1.0", - "pbkdf2": "^3.0.9", - "randombytes": "^2.0.1", - "safe-buffer": "^5.0.1", - "unorm": "^1.3.3" + "decompress-tar": "^4.0.0", + "decompress-tarbz2": "^4.0.0", + "decompress-targz": "^4.0.0", + "decompress-unzip": "^4.0.1", + "graceful-fs": "^4.1.10", + "make-dir": "^1.0.0", + "pify": "^2.3.0", + "strip-dirs": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } } }, - "bip66": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/bip66/-/bip66-1.1.5.tgz", - "integrity": "sha1-AfqHSHhcpwlV1QESF9GzE5lpyiI=", + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", "dev": true, "requires": { - "safe-buffer": "^5.0.1" + "mimic-response": "^1.0.0" } }, - "bl": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", - "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", + "decompress-tar": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", + "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", "dev": true, "requires": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.1" + "file-type": "^5.2.0", + "is-stream": "^1.1.0", + "tar-stream": "^1.5.2" + } + }, + "decompress-tarbz2": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", + "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", + "dev": true, + "requires": { + "decompress-tar": "^4.1.0", + "file-type": "^6.1.0", + "is-stream": "^1.1.0", + "seek-bzip": "^1.0.5", + "unbzip2-stream": "^1.0.9" }, "dependencies": { - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "file-type": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", + "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==", "dev": true - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } } } }, - "block-stream": { - "version": "0.0.9", - "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", - "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "decompress-targz": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", + "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", "dev": true, "requires": { - "inherits": "~2.0.0" + "decompress-tar": "^4.1.1", + "file-type": "^5.2.0", + "is-stream": "^1.1.0" } }, - "bluebird": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz", - "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==", - "dev": true - }, - "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", - "dev": true - }, - "body-parser": { - "version": "1.18.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", - "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", + "decompress-unzip": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", + "integrity": "sha1-3qrM39FK6vhVePczroIQ+bSEj2k=", "dev": true, "requires": { - "bytes": "3.0.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "~1.6.3", - "iconv-lite": "0.4.23", - "on-finished": "~2.3.0", - "qs": "6.5.2", - "raw-body": "2.3.3", - "type-is": "~1.6.16" + "file-type": "^3.8.0", + "get-stream": "^2.2.0", + "pify": "^2.3.0", + "yauzl": "^2.4.2" }, "dependencies": { - "iconv-lite": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", - "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "file-type": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", + "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=", + "dev": true + }, + "get-stream": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", + "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=", "dev": true, "requires": { - "safer-buffer": ">= 2.1.2 < 3" + "object-assign": "^4.0.1", + "pinkie-promise": "^2.0.0" } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true } } }, - "brace-expansion": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", - "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", "dev": true, "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "type-detect": "^4.0.0" } }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", - "dev": true - }, - "browser-stdout": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", - "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, - "browserify-aes": { - "version": "1.2.0", - "resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "dev": true, - "requires": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "browserify-cipher": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", "dev": true, "requires": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" + "object-keys": "^1.0.12" } }, - "browserify-des": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", - "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", "dev": true, "requires": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" + "globby": "^5.0.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "rimraf": "^2.2.8" }, "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "pify": { + "version": "2.3.0", + "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } } }, - "browserify-rsa": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", - "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "randombytes": "^2.0.1" - } + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true }, - "browserify-sha3": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/browserify-sha3/-/browserify-sha3-0.0.4.tgz", - "integrity": "sha1-CGxHuMgjFsnUcCLCYYWVRXbdjiY=", - "dev": true, - "requires": { - "js-sha3": "^0.6.1", - "safe-buffer": "^5.1.1" - } + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true }, - "browserify-sign": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", - "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", + "des.js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", + "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", "dev": true, "requires": { - "bn.js": "^4.1.1", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.2", - "elliptic": "^6.0.0", "inherits": "^2.0.1", - "parse-asn1": "^5.0.0" + "minimalistic-assert": "^1.0.0" } }, - "browserslist": { - "version": "3.2.8", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-3.2.8.tgz", - "integrity": "sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ==", + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "dev": true + }, + "diff": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz", + "integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww==", + "dev": true + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30000844", - "electron-to-chromium": "^1.3.47" + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" } }, - "bs58": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", - "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, - "optional": true, "requires": { - "base-x": "^3.0.2" + "esutils": "^2.0.2" } }, - "bs58check": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", - "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "dom-walk": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz", + "integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg=", + "dev": true + }, + "drbg.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/drbg.js/-/drbg.js-1.0.1.tgz", + "integrity": "sha1-Pja2xCs3BDgjzbwzLVjzHiRFSAs=", "dev": true, - "optional": true, "requires": { - "bs58": "^4.0.0", - "create-hash": "^1.1.0", - "safe-buffer": "^5.1.2" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "optional": true - } + "browserify-aes": "^1.0.6", + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4" } }, - "buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", - "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", "dev": true, + "optional": true, "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4" + "jsbn": "~0.1.0" } }, - "buffer-alloc": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", - "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, + "elliptic": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", + "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", "dev": true, "requires": { - "buffer-alloc-unsafe": "^1.1.0", - "buffer-fill": "^1.0.0" + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" } }, - "buffer-alloc-unsafe": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", - "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", - "dev": true - }, - "buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", - "dev": true - }, - "buffer-fill": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", - "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=", - "dev": true - }, - "buffer-from": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz", - "integrity": "sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ==", - "dev": true - }, - "buffer-to-arraybuffer": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz", - "integrity": "sha1-YGSkD6dutDxyOrqe+PbhIW0QURo=", - "dev": true - }, - "buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", - "dev": true - }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true, + "optional": true }, - "bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", "dev": true }, - "bytewise": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/bytewise/-/bytewise-1.1.0.tgz", - "integrity": "sha1-HRPL/3F65xWAlKqIGzXQgbOHJT4=", + "end-of-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", "dev": true, "requires": { - "bytewise-core": "^1.2.2", - "typewise": "^1.0.3" + "once": "^1.4.0" } }, - "bytewise-core": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/bytewise-core/-/bytewise-core-1.2.3.tgz", - "integrity": "sha1-P7QQx+kVWOsasiqCg0V3qmvWHUI=", + "error-ex": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", + "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", "dev": true, "requires": { - "typewise-core": "^1.2" + "is-arrayish": "^0.2.1" } }, - "cachedown": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/cachedown/-/cachedown-1.0.0.tgz", - "integrity": "sha1-1D8DbkUQaWsxJG19sx6/D3rDLRU=", + "es-abstract": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", + "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", "dev": true, "requires": { - "abstract-leveldown": "^2.4.1", - "lru-cache": "^3.2.0" + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-keys": "^1.0.12" }, "dependencies": { - "abstract-leveldown": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-2.7.2.tgz", - "integrity": "sha512-+OVvxH2rHVEhWLdbudP6p0+dNMXu8JA1CbhP19T8paTYAcX7oJ4OVjT+ZUVpv7mITxXHqDMej+GdqXBmXkw09w==", + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dev": true, "requires": { - "xtend": "~4.0.0" + "function-bind": "^1.1.1" } } } }, - "caller-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", - "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", - "dev": true, - "requires": { - "callsites": "^0.2.0" - } - }, - "callsites": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", - "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", - "dev": true - }, - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "dev": true - }, - "caniuse-lite": { - "version": "1.0.30000948", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000948.tgz", - "integrity": "sha512-Lw4y7oz1X5MOMZm+2IFaSISqVVQvUuD+ZUSfeYK/SlYiMjkHN/eJ2PDfJehW5NA6JjrxYSSnIWfwjeObQMEjFQ==", - "dev": true - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true - }, - "chai": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.1.2.tgz", - "integrity": "sha1-D2RYS6ZC8PKs4oBiefTwbKI61zw=", - "dev": true, - "requires": { - "assertion-error": "^1.0.1", - "check-error": "^1.0.1", - "deep-eql": "^3.0.0", - "get-func-name": "^2.0.0", - "pathval": "^1.0.0", - "type-detect": "^4.0.0" - } - }, - "chai-bn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/chai-bn/-/chai-bn-0.1.1.tgz", - "integrity": "sha512-e1npVXt3cQfZ6oQET9oP38vNj/4HeJ4ojeUpuC8YzhVbTJpIDqANVt7TKi7Dq9yKlHySk2FqbmiMih35iT4DYg==", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "chardet": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", - "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", - "dev": true - }, - "check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", - "dev": true - }, - "checkpoint-store": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/checkpoint-store/-/checkpoint-store-1.1.0.tgz", - "integrity": "sha1-BOTLUWuRQziTWB5tRgGnjpVS6gY=", - "dev": true, - "requires": { - "functional-red-black-tree": "^1.0.1" - } - }, - "chownr": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", - "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==", - "dev": true - }, - "cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", "dev": true, "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" } }, - "circular-json": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", - "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", "dev": true }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "cli-width": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", - "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, - "cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "escodegen": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", + "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", "dev": true, "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" + "esprima": "^2.7.1", + "estraverse": "^1.9.1", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.2.0" }, "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "estraverse": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", + "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", "dev": true }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "source-map": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", + "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", "dev": true, + "optional": true, "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "clone": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", - "dev": true - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true - }, - "coinstring": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/coinstring/-/coinstring-2.3.0.tgz", - "integrity": "sha1-zbYzY6lhUCQEolr7gsLibV/2J6Q=", - "dev": true, - "optional": true, - "requires": { - "bs58": "^2.0.1", - "create-hash": "^1.1.1" - }, - "dependencies": { - "bs58": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-2.0.1.tgz", - "integrity": "sha1-VZCNWPGYKrogCPob7Y+RmYopv40=", - "dev": true, - "optional": true - } - } - }, - "color-convert": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", - "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", - "dev": true, - "requires": { - "color-name": "^1.1.1" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "combined-stream": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", - "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", - "dev": true, - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commander": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", - "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", - "dev": true - }, - "content-disposition": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", - "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=", - "dev": true - }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", - "dev": true - }, - "convert-source-map": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", - "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "cookie": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", - "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", - "dev": true - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", - "dev": true - }, - "cookiejar": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", - "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==", - "dev": true - }, - "core-js": { - "version": "2.6.5", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.5.tgz", - "integrity": "sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A==", - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "dev": true, - "requires": { - "object-assign": "^4", - "vary": "^1" - } - }, - "coveralls": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.0.1.tgz", - "integrity": "sha512-FAzXwiDOYLGDWH+zgoIA+8GbWv50hlx+kpEJyvzLKOdnIBv9uWoVl4DhqGgyUHpiRjAlF8KYZSipWXYtllWH6Q==", - "dev": true, - "requires": { - "js-yaml": "^3.6.1", - "lcov-parse": "^0.0.10", - "log-driver": "^1.2.5", - "minimist": "^1.2.0", - "request": "^2.79.0" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } - } - }, - "create-ecdh": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", - "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "elliptic": "^6.0.0" - } - }, - "create-hash": { - "version": "1.2.0", - "resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "dev": true, - "requires": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "create-hmac": { - "version": "1.1.7", - "resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "dev": true, - "requires": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "cross-fetch": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-2.2.3.tgz", - "integrity": "sha512-PrWWNH3yL2NYIb/7WF/5vFG3DCQiXDOVf8k3ijatbrtnwNuhMWLC7YF7uqf53tbTFDzHIUD8oITw4Bxt8ST3Nw==", - "dev": true, - "requires": { - "node-fetch": "2.1.2", - "whatwg-fetch": "2.0.4" - } - }, - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "dependencies": { - "lru-cache": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", - "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - } - } - }, - "crypto-browserify": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", - "dev": true, - "requires": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" - } - }, - "crypto-js": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.1.8.tgz", - "integrity": "sha1-cV8HC/YBTyrpkqmLOSkli3E/CNU=", - "dev": true - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "death": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/death/-/death-1.1.0.tgz", - "integrity": "sha1-AaqcQB7dknUFFEcLgmY5DGbGcxg=", - "dev": true - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true - }, - "decompress": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.0.tgz", - "integrity": "sha1-eu3YVCflqS2s/lVnSnxQXpbQH50=", - "dev": true, - "requires": { - "decompress-tar": "^4.0.0", - "decompress-tarbz2": "^4.0.0", - "decompress-targz": "^4.0.0", - "decompress-unzip": "^4.0.1", - "graceful-fs": "^4.1.10", - "make-dir": "^1.0.0", - "pify": "^2.3.0", - "strip-dirs": "^2.0.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - } - } - }, - "decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", - "dev": true, - "requires": { - "mimic-response": "^1.0.0" - } - }, - "decompress-tar": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", - "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", - "dev": true, - "requires": { - "file-type": "^5.2.0", - "is-stream": "^1.1.0", - "tar-stream": "^1.5.2" - } - }, - "decompress-tarbz2": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", - "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", - "dev": true, - "requires": { - "decompress-tar": "^4.1.0", - "file-type": "^6.1.0", - "is-stream": "^1.1.0", - "seek-bzip": "^1.0.5", - "unbzip2-stream": "^1.0.9" - }, - "dependencies": { - "file-type": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", - "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==", - "dev": true - } - } - }, - "decompress-targz": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", - "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", - "dev": true, - "requires": { - "decompress-tar": "^4.1.1", - "file-type": "^5.2.0", - "is-stream": "^1.1.0" - } - }, - "decompress-unzip": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", - "integrity": "sha1-3qrM39FK6vhVePczroIQ+bSEj2k=", - "dev": true, - "requires": { - "file-type": "^3.8.0", - "get-stream": "^2.2.0", - "pify": "^2.3.0", - "yauzl": "^2.4.2" - }, - "dependencies": { - "file-type": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", - "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=", - "dev": true - }, - "get-stream": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", - "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=", - "dev": true, - "requires": { - "object-assign": "^4.0.1", - "pinkie-promise": "^2.0.0" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - } - } - }, - "deep-eql": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", - "dev": true, - "requires": { - "type-detect": "^4.0.0" - } - }, - "deep-equal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", - "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", - "dev": true - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "deferred-leveldown": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-1.2.2.tgz", - "integrity": "sha512-uukrWD2bguRtXilKt6cAWKyoXrTSMo5m7crUdLfWQmu8kIm88w3QZoUL+6nhpfKVmhHANER6Re3sKoNoZ3IKMA==", - "dev": true, - "requires": { - "abstract-leveldown": "~2.6.0" - }, - "dependencies": { - "abstract-leveldown": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-2.6.3.tgz", - "integrity": "sha512-2++wDf/DYqkPR3o5tbfdhF96EfMApo1GpPfzOsR/ZYXdkSmELlvOOEAl9iKkRsktMPHdGjO4rtkBpf2I7TiTeA==", - "dev": true, - "requires": { - "xtend": "~4.0.0" - } - } - } - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "requires": { - "object-keys": "^1.0.12" - } - }, - "defined": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", - "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", - "dev": true - }, - "del": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", - "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", - "dev": true, - "requires": { - "globby": "^5.0.0", - "is-path-cwd": "^1.0.0", - "is-path-in-cwd": "^1.0.0", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "rimraf": "^2.2.8" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - } - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true - }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "dev": true - }, - "des.js": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", - "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", - "dev": true - }, - "detect-indent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", - "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", - "dev": true, - "requires": { - "repeating": "^2.0.0" - } - }, - "diff": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz", - "integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww==", - "dev": true - }, - "diffie-hellman": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - } - }, - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "dom-walk": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz", - "integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg=", - "dev": true - }, - "drbg.js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/drbg.js/-/drbg.js-1.0.1.tgz", - "integrity": "sha1-Pja2xCs3BDgjzbwzLVjzHiRFSAs=", - "dev": true, - "requires": { - "browserify-aes": "^1.0.6", - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4" - } - }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", - "dev": true - }, - "ecc-jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", - "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", - "dev": true, - "optional": true, - "requires": { - "jsbn": "~0.1.0" - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", - "dev": true - }, - "electron-to-chromium": { - "version": "1.3.116", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.116.tgz", - "integrity": "sha512-NKwKAXzur5vFCZYBHpdWjTMO8QptNLNP80nItkSIgUOapPAo9Uia+RvkCaZJtO7fhQaVElSvBPWEc2ku6cKsPA==", - "dev": true - }, - "elliptic": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", - "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", - "dev": true, - "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" - } - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true, - "optional": true - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", - "dev": true - }, - "encoding": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", - "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", - "dev": true, - "requires": { - "iconv-lite": "~0.4.13" - } - }, - "encoding-down": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/encoding-down/-/encoding-down-5.0.4.tgz", - "integrity": "sha512-8CIZLDcSKxgzT+zX8ZVfgNbu8Md2wq/iqa1Y7zyVR18QBEAc0Nmzuvj/N5ykSKpfGzjM8qxbaFntLPwnVoUhZw==", - "dev": true, - "requires": { - "abstract-leveldown": "^5.0.0", - "inherits": "^2.0.3", - "level-codec": "^9.0.0", - "level-errors": "^2.0.0", - "xtend": "^4.0.1" - }, - "dependencies": { - "abstract-leveldown": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-5.0.0.tgz", - "integrity": "sha512-5mU5P1gXtsMIXg65/rsYGsi93+MlogXZ9FA8JnwKurHQg64bfXwGYVdVdijNTVNOlAsuIiOwHdvFFD5JqCJQ7A==", - "dev": true, - "requires": { - "xtend": "~4.0.0" - } - } - } - }, - "end-of-stream": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "errno": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", - "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", - "dev": true, - "requires": { - "prr": "~1.0.1" - } - }, - "error-ex": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", - "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", - "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.0", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "is-callable": "^1.1.4", - "is-regex": "^1.0.4", - "object-keys": "^1.0.12" - }, - "dependencies": { - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - } - } - }, - "es-to-primitive": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", - "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "escodegen": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", - "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", - "dev": true, - "requires": { - "esprima": "^2.7.1", - "estraverse": "^1.9.1", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.2.0" - }, - "dependencies": { - "estraverse": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", - "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", - "dev": true - }, - "source-map": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", - "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", - "dev": true, - "optional": true, - "requires": { - "amdefine": ">=0.0.4" + "amdefine": ">=0.0.4" } } } @@ -2773,44 +1748,6 @@ "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", "dev": true }, - "eth-block-tracker": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-3.0.1.tgz", - "integrity": "sha512-WUVxWLuhMmsfenfZvFO5sbl1qFY2IqUlw/FPVmjjdElpqLsZtSG+wPe9Dz7W/sB6e80HgFKknOmKk2eNlznHug==", - "dev": true, - "requires": { - "eth-query": "^2.1.0", - "ethereumjs-tx": "^1.3.3", - "ethereumjs-util": "^5.1.3", - "ethjs-util": "^0.1.3", - "json-rpc-engine": "^3.6.0", - "pify": "^2.3.0", - "tape": "^4.6.3" - }, - "dependencies": { - "ethereumjs-util": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", - "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", - "dev": true, - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "ethjs-util": "^0.1.3", - "keccak": "^1.0.2", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.0.1" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - } - } - }, "eth-ens-namehash": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz", @@ -2829,217 +1766,6 @@ } } }, - "eth-json-rpc-infura": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/eth-json-rpc-infura/-/eth-json-rpc-infura-3.2.0.tgz", - "integrity": "sha512-FLcpdxPRVBCUc7yoE+wHGvyYg2lATedP+/q7PsKvaSzQpJbgTG4ZjLnyrLanxDr6M1k/dSNa6V5QnILwjUKJcw==", - "dev": true, - "requires": { - "cross-fetch": "^2.1.1", - "eth-json-rpc-middleware": "^1.5.0", - "json-rpc-engine": "^3.4.0", - "json-rpc-error": "^2.0.0", - "tape": "^4.8.0" - } - }, - "eth-json-rpc-middleware": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-1.6.0.tgz", - "integrity": "sha512-tDVCTlrUvdqHKqivYMjtFZsdD7TtpNLBCfKAcOpaVs7orBMS/A8HWro6dIzNtTZIR05FAbJ3bioFOnZpuCew9Q==", - "dev": true, - "requires": { - "async": "^2.5.0", - "eth-query": "^2.1.2", - "eth-tx-summary": "^3.1.2", - "ethereumjs-block": "^1.6.0", - "ethereumjs-tx": "^1.3.3", - "ethereumjs-util": "^5.1.2", - "ethereumjs-vm": "^2.1.0", - "fetch-ponyfill": "^4.0.0", - "json-rpc-engine": "^3.6.0", - "json-rpc-error": "^2.0.0", - "json-stable-stringify": "^1.0.1", - "promise-to-callback": "^1.0.0", - "tape": "^4.6.3" - }, - "dependencies": { - "ethereum-common": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/ethereum-common/-/ethereum-common-0.2.0.tgz", - "integrity": "sha512-XOnAR/3rntJgbCdGhqdaLIxDLWKLmsZOGhHdBKadEr6gEnJLH52k93Ou+TUdFaPN3hJc3isBZBal3U/XZ15abA==", - "dev": true - }, - "ethereumjs-block": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/ethereumjs-block/-/ethereumjs-block-1.7.1.tgz", - "integrity": "sha512-B+sSdtqm78fmKkBq78/QLKJbu/4Ts4P2KFISdgcuZUPDm9x+N7qgBPIIFUGbaakQh8bzuquiRVbdmvPKqbILRg==", - "dev": true, - "requires": { - "async": "^2.0.1", - "ethereum-common": "0.2.0", - "ethereumjs-tx": "^1.2.2", - "ethereumjs-util": "^5.0.0", - "merkle-patricia-tree": "^2.1.2" - } - }, - "ethereumjs-common": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ethereumjs-common/-/ethereumjs-common-1.1.0.tgz", - "integrity": "sha512-LUmYkKV/HcZbWRyu3OU9YOevsH3VJDXtI6kEd8VZweQec+JjDGKCmAVKUyzhYUHqxRJu7JNALZ3A/b3NXOP6tA==", - "dev": true - }, - "ethereumjs-util": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", - "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", - "dev": true, - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "ethjs-util": "^0.1.3", - "keccak": "^1.0.2", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.0.1" - } - }, - "ethereumjs-vm": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/ethereumjs-vm/-/ethereumjs-vm-2.6.0.tgz", - "integrity": "sha512-r/XIUik/ynGbxS3y+mvGnbOKnuLo40V5Mj1J25+HEO63aWYREIqvWeRO/hnROlMBE5WoniQmPmhiaN0ctiHaXw==", - "dev": true, - "requires": { - "async": "^2.1.2", - "async-eventemitter": "^0.2.2", - "ethereumjs-account": "^2.0.3", - "ethereumjs-block": "~2.2.0", - "ethereumjs-common": "^1.1.0", - "ethereumjs-util": "^6.0.0", - "fake-merkle-patricia-tree": "^1.0.1", - "functional-red-black-tree": "^1.0.1", - "merkle-patricia-tree": "^2.3.2", - "rustbn.js": "~0.2.0", - "safe-buffer": "^5.1.1" - }, - "dependencies": { - "ethereumjs-block": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ethereumjs-block/-/ethereumjs-block-2.2.0.tgz", - "integrity": "sha512-Ye+uG/L2wrp364Zihdlr/GfC3ft+zG8PdHcRtsBFNNH1CkOhxOwdB8friBU85n89uRZ9eIMAywCq0F4CwT1wAw==", - "dev": true, - "requires": { - "async": "^2.0.1", - "ethereumjs-common": "^1.1.0", - "ethereumjs-tx": "^1.2.2", - "ethereumjs-util": "^5.0.0", - "merkle-patricia-tree": "^2.1.2" - }, - "dependencies": { - "ethereumjs-util": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", - "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", - "dev": true, - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "ethjs-util": "^0.1.3", - "keccak": "^1.0.2", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.0.1" - } - } - } - }, - "ethereumjs-util": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.1.0.tgz", - "integrity": "sha512-URESKMFbDeJxnAxPppnk2fN6Y3BIatn9fwn76Lm8bQlt+s52TpG8dN9M66MLPuRAiAOIqL3dfwqWJf0sd0fL0Q==", - "dev": true, - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "ethjs-util": "0.1.6", - "keccak": "^1.0.2", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.0.1" - } - }, - "merkle-patricia-tree": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/merkle-patricia-tree/-/merkle-patricia-tree-2.3.2.tgz", - "integrity": "sha512-81PW5m8oz/pz3GvsAwbauj7Y00rqm81Tzad77tHBwU7pIAtN+TJnMSOJhxBKflSVYhptMMb9RskhqHqrSm1V+g==", - "dev": true, - "requires": { - "async": "^1.4.2", - "ethereumjs-util": "^5.0.0", - "level-ws": "0.0.0", - "levelup": "^1.2.1", - "memdown": "^1.0.0", - "readable-stream": "^2.0.0", - "rlp": "^2.0.0", - "semaphore": ">=1.0.1" - }, - "dependencies": { - "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", - "dev": true - }, - "ethereumjs-util": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", - "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", - "dev": true, - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "ethjs-util": "^0.1.3", - "keccak": "^1.0.2", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.0.1" - } - } - } - } - } - }, - "level-codec": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/level-codec/-/level-codec-7.0.1.tgz", - "integrity": "sha512-Ua/R9B9r3RasXdRmOtd+t9TCOEIIlts+TN/7XTT2unhDaL6sJn83S3rUyljbr6lVtw49N3/yA0HHjpV6Kzb2aQ==", - "dev": true - }, - "level-errors": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/level-errors/-/level-errors-1.0.5.tgz", - "integrity": "sha512-/cLUpQduF6bNrWuAC4pwtUKA5t669pCsCi2XbmojG2tFeOr9j6ShtdDCtFFQO1DRt+EVZhx9gPzP9G2bUaG4ig==", - "dev": true, - "requires": { - "errno": "~0.1.1" - } - }, - "levelup": { - "version": "1.3.9", - "resolved": "https://registry.npmjs.org/levelup/-/levelup-1.3.9.tgz", - "integrity": "sha512-VVGHfKIlmw8w1XqpGOAGwq6sZm2WwWLmlDcULkKWQXEA5EopA8OBNJ2Ck2v6bdk8HeEZSbCSEgzXadyQFm76sQ==", - "dev": true, - "requires": { - "deferred-leveldown": "~1.2.1", - "level-codec": "~7.0.0", - "level-errors": "~1.0.3", - "level-iterator-stream": "~1.3.0", - "prr": "~1.0.1", - "semver": "~5.4.1", - "xtend": "~4.0.0" - } - } - } - }, "eth-lib": { "version": "0.1.27", "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.1.27.tgz", @@ -3055,337 +1781,6 @@ "xhr-request-promise": "^0.1.2" } }, - "eth-query": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/eth-query/-/eth-query-2.1.2.tgz", - "integrity": "sha1-1nQdkAAQa1FRDHLbktY2VFam2l4=", - "dev": true, - "requires": { - "json-rpc-random-id": "^1.0.0", - "xtend": "^4.0.1" - } - }, - "eth-sig-util": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-2.0.2.tgz", - "integrity": "sha512-tB6E8jf/aZQ943bo3+iojl8xRe3Jzcl+9OT6v8K7kWis6PdIX19SB2vYvN849cB9G9m/XLjYFK381SgdbsnpTA==", - "dev": true, - "requires": { - "ethereumjs-abi": "0.6.5", - "ethereumjs-util": "^5.1.1" - }, - "dependencies": { - "ethereumjs-util": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", - "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", - "dev": true, - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "ethjs-util": "^0.1.3", - "keccak": "^1.0.2", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.0.1" - } - } - } - }, - "eth-tx-summary": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/eth-tx-summary/-/eth-tx-summary-3.2.4.tgz", - "integrity": "sha512-NtlDnaVZah146Rm8HMRUNMgIwG/ED4jiqk0TME9zFheMl1jOp6jL1m0NKGjJwehXQ6ZKCPr16MTr+qspKpEXNg==", - "dev": true, - "requires": { - "async": "^2.1.2", - "clone": "^2.0.0", - "concat-stream": "^1.5.1", - "end-of-stream": "^1.1.0", - "eth-query": "^2.0.2", - "ethereumjs-block": "^1.4.1", - "ethereumjs-tx": "^1.1.1", - "ethereumjs-util": "^5.0.1", - "ethereumjs-vm": "^2.6.0", - "through2": "^2.0.3" - }, - "dependencies": { - "ethereum-common": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/ethereum-common/-/ethereum-common-0.2.0.tgz", - "integrity": "sha512-XOnAR/3rntJgbCdGhqdaLIxDLWKLmsZOGhHdBKadEr6gEnJLH52k93Ou+TUdFaPN3hJc3isBZBal3U/XZ15abA==", - "dev": true - }, - "ethereumjs-block": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/ethereumjs-block/-/ethereumjs-block-1.7.1.tgz", - "integrity": "sha512-B+sSdtqm78fmKkBq78/QLKJbu/4Ts4P2KFISdgcuZUPDm9x+N7qgBPIIFUGbaakQh8bzuquiRVbdmvPKqbILRg==", - "dev": true, - "requires": { - "async": "^2.0.1", - "ethereum-common": "0.2.0", - "ethereumjs-tx": "^1.2.2", - "ethereumjs-util": "^5.0.0", - "merkle-patricia-tree": "^2.1.2" - } - }, - "ethereumjs-common": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ethereumjs-common/-/ethereumjs-common-1.1.0.tgz", - "integrity": "sha512-LUmYkKV/HcZbWRyu3OU9YOevsH3VJDXtI6kEd8VZweQec+JjDGKCmAVKUyzhYUHqxRJu7JNALZ3A/b3NXOP6tA==", - "dev": true - }, - "ethereumjs-util": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", - "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", - "dev": true, - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "ethjs-util": "^0.1.3", - "keccak": "^1.0.2", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.0.1" - } - }, - "ethereumjs-vm": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/ethereumjs-vm/-/ethereumjs-vm-2.6.0.tgz", - "integrity": "sha512-r/XIUik/ynGbxS3y+mvGnbOKnuLo40V5Mj1J25+HEO63aWYREIqvWeRO/hnROlMBE5WoniQmPmhiaN0ctiHaXw==", - "dev": true, - "requires": { - "async": "^2.1.2", - "async-eventemitter": "^0.2.2", - "ethereumjs-account": "^2.0.3", - "ethereumjs-block": "~2.2.0", - "ethereumjs-common": "^1.1.0", - "ethereumjs-util": "^6.0.0", - "fake-merkle-patricia-tree": "^1.0.1", - "functional-red-black-tree": "^1.0.1", - "merkle-patricia-tree": "^2.3.2", - "rustbn.js": "~0.2.0", - "safe-buffer": "^5.1.1" - }, - "dependencies": { - "ethereumjs-block": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ethereumjs-block/-/ethereumjs-block-2.2.0.tgz", - "integrity": "sha512-Ye+uG/L2wrp364Zihdlr/GfC3ft+zG8PdHcRtsBFNNH1CkOhxOwdB8friBU85n89uRZ9eIMAywCq0F4CwT1wAw==", - "dev": true, - "requires": { - "async": "^2.0.1", - "ethereumjs-common": "^1.1.0", - "ethereumjs-tx": "^1.2.2", - "ethereumjs-util": "^5.0.0", - "merkle-patricia-tree": "^2.1.2" - }, - "dependencies": { - "ethereumjs-util": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", - "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", - "dev": true, - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "ethjs-util": "^0.1.3", - "keccak": "^1.0.2", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.0.1" - } - } - } - }, - "ethereumjs-util": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.1.0.tgz", - "integrity": "sha512-URESKMFbDeJxnAxPppnk2fN6Y3BIatn9fwn76Lm8bQlt+s52TpG8dN9M66MLPuRAiAOIqL3dfwqWJf0sd0fL0Q==", - "dev": true, - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "ethjs-util": "0.1.6", - "keccak": "^1.0.2", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.0.1" - } - }, - "merkle-patricia-tree": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/merkle-patricia-tree/-/merkle-patricia-tree-2.3.2.tgz", - "integrity": "sha512-81PW5m8oz/pz3GvsAwbauj7Y00rqm81Tzad77tHBwU7pIAtN+TJnMSOJhxBKflSVYhptMMb9RskhqHqrSm1V+g==", - "dev": true, - "requires": { - "async": "^1.4.2", - "ethereumjs-util": "^5.0.0", - "level-ws": "0.0.0", - "levelup": "^1.2.1", - "memdown": "^1.0.0", - "readable-stream": "^2.0.0", - "rlp": "^2.0.0", - "semaphore": ">=1.0.1" - }, - "dependencies": { - "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", - "dev": true - }, - "ethereumjs-util": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", - "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", - "dev": true, - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "ethjs-util": "^0.1.3", - "keccak": "^1.0.2", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.0.1" - } - } - } - } - } - }, - "level-codec": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/level-codec/-/level-codec-7.0.1.tgz", - "integrity": "sha512-Ua/R9B9r3RasXdRmOtd+t9TCOEIIlts+TN/7XTT2unhDaL6sJn83S3rUyljbr6lVtw49N3/yA0HHjpV6Kzb2aQ==", - "dev": true - }, - "level-errors": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/level-errors/-/level-errors-1.0.5.tgz", - "integrity": "sha512-/cLUpQduF6bNrWuAC4pwtUKA5t669pCsCi2XbmojG2tFeOr9j6ShtdDCtFFQO1DRt+EVZhx9gPzP9G2bUaG4ig==", - "dev": true, - "requires": { - "errno": "~0.1.1" - } - }, - "levelup": { - "version": "1.3.9", - "resolved": "https://registry.npmjs.org/levelup/-/levelup-1.3.9.tgz", - "integrity": "sha512-VVGHfKIlmw8w1XqpGOAGwq6sZm2WwWLmlDcULkKWQXEA5EopA8OBNJ2Ck2v6bdk8HeEZSbCSEgzXadyQFm76sQ==", - "dev": true, - "requires": { - "deferred-leveldown": "~1.2.1", - "level-codec": "~7.0.0", - "level-errors": "~1.0.3", - "level-iterator-stream": "~1.3.0", - "prr": "~1.0.1", - "semver": "~5.4.1", - "xtend": "~4.0.0" - } - } - } - }, - "ethereum-common": { - "version": "0.0.16", - "resolved": "https://registry.npmjs.org/ethereum-common/-/ethereum-common-0.0.16.tgz", - "integrity": "sha1-mh4Wnq00q3XgifUMpRK/0PvRJlU=", - "dev": true - }, - "ethereumjs-abi": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.5.tgz", - "integrity": "sha1-WmN+8Wq0NHP6cqKa2QhxQFs/UkE=", - "dev": true, - "requires": { - "bn.js": "^4.10.0", - "ethereumjs-util": "^4.3.0" - }, - "dependencies": { - "ethereumjs-util": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-4.5.0.tgz", - "integrity": "sha1-PpQosxfuvaPXJg2FT93alUsfG8Y=", - "dev": true, - "requires": { - "bn.js": "^4.8.0", - "create-hash": "^1.1.2", - "keccakjs": "^0.2.0", - "rlp": "^2.0.0", - "secp256k1": "^3.0.1" - } - } - } - }, - "ethereumjs-account": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/ethereumjs-account/-/ethereumjs-account-2.0.5.tgz", - "integrity": "sha512-bgDojnXGjhMwo6eXQC0bY6UK2liSFUSMwwylOmQvZbSl/D7NXQ3+vrGO46ZeOgjGfxXmgIeVNDIiHw7fNZM4VA==", - "dev": true, - "requires": { - "ethereumjs-util": "^5.0.0", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1" - }, - "dependencies": { - "ethereumjs-util": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", - "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", - "dev": true, - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "ethjs-util": "^0.1.3", - "keccak": "^1.0.2", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.0.1" - } - } - } - }, - "ethereumjs-block": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/ethereumjs-block/-/ethereumjs-block-1.2.2.tgz", - "integrity": "sha1-LsdTSlkCG47JuDww5JaQxuuu3aE=", - "dev": true, - "requires": { - "async": "^1.5.2", - "ethereum-common": "0.0.16", - "ethereumjs-tx": "^1.0.0", - "ethereumjs-util": "^4.0.1", - "merkle-patricia-tree": "^2.1.2" - }, - "dependencies": { - "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", - "dev": true - }, - "ethereumjs-util": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-4.5.0.tgz", - "integrity": "sha1-PpQosxfuvaPXJg2FT93alUsfG8Y=", - "dev": true, - "requires": { - "bn.js": "^4.8.0", - "create-hash": "^1.1.2", - "keccakjs": "^0.2.0", - "rlp": "^2.0.0", - "secp256k1": "^3.0.1" - } - } - } - }, - "ethereumjs-common": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/ethereumjs-common/-/ethereumjs-common-0.6.1.tgz", - "integrity": "sha512-4jOrfDu9qOBTTGGb3zrfT1tE1Hyc6a8LJpEk0Vk9AYlLkBY7crjVICyJpRvjNI+KLDMpMITMw3eWVZOLMtZdhw==", - "dev": true - }, "ethereumjs-testrpc-sc": { "version": "6.1.6", "resolved": "https://registry.npmjs.org/ethereumjs-testrpc-sc/-/ethereumjs-testrpc-sc-6.1.6.tgz", @@ -3395,39 +1790,6 @@ "source-map-support": "^0.5.3" } }, - "ethereumjs-tx": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/ethereumjs-tx/-/ethereumjs-tx-1.3.4.tgz", - "integrity": "sha512-kOgUd5jC+0tgV7t52UDECMMz9Uf+Lro+6fSpCvzWemtXfMEcwI3EOxf5mVPMRbTFkMMhuERokNNVF3jItAjidg==", - "dev": true, - "requires": { - "ethereum-common": "^0.0.18", - "ethereumjs-util": "^5.0.0" - }, - "dependencies": { - "ethereum-common": { - "version": "0.0.18", - "resolved": "https://registry.npmjs.org/ethereum-common/-/ethereum-common-0.0.18.tgz", - "integrity": "sha1-L9w1dvIykDNYl26znaeDIT/5Uj8=", - "dev": true - }, - "ethereumjs-util": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", - "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", - "dev": true, - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "ethjs-util": "^0.1.3", - "keccak": "^1.0.2", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.0.1" - } - } - } - }, "ethereumjs-util": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.0.0.tgz", @@ -3438,115 +1800,9 @@ "create-hash": "^1.1.2", "ethjs-util": "^0.1.6", "keccak": "^1.0.2", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.0.1" - } - }, - "ethereumjs-vm": { - "version": "https://github.com/Agusx1211/ethereumjs-vm/releases/download/2.4.1/ethereumjs-vm-2.4.4-coverage.tar.gz", - "integrity": "sha512-MDHFkodtVBn/mrJ7ZUF6UrG36OyvKIq79zbzo2w3vA5QXeqEvp06Jw1a3r0tELNYOyiPPNt+2boyH9XCZ4GipQ==", - "dev": true, - "requires": { - "async": "^2.1.2", - "async-eventemitter": "^0.2.2", - "ethereumjs-account": "^2.0.3", - "ethereumjs-block": "~2.1.0", - "ethereumjs-common": "^0.6.0", - "ethereumjs-util": "^6.0.0", - "fake-merkle-patricia-tree": "^1.0.1", - "functional-red-black-tree": "^1.0.1", - "merkle-patricia-tree": "^2.1.2", - "rustbn.js": "~0.2.0", - "safe-buffer": "^5.1.1" - }, - "dependencies": { - "ethereumjs-block": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ethereumjs-block/-/ethereumjs-block-2.1.0.tgz", - "integrity": "sha512-ip+x4/7hUInX+TQfhEKsQh9MJK1Dbjp4AuPjf1UdX3udAV4beYD4EMCNIPzBLCsGS8WQZYXLpo83tVTISYNpow==", - "dev": true, - "requires": { - "async": "^2.0.1", - "ethereumjs-common": "^0.6.0", - "ethereumjs-tx": "^1.2.2", - "ethereumjs-util": "^5.0.0", - "merkle-patricia-tree": "^2.1.2" - }, - "dependencies": { - "ethereumjs-util": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", - "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", - "dev": true, - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "ethjs-util": "^0.1.3", - "keccak": "^1.0.2", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.0.1" - } - } - } - } - } - }, - "ethereumjs-wallet": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/ethereumjs-wallet/-/ethereumjs-wallet-0.6.2.tgz", - "integrity": "sha512-DHEKPV9lYORM7dL8602dkb+AgdfzCYz2lxpdYQoD3OwG355LLDuivW9rGuLpDMCry/ORyBYV6n+QCo/71SwACg==", - "dev": true, - "optional": true, - "requires": { - "aes-js": "^3.1.1", - "bs58check": "^2.1.2", - "ethereumjs-util": "^5.2.0", - "hdkey": "^1.0.0", - "safe-buffer": "^5.1.2", - "scrypt.js": "^0.2.0", - "utf8": "^3.0.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "aes-js": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.1.2.tgz", - "integrity": "sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ==", - "dev": true, - "optional": true - }, - "ethereumjs-util": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", - "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", - "dev": true, - "optional": true, - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "ethjs-util": "^0.1.3", - "keccak": "^1.0.2", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.0.1" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "optional": true - }, - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", - "dev": true, - "optional": true - } + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1", + "secp256k1": "^3.0.1" } }, "ethers": { @@ -3652,12 +1908,6 @@ "integrity": "sha1-R3hr2qCHyvext15zq8XH1UAVjNA=", "dev": true }, - "events": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", - "integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==", - "dev": true - }, "evp_bytestokey": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", @@ -3769,15 +2019,6 @@ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", "dev": true }, - "fake-merkle-patricia-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/fake-merkle-patricia-tree/-/fake-merkle-patricia-tree-1.0.1.tgz", - "integrity": "sha1-S4w6z7Ugr635hgsfFM2M40As3dM=", - "dev": true, - "requires": { - "checkpoint-store": "^1.1.0" - } - }, "fast-deep-equal": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", @@ -3811,27 +2052,6 @@ "pend": "~1.2.0" } }, - "fetch-ponyfill": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/fetch-ponyfill/-/fetch-ponyfill-4.1.0.tgz", - "integrity": "sha1-rjzl9zLGReq4fkroeTQUcJsjmJM=", - "dev": true, - "requires": { - "node-fetch": "~1.7.1" - }, - "dependencies": { - "node-fetch": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", - "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", - "dev": true, - "requires": { - "encoding": "^0.1.11", - "is-stream": "^1.0.1" - } - } - } - }, "figures": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", @@ -3959,15 +2179,6 @@ "rimraf": "^2.2.8" } }, - "fs-minipass": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", - "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", - "dev": true, - "requires": { - "minipass": "^2.2.1" - } - }, "fs-promise": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/fs-promise/-/fs-promise-2.0.3.tgz", @@ -4402,441 +2613,384 @@ } }, "ganache-cli-coverage": { - "version": "github:Agusx1211/ganache-cli#c462b3fc48fe9b16756f7799885c0741114d9ed3", - "from": "github:Agusx1211/ganache-cli#c462b3fc48fe9b16756f7799885c0741114d9ed3", - "dev": true, - "requires": { - "async": "^2.6.1", - "bn.js": "4.11.8", - "ganache-core": "github:agusx1211/ganache-core#coverage", - "source-map-support": "^0.5.3", - "web3": "^1.0.0-beta.36", - "yargs": "^11.0.0" - } - }, - "ganache-core": { - "version": "github:agusx1211/ganache-core#d885dd09685f84150db8ef11cd6929785acd0f98", - "from": "github:agusx1211/ganache-core#coverage", + "version": "github:frangio/ganache-cli#41ad7490dfcd165c7409f89898eb76e733dd4c88", + "from": "github:frangio/ganache-cli#coverage", "dev": true, "requires": { - "abstract-leveldown": "3.0.0", - "async": "2.6.1", - "bip39": "2.5.0", "bn.js": "4.11.8", - "cachedown": "1.0.0", - "clone": "2.1.2", - "debug": "3.1.0", - "encoding-down": "5.0.4", - "eth-sig-util": "2.0.2", - "ethereumjs-abi": "0.6.5", - "ethereumjs-account": "2.0.5", - "ethereumjs-block": "1.2.2", - "ethereumjs-tx": "1.3.4", - "ethereumjs-util": "^5.2.0", - "ethereumjs-vm": "https://github.com/Agusx1211/ethereumjs-vm/releases/download/2.4.1/ethereumjs-vm-2.4.4-coverage.tar.gz", - "ethereumjs-wallet": "0.6.2", - "heap": "0.2.6", - "level-sublevel": "6.6.4", - "levelup": "3.1.1", - "lodash": "4.17.10", - "merkle-patricia-tree": "2.3.1", - "seedrandom": "2.4.4", - "tmp": "0.0.33", - "web3": "1.0.0-beta.35", - "web3-provider-engine": "14.1.0", - "websocket": "1.0.26" + "source-map-support": "0.5.9", + "yargs": "11.1.0" }, "dependencies": { - "async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", - "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", - "dev": true, - "requires": { - "lodash": "^4.17.10" - } + "ansi-regex": { + "version": "3.0.0", + "bundled": true, + "dev": true }, - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "requires": { - "ms": "2.0.0" - } + "bn.js": { + "version": "4.11.8", + "bundled": true, + "dev": true + }, + "buffer-from": { + "version": "1.1.1", + "bundled": true, + "dev": true }, - "ethereumjs-util": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", - "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", + "cliui": { + "version": "4.1.0", + "bundled": true, "dev": true, "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "ethjs-util": "^0.1.3", - "keccak": "^1.0.2", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.0.1" + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" } }, - "lodash": { - "version": "4.17.10", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", - "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==", + "code-point-at": { + "version": "1.1.0", + "bundled": true, "dev": true }, - "utf8": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/utf8/-/utf8-2.1.1.tgz", - "integrity": "sha1-LgHbAvfY0JRPdxBPFgnrDDBM92g=", - "dev": true, - "optional": true - }, - "uuid": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", - "integrity": "sha1-wqMN7bPlNdcsz4LjQ5QaULqFM6w=", - "dev": true, - "optional": true - }, - "web3": { - "version": "1.0.0-beta.35", - "resolved": "https://registry.npmjs.org/web3/-/web3-1.0.0-beta.35.tgz", - "integrity": "sha512-xwDmUhvTcHQvvNnOPcPZZgCxKUsI2e+GbHy7JkTK3/Rmnutazy8x7fsAXT9myw7V1qpi3GgLoZ3fkglSUbg1Mg==", + "cross-spawn": { + "version": "5.1.0", + "bundled": true, "dev": true, - "optional": true, "requires": { - "web3-bzz": "1.0.0-beta.35", - "web3-core": "1.0.0-beta.35", - "web3-eth": "1.0.0-beta.35", - "web3-eth-personal": "1.0.0-beta.35", - "web3-net": "1.0.0-beta.35", - "web3-shh": "1.0.0-beta.35", - "web3-utils": "1.0.0-beta.35" + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } }, - "web3-bzz": { - "version": "1.0.0-beta.35", - "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.0.0-beta.35.tgz", - "integrity": "sha512-BhAU0qhlr8zltm4gs/+P1gki2VkxHJaM2Rrh4DGesDW0lzwufRoNvWFlwx1bKHoFPWNbSmm9PRkHOYOINL/Tgw==", + "decamelize": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "execa": { + "version": "0.7.0", + "bundled": true, "dev": true, - "optional": true, "requires": { - "got": "7.1.0", - "swarm-js": "0.1.37", - "underscore": "1.8.3" + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" } }, - "web3-core": { - "version": "1.0.0-beta.35", - "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.0.0-beta.35.tgz", - "integrity": "sha512-ayGavbgVk4KL9Y88Uv411fBJ0SVgVfKhKEBweKYzmP0zOqneMzWt6YsyD1n6kRvjAbqA0AfUPEOKyMNjcx2tjw==", + "find-up": { + "version": "2.1.0", + "bundled": true, "dev": true, - "optional": true, "requires": { - "web3-core-helpers": "1.0.0-beta.35", - "web3-core-method": "1.0.0-beta.35", - "web3-core-requestmanager": "1.0.0-beta.35", - "web3-utils": "1.0.0-beta.35" + "locate-path": "^2.0.0" } }, - "web3-core-helpers": { - "version": "1.0.0-beta.35", - "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.0.0-beta.35.tgz", - "integrity": "sha512-APOu3sEsamyqWt//8o4yq9KF25/uqGm+pQShson/sC4gKzmfJB07fLo2ond0X30E8fIqAPeVCotPXQxGciGUmA==", + "get-caller-file": { + "version": "1.0.3", + "bundled": true, + "dev": true + }, + "get-stream": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "invert-kv": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "isexe": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "lcid": { + "version": "1.0.0", + "bundled": true, "dev": true, - "optional": true, "requires": { - "underscore": "1.8.3", - "web3-eth-iban": "1.0.0-beta.35", - "web3-utils": "1.0.0-beta.35" + "invert-kv": "^1.0.0" } }, - "web3-core-method": { - "version": "1.0.0-beta.35", - "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.0.0-beta.35.tgz", - "integrity": "sha512-jidImCide8q0GpfsO4L73qoHrbkeWgwU3uOH5DKtJtv0ccmG086knNMRgryb/o9ZgetDWLmDEsJnHjBSoIwcbA==", + "locate-path": { + "version": "2.0.0", + "bundled": true, "dev": true, - "optional": true, "requires": { - "underscore": "1.8.3", - "web3-core-helpers": "1.0.0-beta.35", - "web3-core-promievent": "1.0.0-beta.35", - "web3-core-subscriptions": "1.0.0-beta.35", - "web3-utils": "1.0.0-beta.35" + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "dependencies": { + "path-exists": { + "version": "3.0.0", + "bundled": true, + "dev": true + } } }, - "web3-core-promievent": { - "version": "1.0.0-beta.35", - "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.0.0-beta.35.tgz", - "integrity": "sha512-GvqXqKq07OmHuVi5uNRg6k79a1/CI0ViCC+EtNv4CORHtDRmYEt5Bvdv6z6FJEiaaQkD0lKbFwNhLxutx7HItw==", + "lru-cache": { + "version": "4.1.4", + "bundled": true, "dev": true, - "optional": true, "requires": { - "any-promise": "1.3.0", - "eventemitter3": "1.1.1" + "pseudomap": "^1.0.2", + "yallist": "^3.0.2" } }, - "web3-core-requestmanager": { - "version": "1.0.0-beta.35", - "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.0.0-beta.35.tgz", - "integrity": "sha512-S+zW2h17ZZQU9oe3yaCJE0E7aJS4C3Kf4kGPDv+nXjW0gKhQQhgVhw1Doq/aYQGqNSWJp7f1VHkz5gQWwg6RRg==", + "mem": { + "version": "1.1.0", + "bundled": true, "dev": true, - "optional": true, "requires": { - "underscore": "1.8.3", - "web3-core-helpers": "1.0.0-beta.35", - "web3-providers-http": "1.0.0-beta.35", - "web3-providers-ipc": "1.0.0-beta.35", - "web3-providers-ws": "1.0.0-beta.35" + "mimic-fn": "^1.0.0" } }, - "web3-core-subscriptions": { - "version": "1.0.0-beta.35", - "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.0.0-beta.35.tgz", - "integrity": "sha512-gXzLrWvcGkGiWq1y33Z4Y80XI8XMrwowiQJkrPSjQ81K5PBKquOGwcMffLaKcwdmEy/NpsOXDeFo3eLE1Ghvvw==", + "mimic-fn": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "npm-run-path": { + "version": "2.0.2", + "bundled": true, "dev": true, - "optional": true, "requires": { - "eventemitter3": "1.1.1", - "underscore": "1.8.3", - "web3-core-helpers": "1.0.0-beta.35" + "path-key": "^2.0.0" } }, - "web3-eth": { - "version": "1.0.0-beta.35", - "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.0.0-beta.35.tgz", - "integrity": "sha512-04mcb2nGPXThawuuYICPOxv0xOHofvQKsjZeIq+89nyOC8DQMGTAErDkGyMHQYtjpth5XDhic0wuEsA80AmFZA==", + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "os-locale": { + "version": "2.1.0", + "bundled": true, "dev": true, - "optional": true, "requires": { - "underscore": "1.8.3", - "web3-core": "1.0.0-beta.35", - "web3-core-helpers": "1.0.0-beta.35", - "web3-core-method": "1.0.0-beta.35", - "web3-core-subscriptions": "1.0.0-beta.35", - "web3-eth-abi": "1.0.0-beta.35", - "web3-eth-accounts": "1.0.0-beta.35", - "web3-eth-contract": "1.0.0-beta.35", - "web3-eth-iban": "1.0.0-beta.35", - "web3-eth-personal": "1.0.0-beta.35", - "web3-net": "1.0.0-beta.35", - "web3-utils": "1.0.0-beta.35" + "execa": "^0.7.0", + "lcid": "^1.0.0", + "mem": "^1.1.0" } }, - "web3-eth-abi": { - "version": "1.0.0-beta.35", - "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.0.0-beta.35.tgz", - "integrity": "sha512-KUDC+EtFFYG8z01ZleKrASdjj327/rtWHzEt6RWsEj7bBa0bGp9nEh+nqdZx/Sdgz1O8tnfFzJlrRcXpfr1vGg==", + "p-finally": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "bundled": true, "dev": true, - "optional": true, "requires": { - "bn.js": "4.11.6", - "underscore": "1.8.3", - "web3-core-helpers": "1.0.0-beta.35", - "web3-utils": "1.0.0-beta.35" - }, - "dependencies": { - "bn.js": { - "version": "4.11.6", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", - "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=", - "dev": true, - "optional": true - } + "p-try": "^1.0.0" } }, - "web3-eth-accounts": { - "version": "1.0.0-beta.35", - "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.0.0-beta.35.tgz", - "integrity": "sha512-duIgRsfht/0kAW/eQ0X9lKtVIykbETrnM2H7EnvplCzPHtQLodpib4o9JXfh9n6ZDgdDC7cuJoiVB9QJg089ew==", + "p-locate": { + "version": "2.0.0", + "bundled": true, "dev": true, - "optional": true, "requires": { - "any-promise": "1.3.0", - "crypto-browserify": "3.12.0", - "eth-lib": "0.2.7", - "scrypt.js": "0.2.0", - "underscore": "1.8.3", - "uuid": "2.0.1", - "web3-core": "1.0.0-beta.35", - "web3-core-helpers": "1.0.0-beta.35", - "web3-core-method": "1.0.0-beta.35", - "web3-utils": "1.0.0-beta.35" - }, - "dependencies": { - "eth-lib": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.7.tgz", - "integrity": "sha1-L5Pxex4jrsN1nNSj/iDBKGo/wco=", - "dev": true, - "optional": true, - "requires": { - "bn.js": "^4.11.6", - "elliptic": "^6.4.0", - "xhr-request-promise": "^0.1.2" - } - } + "p-limit": "^1.1.0" } }, - "web3-eth-contract": { - "version": "1.0.0-beta.35", - "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.0.0-beta.35.tgz", - "integrity": "sha512-foPohOg5O1UCGKGZOIs+kQK5IZdV2QQ7pAWwNxH8WHplUA+fre1MurXNpoxknUmH6mYplFhXjqgYq2MsrBpHrA==", + "p-try": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "path-key": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "bundled": true, "dev": true, - "optional": true, "requires": { - "underscore": "1.8.3", - "web3-core": "1.0.0-beta.35", - "web3-core-helpers": "1.0.0-beta.35", - "web3-core-method": "1.0.0-beta.35", - "web3-core-promievent": "1.0.0-beta.35", - "web3-core-subscriptions": "1.0.0-beta.35", - "web3-eth-abi": "1.0.0-beta.35", - "web3-utils": "1.0.0-beta.35" + "shebang-regex": "^1.0.0" } }, - "web3-eth-iban": { - "version": "1.0.0-beta.35", - "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.0.0-beta.35.tgz", - "integrity": "sha512-H5wkcNcAIc+h/WoDIKv7ZYmrM2Xqu3O7jBQl1IWo73EDVQji+AoB2i3J8tuwI1yZRInRwrfpI3Zuwuf54hXHmQ==", + "shebang-regex": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true + }, + "source-map-support": { + "version": "0.5.9", + "bundled": true, "dev": true, - "optional": true, "requires": { - "bn.js": "4.11.6", - "web3-utils": "1.0.0-beta.35" + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" }, "dependencies": { - "bn.js": { - "version": "4.11.6", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", - "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=", - "dev": true, - "optional": true + "source-map": { + "version": "0.6.1", + "bundled": true, + "dev": true } } }, - "web3-eth-personal": { - "version": "1.0.0-beta.35", - "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.0.0-beta.35.tgz", - "integrity": "sha512-AcM9nnlxu7ZRRxPvkrFB9eLxMM4A2cPfj2aCg21Wb2EpMnhR+b/O1cT33k7ApRowoMpM+T9M8vx2oPNwXfaCOQ==", + "string-width": { + "version": "2.1.1", + "bundled": true, "dev": true, - "optional": true, "requires": { - "web3-core": "1.0.0-beta.35", - "web3-core-helpers": "1.0.0-beta.35", - "web3-core-method": "1.0.0-beta.35", - "web3-net": "1.0.0-beta.35", - "web3-utils": "1.0.0-beta.35" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" } }, - "web3-net": { - "version": "1.0.0-beta.35", - "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.0.0-beta.35.tgz", - "integrity": "sha512-bbwaQ/KohGjIJ6HAKbZ6KrklCAaG6/B7hIbAbVLSFLxF+Yz9lmAgQYaDInpidpC/NLb3WOmcbRF+P77J4qMVIA==", + "strip-ansi": { + "version": "4.0.0", + "bundled": true, "dev": true, - "optional": true, "requires": { - "web3-core": "1.0.0-beta.35", - "web3-core-method": "1.0.0-beta.35", - "web3-utils": "1.0.0-beta.35" + "ansi-regex": "^3.0.0" } }, - "web3-providers-http": { - "version": "1.0.0-beta.35", - "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.0.0-beta.35.tgz", - "integrity": "sha512-DcIMFq52Fb08UpWyZ3ZlES6NsNqJnco4hBS/Ej6eOcASfuUayPI+GLkYVZsnF3cBYqlH+DOKuArcKSuIxK7jIA==", - "dev": true, - "optional": true, - "requires": { - "web3-core-helpers": "1.0.0-beta.35", - "xhr2-cookies": "1.1.0" - } + "strip-eof": { + "version": "1.0.0", + "bundled": true, + "dev": true }, - "web3-providers-ipc": { - "version": "1.0.0-beta.35", - "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.0.0-beta.35.tgz", - "integrity": "sha512-iB0FG0HcpUnayfa8pn4guqEQ4Y1nrroi/jffdtQgFkrNt0sD3fMSwwC0AbmECqj3tDLl0e1slBR0RENll+ZF0g==", + "which": { + "version": "1.3.1", + "bundled": true, "dev": true, - "optional": true, "requires": { - "oboe": "2.1.3", - "underscore": "1.8.3", - "web3-core-helpers": "1.0.0-beta.35" + "isexe": "^2.0.0" } }, - "web3-providers-ws": { - "version": "1.0.0-beta.35", - "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.0.0-beta.35.tgz", - "integrity": "sha512-Cx64NgDStynKaUGDIIOfaCd0fZusL8h5avKTkdTjUu2aHhFJhZoVBGVLhoDtUaqZGWIZGcBJOoVf2JkGUOjDRQ==", + "which-module": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "wrap-ansi": { + "version": "2.1.0", + "bundled": true, "dev": true, - "optional": true, "requires": { - "underscore": "1.8.3", - "web3-core-helpers": "1.0.0-beta.35", - "websocket": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible" + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" }, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "bundled": true, "dev": true, - "optional": true, "requires": { - "ms": "2.0.0" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } }, - "websocket": { - "version": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", - "from": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible", + "strip-ansi": { + "version": "3.0.1", + "bundled": true, "dev": true, - "optional": true, "requires": { - "debug": "^2.2.0", - "nan": "^2.3.3", - "typedarray-to-buffer": "^3.1.2", - "yaeti": "^0.0.6" + "ansi-regex": "^2.0.0" } } } }, - "web3-shh": { - "version": "1.0.0-beta.35", - "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.0.0-beta.35.tgz", - "integrity": "sha512-8qSonk/x0xabERS9Sr6AIADN/Ty+5KwARkkGIfSYHKqFpdMDz+76F7cUCxtoCZoS8K04xgZlDKYe0TJXLYA0Fw==", + "y18n": { + "version": "3.2.1", + "bundled": true, + "dev": true + }, + "yallist": { + "version": "3.0.2", + "bundled": true, + "dev": true + }, + "yargs": { + "version": "11.1.0", + "bundled": true, "dev": true, - "optional": true, "requires": { - "web3-core": "1.0.0-beta.35", - "web3-core-method": "1.0.0-beta.35", - "web3-core-subscriptions": "1.0.0-beta.35", - "web3-net": "1.0.0-beta.35" + "cliui": "^4.0.0", + "decamelize": "^1.1.1", + "find-up": "^2.1.0", + "get-caller-file": "^1.0.1", + "os-locale": "^2.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^9.0.2" } }, - "web3-utils": { - "version": "1.0.0-beta.35", - "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.0.0-beta.35.tgz", - "integrity": "sha512-Dq6f0SOKj3BDFRgOPnE6ALbzBDCKVIW8mKWVf7tGVhTDHf+wQaWwQSC3aArFSqdExB75BPBPyDpuMTNszhljpA==", + "yargs-parser": { + "version": "9.0.2", + "bundled": true, "dev": true, - "optional": true, "requires": { - "bn.js": "4.11.6", - "eth-lib": "0.1.27", - "ethjs-unit": "0.1.6", - "number-to-bn": "1.7.0", - "randomhex": "0.1.5", - "underscore": "1.8.3", - "utf8": "2.1.1" + "camelcase": "^4.1.0" }, "dependencies": { - "bn.js": { - "version": "4.11.6", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", - "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=", - "dev": true, - "optional": true + "camelcase": { + "version": "4.1.0", + "bundled": true, + "dev": true } } } @@ -4893,12 +3047,6 @@ "process": "~0.5.1" } }, - "globals": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", - "dev": true - }, "globby": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", @@ -5062,30 +3210,12 @@ "minimalistic-assert": "^1.0.0" } }, - "hdkey": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/hdkey/-/hdkey-1.1.1.tgz", - "integrity": "sha512-DvHZ5OuavsfWs5yfVJZestsnc3wzPvLWNk6c2nRUfo6X+OtxypGt20vDDf7Ba+MJzjL3KS1og2nw2eBbLCOUTA==", - "dev": true, - "optional": true, - "requires": { - "coinstring": "^2.0.0", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.0.1" - } - }, "he": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", "dev": true }, - "heap": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/heap/-/heap-0.2.6.tgz", - "integrity": "sha1-CH4fELBGky/IWU3Z5tN4r8nR5aw=", - "dev": true - }, "hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -5097,16 +3227,6 @@ "minimalistic-crypto-utils": "^1.0.1" } }, - "home-or-tmp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", - "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", - "dev": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.1" - } - }, "hosted-git-info": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", @@ -5177,12 +3297,6 @@ "integrity": "sha512-YGG3ejvBNHRqu0559EOxxNFihD0AjpvHlC/pdGKd3X3ofe+CoJkYazwNJYTNebqpPKN+VVQbh4ZFn1DivMNuHA==", "dev": true }, - "immediate": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.2.3.tgz", - "integrity": "sha1-0UD6j2FGWb1lQSMwl92qwlzdmRw=", - "dev": true - }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -5301,15 +3415,6 @@ "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", "dev": true }, - "invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dev": true, - "requires": { - "loose-envify": "^1.0.0" - } - }, "invert-kv": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", @@ -5349,21 +3454,6 @@ "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", "dev": true }, - "is-finite": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", - "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "is-fn": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fn/-/is-fn-1.0.0.tgz", - "integrity": "sha1-lUPV3nvPWwiiLsiiC65uKG1RDYw=", - "dev": true - }, "is-fullwidth-code-point": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", @@ -5602,41 +3692,6 @@ "dev": true, "optional": true }, - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true - }, - "json-rpc-engine": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/json-rpc-engine/-/json-rpc-engine-3.8.0.tgz", - "integrity": "sha512-6QNcvm2gFuuK4TKU1uwfH0Qd/cOSb9c1lls0gbnIhciktIUQJwz6NQNAW4B1KiGPenv7IKu97V222Yo1bNhGuA==", - "dev": true, - "requires": { - "async": "^2.0.1", - "babel-preset-env": "^1.7.0", - "babelify": "^7.3.0", - "json-rpc-error": "^2.0.0", - "promise-to-callback": "^1.0.0", - "safe-event-emitter": "^1.0.1" - } - }, - "json-rpc-error": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/json-rpc-error/-/json-rpc-error-2.0.0.tgz", - "integrity": "sha1-p6+cICg4tekFxyUOVH8a/3cligI=", - "dev": true, - "requires": { - "inherits": "^2.0.1" - } - }, - "json-rpc-random-id": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-rpc-random-id/-/json-rpc-random-id-1.0.1.tgz", - "integrity": "sha1-uknZat7RRE27jaPSA3SKy7zeyMg=", - "dev": true - }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", @@ -5649,15 +3704,6 @@ "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", "dev": true }, - "json-stable-stringify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", - "dev": true, - "requires": { - "jsonify": "~0.0.0" - } - }, "json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", @@ -5670,12 +3716,6 @@ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", "dev": true }, - "json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", - "dev": true - }, "jsonfile": { "version": "2.4.0", "resolved": "http://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", @@ -5685,12 +3725,6 @@ "graceful-fs": "^4.1.6" } }, - "jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", - "dev": true - }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -5730,258 +3764,25 @@ "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", "dev": true, - "requires": { - "graceful-fs": "^4.1.9" - } - }, - "lcid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", - "dev": true, - "requires": { - "invert-kv": "^1.0.0" - } - }, - "lcov-parse": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-0.0.10.tgz", - "integrity": "sha1-GwuP+ayceIklBYK3C3ExXZ2m2aM=", - "dev": true - }, - "level-codec": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/level-codec/-/level-codec-9.0.0.tgz", - "integrity": "sha512-OIpVvjCcZNP5SdhcNupnsI1zo5Y9Vpm+k/F1gfG5kXrtctlrwanisakweJtE0uA0OpLukRfOQae+Fg0M5Debhg==", - "dev": true - }, - "level-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/level-errors/-/level-errors-2.0.0.tgz", - "integrity": "sha512-AmY4HCp9h3OiU19uG+3YWkdELgy05OTP/r23aNHaQKWv8DO787yZgsEuGVkoph40uwN+YdUKnANlrxSsoOaaxg==", - "dev": true, - "requires": { - "errno": "~0.1.1" - } - }, - "level-iterator-stream": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-1.3.1.tgz", - "integrity": "sha1-5Dt4sagUPm+pek9IXrjqUwNS8u0=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "level-errors": "^1.0.3", - "readable-stream": "^1.0.33", - "xtend": "^4.0.0" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "level-errors": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/level-errors/-/level-errors-1.1.2.tgz", - "integrity": "sha512-Sw/IJwWbPKF5Ai4Wz60B52yj0zYeqzObLh8k1Tk88jVmD51cJSKWSYpRyhVIvFzZdvsPqlH5wfhp/yxdsaQH4w==", - "dev": true, - "requires": { - "errno": "~0.1.1" - } - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - } - } - }, - "level-post": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/level-post/-/level-post-1.0.7.tgz", - "integrity": "sha512-PWYqG4Q00asOrLhX7BejSajByB4EmG2GaKHfj3h5UmmZ2duciXLPGYWIjBzLECFWUGOZWlm5B20h/n3Gs3HKew==", - "dev": true, - "requires": { - "ltgt": "^2.1.2" - } - }, - "level-sublevel": { - "version": "6.6.4", - "resolved": "https://registry.npmjs.org/level-sublevel/-/level-sublevel-6.6.4.tgz", - "integrity": "sha512-pcCrTUOiO48+Kp6F1+UAzF/OtWqLcQVTVF39HLdZ3RO8XBoXt+XVPKZO1vVr1aUoxHZA9OtD2e1v7G+3S5KFDA==", - "dev": true, - "requires": { - "bytewise": "~1.1.0", - "level-codec": "^9.0.0", - "level-errors": "^2.0.0", - "level-iterator-stream": "^2.0.3", - "ltgt": "~2.1.1", - "pull-defer": "^0.2.2", - "pull-level": "^2.0.3", - "pull-stream": "^3.6.8", - "typewiselite": "~1.0.0", - "xtend": "~4.0.0" - }, - "dependencies": { - "level-iterator-stream": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-2.0.3.tgz", - "integrity": "sha512-I6Heg70nfF+e5Y3/qfthJFexhRw/Gi3bIymCoXAlijZdAcLaPuWSJs3KXyTYf23ID6g0o2QF62Yh+grOXY3Rig==", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.5", - "xtend": "^4.0.0" - } - }, - "ltgt": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.1.3.tgz", - "integrity": "sha1-EIUaBtmWS5cReEQcI8nlJpjuzjQ=", - "dev": true - } - } - }, - "level-ws": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/level-ws/-/level-ws-0.0.0.tgz", - "integrity": "sha1-Ny5RIXeSSgBCSwtDrvK7QkltIos=", - "dev": true, - "requires": { - "readable-stream": "~1.0.15", - "xtend": "~2.1.1" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "object-keys": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", - "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=", - "dev": true - }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - }, - "xtend": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", - "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=", - "dev": true, - "requires": { - "object-keys": "~0.4.0" - } - } + "requires": { + "graceful-fs": "^4.1.9" } }, - "levelup": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/levelup/-/levelup-3.1.1.tgz", - "integrity": "sha512-9N10xRkUU4dShSRRFTBdNaBxofz+PGaIZO962ckboJZiNmLuhVT6FZ6ZKAsICKfUBO76ySaYU6fJWX/jnj3Lcg==", + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", "dev": true, "requires": { - "deferred-leveldown": "~4.0.0", - "level-errors": "~2.0.0", - "level-iterator-stream": "~3.0.0", - "xtend": "~4.0.0" - }, - "dependencies": { - "abstract-leveldown": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-5.0.0.tgz", - "integrity": "sha512-5mU5P1gXtsMIXg65/rsYGsi93+MlogXZ9FA8JnwKurHQg64bfXwGYVdVdijNTVNOlAsuIiOwHdvFFD5JqCJQ7A==", - "dev": true, - "requires": { - "xtend": "~4.0.0" - } - }, - "deferred-leveldown": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-4.0.2.tgz", - "integrity": "sha512-5fMC8ek8alH16QiV0lTCis610D1Zt1+LA4MS4d63JgS32lrCjTFDUFz2ao09/j2I4Bqb5jL4FZYwu7Jz0XO1ww==", - "dev": true, - "requires": { - "abstract-leveldown": "~5.0.0", - "inherits": "^2.0.3" - } - }, - "level-iterator-stream": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-3.0.1.tgz", - "integrity": "sha512-nEIQvxEED9yRThxvOrq8Aqziy4EGzrxSZK+QzEFAVuJvQ8glfyZ96GB6BoI4sBbLfjMXm2w4vu3Tkcm9obcY0g==", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.3.6", - "xtend": "^4.0.0" - } - }, - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", - "dev": true - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } + "invert-kv": "^1.0.0" } }, + "lcov-parse": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-0.0.10.tgz", + "integrity": "sha1-GwuP+ayceIklBYK3C3ExXZ2m2aM=", + "dev": true + }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", @@ -6049,42 +3850,12 @@ "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==", "dev": true }, - "looper": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/looper/-/looper-2.0.0.tgz", - "integrity": "sha1-Zs0Md0rz1P7axTeU90LbVtqPCew=", - "dev": true - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, "lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", "dev": true }, - "lru-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-3.2.0.tgz", - "integrity": "sha1-cXibO39Tmb7IVl3aOKow0qCX7+4=", - "dev": true, - "requires": { - "pseudomap": "^1.0.1" - } - }, - "ltgt": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.2.1.tgz", - "integrity": "sha1-81ypHEk/e3PaDgdJUwTxezH4fuU=", - "dev": true - }, "make-dir": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", @@ -6136,31 +3907,6 @@ "mimic-fn": "^1.0.0" } }, - "memdown": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/memdown/-/memdown-1.4.1.tgz", - "integrity": "sha1-tOThkhdGZP+65BNhqlAPMRnv4hU=", - "dev": true, - "requires": { - "abstract-leveldown": "~2.7.1", - "functional-red-black-tree": "^1.0.1", - "immediate": "^3.2.3", - "inherits": "~2.0.1", - "ltgt": "~2.2.0", - "safe-buffer": "~5.1.1" - }, - "dependencies": { - "abstract-leveldown": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-2.7.2.tgz", - "integrity": "sha512-+OVvxH2rHVEhWLdbudP6p0+dNMXu8JA1CbhP19T8paTYAcX7oJ4OVjT+ZUVpv7mITxXHqDMej+GdqXBmXkw09w==", - "dev": true, - "requires": { - "xtend": "~4.0.0" - } - } - } - }, "memorystream": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", @@ -6173,75 +3919,6 @@ "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", "dev": true }, - "merkle-patricia-tree": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/merkle-patricia-tree/-/merkle-patricia-tree-2.3.1.tgz", - "integrity": "sha512-Qp9Mpb3xazznXzzGQBqHbqCpT2AR9joUOHYYPiQjYCarrdCPCnLWXo4BFv77y4xN26KR224xoU1n/qYY7RYYgw==", - "dev": true, - "requires": { - "async": "^1.4.2", - "ethereumjs-util": "^5.0.0", - "level-ws": "0.0.0", - "levelup": "^1.2.1", - "memdown": "^1.0.0", - "readable-stream": "^2.0.0", - "rlp": "^2.0.0", - "semaphore": ">=1.0.1" - }, - "dependencies": { - "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", - "dev": true - }, - "ethereumjs-util": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", - "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", - "dev": true, - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "ethjs-util": "^0.1.3", - "keccak": "^1.0.2", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.0.1" - } - }, - "level-codec": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/level-codec/-/level-codec-7.0.1.tgz", - "integrity": "sha512-Ua/R9B9r3RasXdRmOtd+t9TCOEIIlts+TN/7XTT2unhDaL6sJn83S3rUyljbr6lVtw49N3/yA0HHjpV6Kzb2aQ==", - "dev": true - }, - "level-errors": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/level-errors/-/level-errors-1.0.5.tgz", - "integrity": "sha512-/cLUpQduF6bNrWuAC4pwtUKA5t669pCsCi2XbmojG2tFeOr9j6ShtdDCtFFQO1DRt+EVZhx9gPzP9G2bUaG4ig==", - "dev": true, - "requires": { - "errno": "~0.1.1" - } - }, - "levelup": { - "version": "1.3.9", - "resolved": "https://registry.npmjs.org/levelup/-/levelup-1.3.9.tgz", - "integrity": "sha512-VVGHfKIlmw8w1XqpGOAGwq6sZm2WwWLmlDcULkKWQXEA5EopA8OBNJ2Ck2v6bdk8HeEZSbCSEgzXadyQFm76sQ==", - "dev": true, - "requires": { - "deferred-leveldown": "~1.2.1", - "level-codec": "~7.0.0", - "level-errors": "~1.0.3", - "level-iterator-stream": "~1.3.0", - "prr": "~1.0.1", - "semver": "~5.4.1", - "xtend": "~4.0.0" - } - } - } - }, "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -6327,39 +4004,6 @@ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true }, - "minipass": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz", - "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "yallist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", - "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", - "dev": true - } - } - }, - "minizlib": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz", - "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==", - "dev": true, - "requires": { - "minipass": "^2.2.1" - } - }, "mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", @@ -6487,12 +4131,6 @@ "integrity": "sha512-2NpiFHqC87y/zFke0fC0spBXL3bBsoh/p5H1EFhshxjCR5+0g2d6BiXbUFz9v1sAcxsk2htp2eQnNIci2dIYcA==", "dev": true }, - "node-fetch": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz", - "integrity": "sha1-q4hOjn5X44qUR1POxwb3iNF2i7U=", - "dev": true - }, "nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", @@ -6559,12 +4197,6 @@ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true }, - "object-inspect": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", - "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", - "dev": true - }, "object-keys": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.0.tgz", @@ -6666,23 +4298,6 @@ "integrity": "sha1-DxMEcVhM0zURxew4yNWSE/msXiA=", "dev": true }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true - }, - "os-locale": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", - "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", - "dev": true, - "requires": { - "execa": "^0.7.0", - "lcid": "^1.0.0", - "mem": "^1.1.0" - } - }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", @@ -6902,12 +4517,6 @@ "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", "dev": true }, - "precond": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/precond/-/precond-0.2.3.tgz", - "integrity": "sha1-qpWRvKokkj8eD0hJ0kD0fvwQdaw=", - "dev": true - }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -6988,12 +4597,6 @@ } } }, - "private": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", - "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", - "dev": true - }, "process": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz", @@ -7012,16 +4615,6 @@ "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=", "dev": true }, - "promise-to-callback": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/promise-to-callback/-/promise-to-callback-1.0.0.tgz", - "integrity": "sha1-XSp0kBC/tn2WNZj805YHRqaP7vc=", - "dev": true, - "requires": { - "is-fn": "^1.0.0", - "set-immediate-shim": "^1.0.1" - } - }, "proxy-addr": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", @@ -7032,12 +4625,6 @@ "ipaddr.js": "1.8.0" } }, - "prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", - "dev": true - }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", @@ -7066,64 +4653,6 @@ } } }, - "pull-cat": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/pull-cat/-/pull-cat-1.1.11.tgz", - "integrity": "sha1-tkLdElXaN2pwa220+pYvX9t0wxs=", - "dev": true - }, - "pull-defer": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/pull-defer/-/pull-defer-0.2.3.tgz", - "integrity": "sha512-/An3KE7mVjZCqNhZsr22k1Tx8MACnUnHZZNPSJ0S62td8JtYr/AiRG42Vz7Syu31SoTLUzVIe61jtT/pNdjVYA==", - "dev": true - }, - "pull-level": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pull-level/-/pull-level-2.0.4.tgz", - "integrity": "sha512-fW6pljDeUThpq5KXwKbRG3X7Ogk3vc75d5OQU/TvXXui65ykm+Bn+fiktg+MOx2jJ85cd+sheufPL+rw9QSVZg==", - "dev": true, - "requires": { - "level-post": "^1.0.7", - "pull-cat": "^1.1.9", - "pull-live": "^1.0.1", - "pull-pushable": "^2.0.0", - "pull-stream": "^3.4.0", - "pull-window": "^2.1.4", - "stream-to-pull-stream": "^1.7.1" - } - }, - "pull-live": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/pull-live/-/pull-live-1.0.1.tgz", - "integrity": "sha1-pOzuAeMwFV6RJLu89HYfIbOPUfU=", - "dev": true, - "requires": { - "pull-cat": "^1.1.9", - "pull-stream": "^3.4.0" - } - }, - "pull-pushable": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/pull-pushable/-/pull-pushable-2.2.0.tgz", - "integrity": "sha1-Xy867UethpGfAbEqLpnW8b13ZYE=", - "dev": true - }, - "pull-stream": { - "version": "3.6.9", - "resolved": "https://registry.npmjs.org/pull-stream/-/pull-stream-3.6.9.tgz", - "integrity": "sha512-hJn4POeBrkttshdNl0AoSCVjMVSuBwuHocMerUdoZ2+oIUzrWHFTwJMlbHND7OiKLVgvz6TFj8ZUVywUMXccbw==", - "dev": true - }, - "pull-window": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/pull-window/-/pull-window-2.1.4.tgz", - "integrity": "sha1-/DuG/uvRkgx64pdpHiP3BfiFUvA=", - "dev": true, - "requires": { - "looper": "^2.0.0" - } - }, "punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", @@ -7147,12 +4676,6 @@ "strict-uri-encode": "^1.0.0" } }, - "querystringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.0.tgz", - "integrity": "sha512-sluvZZ1YiTLD5jsqZcDmFyV2EwToyXZBfpoVOmktMmW+VEnhgakFHnasVph65fOjGPTWN0Nw3+XQaSeMayr0kg==", - "dev": true - }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -7252,70 +4775,12 @@ "resolve": "^1.1.6" } }, - "regenerate": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", - "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", - "dev": true - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", - "dev": true - }, - "regenerator-transform": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", - "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", - "dev": true, - "requires": { - "babel-runtime": "^6.18.0", - "babel-types": "^6.19.0", - "private": "^0.1.6" - } - }, "regexpp": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==", "dev": true }, - "regexpu-core": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", - "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", - "dev": true, - "requires": { - "regenerate": "^1.2.1", - "regjsgen": "^0.2.0", - "regjsparser": "^0.1.4" - } - }, - "regjsgen": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", - "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", - "dev": true - }, - "regjsparser": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", - "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", - "dev": true, - "requires": { - "jsesc": "~0.5.0" - } - }, - "repeating": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", - "dev": true, - "requires": { - "is-finite": "^1.0.0" - } - }, "req-cwd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/req-cwd/-/req-cwd-1.0.1.tgz", @@ -7404,12 +4869,6 @@ "integrity": "sha1-5UBLgVV+91225JxacgBIk/4D4WI=", "dev": true }, - "requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", - "dev": true - }, "resolve": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.4.0.tgz", @@ -7435,15 +4894,6 @@ "signal-exit": "^3.0.2" } }, - "resumer": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/resumer/-/resumer-0.0.0.tgz", - "integrity": "sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k=", - "dev": true, - "requires": { - "through": "~2.3.4" - } - }, "rimraf": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", @@ -7481,12 +4931,6 @@ "is-promise": "^2.1.0" } }, - "rustbn.js": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/rustbn.js/-/rustbn.js-0.2.0.tgz", - "integrity": "sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA==", - "dev": true - }, "rx-lite": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", @@ -7508,15 +4952,6 @@ "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", "dev": true }, - "safe-event-emitter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/safe-event-emitter/-/safe-event-emitter-1.0.1.tgz", - "integrity": "sha512-e1wFe99A91XYYxoQbcq2ZJUWurxEyP8vfz7A7vuUe1s95q8r5ebraVaA1BukYJcpM6V16ugWoD9vngi8Ccu5fg==", - "dev": true, - "requires": { - "events": "^3.0.0" - } - }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -7573,12 +5008,6 @@ "safe-buffer": "^5.1.0" } }, - "seedrandom": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-2.4.4.tgz", - "integrity": "sha512-9A+PDmgm+2du77B5i0Ip2cxOqqHjgNxnBgglxLcX78A2D6c2rTo61z4jnVABpF4cKeDMDG+cmXXvdnqse2VqMA==", - "dev": true - }, "seek-bzip": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.5.tgz", @@ -7599,12 +5028,6 @@ } } }, - "semaphore": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/semaphore/-/semaphore-1.1.0.tgz", - "integrity": "sha512-O4OZEaNtkMd/K0i6js9SL+gqy0ZCBMgUvlSqHKi4IBdjhe7wB8pwztUk1BbZ1fmrvpwFrPbHzqd2w5pTcJH6LA==", - "dev": true - }, "semver": { "version": "5.4.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", @@ -7671,12 +5094,6 @@ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, - "set-immediate-shim": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", - "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", - "dev": true - }, "setimmediate": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.4.tgz", @@ -7757,12 +5174,6 @@ "simple-concat": "^1.0.0" } }, - "slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", - "dev": true - }, "slice-ansi": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", @@ -8403,12 +5814,6 @@ } } }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, "source-map-support": { "version": "0.5.11", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.11.tgz", @@ -8474,26 +5879,8 @@ "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "dev": true - }, - "stream-to-pull-stream": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/stream-to-pull-stream/-/stream-to-pull-stream-1.7.2.tgz", - "integrity": "sha1-dXYJrhzr0zx0MtSvvjH/eGULnd4=", - "dev": true, - "requires": { - "looper": "^3.0.0", - "pull-stream": "^3.2.3" - }, - "dependencies": { - "looper": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/looper/-/looper-3.0.0.tgz", - "integrity": "sha1-LvpUw7HLq6m5Su4uWRSwvlf7t0k=", - "dev": true - } - } + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true }, "strict-uri-encode": { "version": "1.1.0", @@ -8701,79 +6088,6 @@ } } }, - "tape": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/tape/-/tape-4.10.1.tgz", - "integrity": "sha512-G0DywYV1jQeY3axeYnXUOt6ktnxS9OPJh97FGR3nrua8lhWi1zPflLxcAHavZ7Jf3qUfY7cxcVIVFa4mY2IY1w==", - "dev": true, - "requires": { - "deep-equal": "~1.0.1", - "defined": "~1.0.0", - "for-each": "~0.3.3", - "function-bind": "~1.1.1", - "glob": "~7.1.3", - "has": "~1.0.3", - "inherits": "~2.0.3", - "minimist": "~1.2.0", - "object-inspect": "~1.6.0", - "resolve": "~1.10.0", - "resumer": "~0.0.0", - "string.prototype.trim": "~1.1.2", - "through": "~2.3.8" - }, - "dependencies": { - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, - "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", - "dev": true - }, - "resolve": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", - "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", - "dev": true, - "requires": { - "path-parse": "^1.0.6" - } - } - } - }, "tar": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", @@ -8851,48 +6165,6 @@ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - }, - "dependencies": { - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", - "dev": true - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, "timed-out": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", @@ -8914,12 +6186,6 @@ "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==", "dev": true }, - "to-fast-properties": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", - "dev": true - }, "tough-cookie": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", @@ -8935,12 +6201,6 @@ "integrity": "sha512-4hjqbObwlh2dLyW4tcz0Ymw0ggoaVDMveUB9w8kFSQScdRLo0gxO9J7WFcUBo+W3C1TLdFIEwNOWebgZZ0RH9Q==", "dev": true }, - "trim-right": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", - "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", - "dev": true - }, "truffle": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/truffle/-/truffle-5.0.0.tgz", @@ -9076,686 +6336,191 @@ "safe-buffer": "^5.0.1" } }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true, - "optional": true - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true - }, - "type-is": { - "version": "1.6.16", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", - "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", - "dev": true, - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.18" - } - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true - }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "requires": { - "is-typedarray": "^1.0.0" - } - }, - "typewise": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typewise/-/typewise-1.0.3.tgz", - "integrity": "sha1-EGeTZUCvl5N8xdz5kiSG6fooRlE=", - "dev": true, - "requires": { - "typewise-core": "^1.2.0" - } - }, - "typewise-core": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/typewise-core/-/typewise-core-1.2.0.tgz", - "integrity": "sha1-l+uRgFx/VdL5QXSPpQ0xXZke8ZU=", - "dev": true - }, - "typewiselite": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typewiselite/-/typewiselite-1.0.0.tgz", - "integrity": "sha1-yIgvobsQksBgBal/NO9chQjjZk4=", - "dev": true - }, - "uglify-js": { - "version": "3.4.10", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", - "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==", - "dev": true, - "optional": true, - "requires": { - "commander": "~2.19.0", - "source-map": "~0.6.1" - }, - "dependencies": { - "commander": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", - "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", - "dev": true, - "optional": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true - } - } - }, - "ultron": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", - "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", - "dev": true - }, - "unbzip2-stream": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.3.3.tgz", - "integrity": "sha512-fUlAF7U9Ah1Q6EieQ4x4zLNejrRvDWUYmxXUpN3uziFYCHapjWFaCAnreY9bGgxzaMCFAPPpYNng57CypwJVhg==", - "dev": true, - "requires": { - "buffer": "^5.2.1", - "through": "^2.3.8" - } - }, - "underscore": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", - "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=", - "dev": true - }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true - }, - "unorm": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/unorm/-/unorm-1.5.0.tgz", - "integrity": "sha512-sMfSWoiRaXXeDZSXC+YRZ23H4xchQpwxjpw1tmfR+kgbBCaOgln4NI0LXejJIhnBuKINrB3WRn+ZI8IWssirVw==", - "dev": true - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "dev": true - }, - "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - }, - "dependencies": { - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - } - } - }, - "url-parse": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.4.tgz", - "integrity": "sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg==", - "dev": true, - "requires": { - "querystringify": "^2.0.0", - "requires-port": "^1.0.0" - } - }, - "url-parse-lax": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", - "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", - "dev": true, - "requires": { - "prepend-http": "^1.0.1" - } - }, - "url-set-query": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-set-query/-/url-set-query-1.0.0.tgz", - "integrity": "sha1-AW6M/Xwg7gXK/neV6JK9BwL6ozk=", - "dev": true - }, - "url-to-options": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", - "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=", - "dev": true - }, - "utf8": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", - "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==", + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", "dev": true, "optional": true }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "dev": true + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } }, - "uuid": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.0.tgz", - "integrity": "sha512-ijO9N2xY/YaOqQ5yz5c4sy2ZjWmA6AR6zASb/gdpeKZ8+948CxwfMW9RrKVk5may6ev8c0/Xguu32e2Llelpqw==", + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true }, - "validate-npm-package-license": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", - "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", + "type-is": { + "version": "1.6.16", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", "dev": true, "requires": { - "spdx-correct": "~1.0.0", - "spdx-expression-parse": "~1.0.0" + "media-typer": "0.3.0", + "mime-types": "~2.1.18" } }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", "dev": true, "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" + "is-typedarray": "^1.0.0" } }, - "web3": { - "version": "1.0.0-beta.48", - "resolved": "https://registry.npmjs.org/web3/-/web3-1.0.0-beta.48.tgz", - "integrity": "sha512-/HfIaRQVScZv0iy6fnEZCsXQbbOmtEB08sa2YaCkRo8nqUQo1C+55VC5sXqjrwKaDs9Xf9qxVTiUUeTbKD+KYg==", - "dev": true, - "requires": { - "@babel/runtime": "^7.3.1", - "@types/node": "^10.12.18", - "web3-bzz": "1.0.0-beta.48", - "web3-core": "1.0.0-beta.48", - "web3-core-helpers": "1.0.0-beta.48", - "web3-core-method": "1.0.0-beta.48", - "web3-eth": "1.0.0-beta.48", - "web3-eth-personal": "1.0.0-beta.48", - "web3-net": "1.0.0-beta.48", - "web3-providers": "1.0.0-beta.48", - "web3-shh": "1.0.0-beta.48", - "web3-utils": "1.0.0-beta.48" + "uglify-js": { + "version": "3.4.10", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", + "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==", + "dev": true, + "optional": true, + "requires": { + "commander": "~2.19.0", + "source-map": "~0.6.1" }, "dependencies": { - "ethers": { - "version": "4.0.26", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.26.tgz", - "integrity": "sha512-3hK4S8eAGhuWZ/feip5z17MswjGgjb4lEPJqWO/O0dNqToYLSHhvu6gGQPs8d9f+XfpEB2EYexfF0qjhWiZjUA==", - "dev": true, - "requires": { - "@types/node": "^10.3.2", - "aes-js": "3.0.0", - "bn.js": "^4.4.0", - "elliptic": "6.3.3", - "hash.js": "1.1.3", - "js-sha3": "0.5.7", - "scrypt-js": "2.0.4", - "setimmediate": "1.0.4", - "uuid": "2.0.1", - "xmlhttprequest": "1.8.0" - }, - "dependencies": { - "elliptic": { - "version": "6.3.3", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.3.3.tgz", - "integrity": "sha1-VILZZG1UvLif19mU/J4ulWiHbj8=", - "dev": true, - "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "inherits": "^2.0.1" - } - }, - "setimmediate": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.4.tgz", - "integrity": "sha1-IOgd5iLUoCWIzgyNqJc8vPHTE48=", - "dev": true - } - } - }, - "eventemitter3": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz", - "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==", - "dev": true - }, - "fs-extra": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", - "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "js-sha3": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", - "integrity": "sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc=", - "dev": true - }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", - "dev": true - }, - "swarm-js": { - "version": "0.1.39", - "resolved": "https://registry.npmjs.org/swarm-js/-/swarm-js-0.1.39.tgz", - "integrity": "sha512-QLMqL2rzF6n5s50BptyD6Oi0R1aWlJC5Y17SRIVXRj6OR1DRIPM7nepvrxxkjA1zNzFz6mUOMjfeqeDaWB7OOg==", - "dev": true, - "requires": { - "bluebird": "^3.5.0", - "buffer": "^5.0.5", - "decompress": "^4.0.0", - "eth-lib": "^0.1.26", - "fs-extra": "^4.0.2", - "got": "^7.1.0", - "mime-types": "^2.1.16", - "mkdirp-promise": "^5.0.1", - "mock-fs": "^4.1.0", - "setimmediate": "^1.0.5", - "tar": "^4.0.2", - "xhr-request-promise": "^0.1.2" - } - }, - "tar": { - "version": "4.4.8", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz", - "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==", - "dev": true, - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.3.4", - "minizlib": "^1.1.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.2" - } - }, - "utf8": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/utf8/-/utf8-2.1.1.tgz", - "integrity": "sha1-LgHbAvfY0JRPdxBPFgnrDDBM92g=", - "dev": true - }, - "uuid": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", - "integrity": "sha1-wqMN7bPlNdcsz4LjQ5QaULqFM6w=", - "dev": true - }, - "web3-bzz": { - "version": "1.0.0-beta.48", - "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.0.0-beta.48.tgz", - "integrity": "sha512-rl+z5cyBXefZ1tgmhnC4QDutCYYmURKogHSkmhoH3ow161D1P8qYrxDqNSXwNcuXyejUaaPzi5OLAlR3JTnyxw==", - "dev": true, - "requires": { - "@babel/runtime": "^7.3.1", - "@types/node": "^10.12.18", - "lodash": "^4.17.11", - "swarm-js": "^0.1.39" - } - }, - "web3-core": { - "version": "1.0.0-beta.48", - "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.0.0-beta.48.tgz", - "integrity": "sha512-vOciU4otvpqp5rRJlfjMGuq+OqBG0EYskKwUbQY+UUM8w8g8MRKjYZGzqIMGQGQ3liIbJGQk8WtiVQjh0e5ZrQ==", - "dev": true, - "requires": { - "@babel/runtime": "^7.3.1", - "@types/node": "^10.12.18", - "lodash": "^4.17.11", - "web3-utils": "1.0.0-beta.48" - } - }, - "web3-core-helpers": { - "version": "1.0.0-beta.48", - "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.0.0-beta.48.tgz", - "integrity": "sha512-WjRKTw67IVX1k0S600c9pyp1YZib3AjSOFWAyJu5XbhtckXryZ5oQVFbJRc7XVeJWJA0yLGnqZuSUSh4ot8Byw==", - "dev": true, - "requires": { - "@babel/runtime": "^7.3.1", - "lodash": "^4.17.11", - "web3-eth-iban": "1.0.0-beta.48", - "web3-utils": "1.0.0-beta.48" - } - }, - "web3-core-method": { - "version": "1.0.0-beta.48", - "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.0.0-beta.48.tgz", - "integrity": "sha512-/VfRiFzksrHqKbicK+Yw8SzK2hw/YXKjTQ6l/j9CVFw2FDpBqQtlo9A3qZNeoo6aIh1McTVeSSIrR9vJGFo3dw==", - "dev": true, - "requires": { - "@babel/runtime": "^7.3.1", - "eventemitter3": "3.1.0", - "lodash": "^4.17.11", - "web3-core": "1.0.0-beta.48", - "web3-core-helpers": "1.0.0-beta.48", - "web3-core-promievent": "1.0.0-beta.48", - "web3-core-subscriptions": "1.0.0-beta.48", - "web3-utils": "1.0.0-beta.48" - } - }, - "web3-core-promievent": { - "version": "1.0.0-beta.48", - "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.0.0-beta.48.tgz", - "integrity": "sha512-GNUnYUL0PUO/QzvlYxIlZW5Pra3jyjN6uHuUSDFRp59NbknluP470nTSC/+0XkvZrVTYADf0+04yyOlVM083Ug==", - "dev": true, - "requires": { - "@babel/runtime": "^7.3.1", - "eventemitter3": "^3.1.0" - } - }, - "web3-core-subscriptions": { - "version": "1.0.0-beta.48", - "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.0.0-beta.48.tgz", - "integrity": "sha512-9G5hQhFuEvEtZ+e+wEulpfGQnUny7McDiQ6G3pxN6b5/Wg7MVW5Zovcm8s7kvBGISW/8UkRVOJ1vYkzjH0Y2fg==", - "dev": true, - "requires": { - "@babel/runtime": "^7.3.1", - "eventemitter3": "^3.1.0", - "lodash": "^4.17.11", - "web3-core-helpers": "1.0.0-beta.48", - "web3-utils": "1.0.0-beta.48" - } - }, - "web3-eth": { - "version": "1.0.0-beta.48", - "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.0.0-beta.48.tgz", - "integrity": "sha512-PTSe+UAzd/HxKFzG8VVr0WePtnErHhXeRu3j2dA+Z4ucVULJcJo8r6ux+ekWKNZMxXV+gtJjoChk7WGIqXLmSw==", - "dev": true, - "requires": { - "@babel/runtime": "^7.3.1", - "eth-lib": "0.2.8", - "web3-core": "1.0.0-beta.48", - "web3-core-helpers": "1.0.0-beta.48", - "web3-core-method": "1.0.0-beta.48", - "web3-core-subscriptions": "1.0.0-beta.48", - "web3-eth-abi": "1.0.0-beta.48", - "web3-eth-accounts": "1.0.0-beta.48", - "web3-eth-contract": "1.0.0-beta.48", - "web3-eth-ens": "1.0.0-beta.48", - "web3-eth-iban": "1.0.0-beta.48", - "web3-eth-personal": "1.0.0-beta.48", - "web3-net": "1.0.0-beta.48", - "web3-providers": "1.0.0-beta.48", - "web3-utils": "1.0.0-beta.48" - }, - "dependencies": { - "eth-lib": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.8.tgz", - "integrity": "sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw==", - "dev": true, - "requires": { - "bn.js": "^4.11.6", - "elliptic": "^6.4.0", - "xhr-request-promise": "^0.1.2" - } - } - } - }, - "web3-eth-abi": { - "version": "1.0.0-beta.48", - "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.0.0-beta.48.tgz", - "integrity": "sha512-wT1EarsrxHSkd4ZKMn9McgRVXa5fFaNHkjBRo/idXWyV/MMrzs7oCa2AtovrCrkQRiT2GmecaBDLXxGPA06grw==", - "dev": true, - "requires": { - "@babel/runtime": "^7.3.1", - "ethers": "4.0.26", - "lodash": "^4.17.11", - "web3-utils": "1.0.0-beta.48" - } - }, - "web3-eth-accounts": { - "version": "1.0.0-beta.48", - "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.0.0-beta.48.tgz", - "integrity": "sha512-h+1I7Ao0ALKRz0EeDBcZ+ASYyvW06DZmsIYl0yqKTdH3ilfhTkPrEUjmnRPA9KKvJQvrmUkSLEcBHc6OxG+zlA==", - "dev": true, - "requires": { - "@babel/runtime": "^7.3.1", - "crypto-browserify": "3.12.0", - "eth-lib": "0.2.8", - "lodash": "^4.17.11", - "scrypt.js": "0.2.0", - "uuid": "3.3.2", - "web3-core": "1.0.0-beta.48", - "web3-core-helpers": "1.0.0-beta.48", - "web3-core-method": "1.0.0-beta.48", - "web3-providers": "1.0.0-beta.48", - "web3-utils": "1.0.0-beta.48" - }, - "dependencies": { - "eth-lib": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.8.tgz", - "integrity": "sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw==", - "dev": true, - "requires": { - "bn.js": "^4.11.6", - "elliptic": "^6.4.0", - "xhr-request-promise": "^0.1.2" - } - }, - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", - "dev": true - } - } - }, - "web3-eth-contract": { - "version": "1.0.0-beta.48", - "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.0.0-beta.48.tgz", - "integrity": "sha512-V02dZ0FozYAfE9LBiqHEUWNWY5K9EIFCoQ/9lJz/ixgeyzDe6LRWzec1fT0ntPrMaU3J3hr6+2Ikg41xnfYoaQ==", - "dev": true, - "requires": { - "@babel/runtime": "^7.3.1", - "lodash": "^4.17.11", - "web3-core": "1.0.0-beta.48", - "web3-core-helpers": "1.0.0-beta.48", - "web3-core-method": "1.0.0-beta.48", - "web3-core-promievent": "1.0.0-beta.48", - "web3-core-subscriptions": "1.0.0-beta.48", - "web3-eth-abi": "1.0.0-beta.48", - "web3-eth-accounts": "1.0.0-beta.48", - "web3-providers": "1.0.0-beta.48", - "web3-utils": "1.0.0-beta.48" - } - }, - "web3-eth-ens": { - "version": "1.0.0-beta.48", - "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.0.0-beta.48.tgz", - "integrity": "sha512-5pmpbms7n5o6zoKc77d5qWNbjPEfeU9qbTsmzbaZenriVpMqXpvdriuCDLkB/3OV4PvBi+z4Lj8RBTiDb2jBuA==", - "dev": true, - "requires": { - "@babel/runtime": "^7.3.1", - "eth-ens-namehash": "2.0.8", - "lodash": "^4.17.11", - "web3-core": "1.0.0-beta.48", - "web3-core-helpers": "1.0.0-beta.48", - "web3-core-method": "1.0.0-beta.48", - "web3-core-promievent": "1.0.0-beta.48", - "web3-eth-abi": "1.0.0-beta.48", - "web3-eth-contract": "1.0.0-beta.48", - "web3-net": "1.0.0-beta.48", - "web3-providers": "1.0.0-beta.48", - "web3-utils": "1.0.0-beta.48" - } - }, - "web3-eth-iban": { - "version": "1.0.0-beta.48", - "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.0.0-beta.48.tgz", - "integrity": "sha512-ZQapOV6qTP6Wb3TMFUNRyyFwFgPYbB4pGdSW3OkNjFpx8xr+QjcQgwa6EbnSgF+3ApgSWeUzPtdRlqvV/7j5Lw==", - "dev": true, - "requires": { - "@babel/runtime": "^7.3.1", - "bn.js": "4.11.8", - "web3-utils": "1.0.0-beta.48" - } - }, - "web3-eth-personal": { - "version": "1.0.0-beta.48", - "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.0.0-beta.48.tgz", - "integrity": "sha512-mcoslAQpxBbGiPRO6tOAHiLK3WoE+O1fN/6WJLRkEYlDUEJeo3eoWiAkkyaCZyzqCrrohZpZ977s7/spuxSSDA==", - "dev": true, - "requires": { - "@babel/runtime": "^7.3.1", - "web3-core": "1.0.0-beta.48", - "web3-core-helpers": "1.0.0-beta.48", - "web3-core-method": "1.0.0-beta.48", - "web3-net": "1.0.0-beta.48", - "web3-providers": "1.0.0-beta.48", - "web3-utils": "1.0.0-beta.48" - } - }, - "web3-net": { - "version": "1.0.0-beta.48", - "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.0.0-beta.48.tgz", - "integrity": "sha512-q9nLXc2DwepLaTvbJ8Bvv5QHJVY9CUNKJQnIYfcU+R5OHkZ9eN//B8skHbmk5dtbwKJbeUyt5sfZKas/cf4mlw==", - "dev": true, - "requires": { - "@babel/runtime": "^7.3.1", - "lodash": "^4.17.11", - "web3-core": "1.0.0-beta.48", - "web3-core-helpers": "1.0.0-beta.48", - "web3-core-method": "1.0.0-beta.48", - "web3-providers": "1.0.0-beta.48", - "web3-utils": "1.0.0-beta.48" - } - }, - "web3-shh": { - "version": "1.0.0-beta.48", - "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.0.0-beta.48.tgz", - "integrity": "sha512-7F3JcsdMxuq2ezC2BaSFqy0suXtU7a58CjUIM6kVeWa1a3jwSIPvfzlDtMe3AKaabeOay0jaHHs3UUbw4Hzi+A==", + "commander": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", + "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", "dev": true, - "requires": { - "@babel/runtime": "^7.3.1", - "web3-core": "1.0.0-beta.48", - "web3-core-helpers": "1.0.0-beta.48", - "web3-core-method": "1.0.0-beta.48", - "web3-core-subscriptions": "1.0.0-beta.48", - "web3-net": "1.0.0-beta.48", - "web3-providers": "1.0.0-beta.48", - "web3-utils": "1.0.0-beta.48" - } + "optional": true }, - "web3-utils": { - "version": "1.0.0-beta.48", - "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.0.0-beta.48.tgz", - "integrity": "sha512-TK61xy7mRpLt53M8GbPnrFr9lA2SmqLHvWIJN8K9cU4oDH9MWxuxxJ+Lxg+pQPKqIO9f1u+AiMRNvSEuMeeAmg==", + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, - "requires": { - "@babel/runtime": "^7.3.1", - "@types/bn.js": "^4.11.4", - "@types/node": "^10.12.18", - "bn.js": "4.11.8", - "eth-lib": "0.2.8", - "ethjs-unit": "^0.1.6", - "lodash": "^4.17.11", - "number-to-bn": "1.7.0", - "randomhex": "0.1.5", - "utf8": "2.1.1" - }, - "dependencies": { - "eth-lib": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.8.tgz", - "integrity": "sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw==", - "dev": true, - "requires": { - "bn.js": "^4.11.6", - "elliptic": "^6.4.0", - "xhr-request-promise": "^0.1.2" - } - } - } - }, - "yallist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", - "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", + "optional": true + } + } + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", + "dev": true + }, + "unbzip2-stream": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.3.3.tgz", + "integrity": "sha512-fUlAF7U9Ah1Q6EieQ4x4zLNejrRvDWUYmxXUpN3uziFYCHapjWFaCAnreY9bGgxzaMCFAPPpYNng57CypwJVhg==", + "dev": true, + "requires": { + "buffer": "^5.2.1", + "through": "^2.3.8" + } + }, + "underscore": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", + "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + }, + "dependencies": { + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true } } }, + "url-parse-lax": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", + "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "dev": true, + "requires": { + "prepend-http": "^1.0.1" + } + }, + "url-set-query": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-set-query/-/url-set-query-1.0.0.tgz", + "integrity": "sha1-AW6M/Xwg7gXK/neV6JK9BwL6ozk=", + "dev": true + }, + "url-to-options": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", + "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true + }, + "uuid": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.0.tgz", + "integrity": "sha512-ijO9N2xY/YaOqQ5yz5c4sy2ZjWmA6AR6zASb/gdpeKZ8+948CxwfMW9RrKVk5may6ev8c0/Xguu32e2Llelpqw==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", + "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", + "dev": true, + "requires": { + "spdx-correct": "~1.0.0", + "spdx-expression-parse": "~1.0.0" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, "web3-bzz": { "version": "1.0.0-beta.37", "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.0.0-beta.37.tgz", @@ -10030,266 +6795,6 @@ "web3-utils": "1.0.0-beta.37" } }, - "web3-provider-engine": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/web3-provider-engine/-/web3-provider-engine-14.1.0.tgz", - "integrity": "sha512-vGZtqhSUzGTiMGhJXNnB/aRDlrPZLhLnBZ2NPArkZtr8XSrwg9m08tw4+PuWg5za0TJuoE/vuPQc501HddZZWw==", - "dev": true, - "requires": { - "async": "^2.5.0", - "backoff": "^2.5.0", - "clone": "^2.0.0", - "cross-fetch": "^2.1.0", - "eth-block-tracker": "^3.0.0", - "eth-json-rpc-infura": "^3.1.0", - "eth-sig-util": "^1.4.2", - "ethereumjs-block": "^1.2.2", - "ethereumjs-tx": "^1.2.0", - "ethereumjs-util": "^5.1.5", - "ethereumjs-vm": "^2.3.4", - "json-rpc-error": "^2.0.0", - "json-stable-stringify": "^1.0.1", - "promise-to-callback": "^1.0.0", - "readable-stream": "^2.2.9", - "request": "^2.85.0", - "semaphore": "^1.0.3", - "ws": "^5.1.1", - "xhr": "^2.2.0", - "xtend": "^4.0.1" - }, - "dependencies": { - "eth-sig-util": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", - "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", - "dev": true, - "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git", - "ethereumjs-util": "^5.1.1" - } - }, - "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d8d7fc9cc1fd781186c25676af100d1ec727013e", - "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", - "dev": true, - "requires": { - "bn.js": "^4.11.8", - "ethereumjs-util": "^6.0.0" - }, - "dependencies": { - "ethereumjs-util": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.1.0.tgz", - "integrity": "sha512-URESKMFbDeJxnAxPppnk2fN6Y3BIatn9fwn76Lm8bQlt+s52TpG8dN9M66MLPuRAiAOIqL3dfwqWJf0sd0fL0Q==", - "dev": true, - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "ethjs-util": "0.1.6", - "keccak": "^1.0.2", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.0.1" - } - } - } - }, - "ethereumjs-common": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ethereumjs-common/-/ethereumjs-common-1.1.0.tgz", - "integrity": "sha512-LUmYkKV/HcZbWRyu3OU9YOevsH3VJDXtI6kEd8VZweQec+JjDGKCmAVKUyzhYUHqxRJu7JNALZ3A/b3NXOP6tA==", - "dev": true - }, - "ethereumjs-util": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", - "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", - "dev": true, - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "ethjs-util": "^0.1.3", - "keccak": "^1.0.2", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.0.1" - } - }, - "ethereumjs-vm": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/ethereumjs-vm/-/ethereumjs-vm-2.6.0.tgz", - "integrity": "sha512-r/XIUik/ynGbxS3y+mvGnbOKnuLo40V5Mj1J25+HEO63aWYREIqvWeRO/hnROlMBE5WoniQmPmhiaN0ctiHaXw==", - "dev": true, - "requires": { - "async": "^2.1.2", - "async-eventemitter": "^0.2.2", - "ethereumjs-account": "^2.0.3", - "ethereumjs-block": "~2.2.0", - "ethereumjs-common": "^1.1.0", - "ethereumjs-util": "^6.0.0", - "fake-merkle-patricia-tree": "^1.0.1", - "functional-red-black-tree": "^1.0.1", - "merkle-patricia-tree": "^2.3.2", - "rustbn.js": "~0.2.0", - "safe-buffer": "^5.1.1" - }, - "dependencies": { - "ethereumjs-block": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ethereumjs-block/-/ethereumjs-block-2.2.0.tgz", - "integrity": "sha512-Ye+uG/L2wrp364Zihdlr/GfC3ft+zG8PdHcRtsBFNNH1CkOhxOwdB8friBU85n89uRZ9eIMAywCq0F4CwT1wAw==", - "dev": true, - "requires": { - "async": "^2.0.1", - "ethereumjs-common": "^1.1.0", - "ethereumjs-tx": "^1.2.2", - "ethereumjs-util": "^5.0.0", - "merkle-patricia-tree": "^2.1.2" - }, - "dependencies": { - "ethereumjs-util": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", - "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", - "dev": true, - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "ethjs-util": "^0.1.3", - "keccak": "^1.0.2", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.0.1" - } - } - } - }, - "ethereumjs-util": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.1.0.tgz", - "integrity": "sha512-URESKMFbDeJxnAxPppnk2fN6Y3BIatn9fwn76Lm8bQlt+s52TpG8dN9M66MLPuRAiAOIqL3dfwqWJf0sd0fL0Q==", - "dev": true, - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "ethjs-util": "0.1.6", - "keccak": "^1.0.2", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.0.1" - } - } - } - }, - "level-codec": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/level-codec/-/level-codec-7.0.1.tgz", - "integrity": "sha512-Ua/R9B9r3RasXdRmOtd+t9TCOEIIlts+TN/7XTT2unhDaL6sJn83S3rUyljbr6lVtw49N3/yA0HHjpV6Kzb2aQ==", - "dev": true - }, - "level-errors": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/level-errors/-/level-errors-1.0.5.tgz", - "integrity": "sha512-/cLUpQduF6bNrWuAC4pwtUKA5t669pCsCi2XbmojG2tFeOr9j6ShtdDCtFFQO1DRt+EVZhx9gPzP9G2bUaG4ig==", - "dev": true, - "requires": { - "errno": "~0.1.1" - } - }, - "levelup": { - "version": "1.3.9", - "resolved": "https://registry.npmjs.org/levelup/-/levelup-1.3.9.tgz", - "integrity": "sha512-VVGHfKIlmw8w1XqpGOAGwq6sZm2WwWLmlDcULkKWQXEA5EopA8OBNJ2Ck2v6bdk8HeEZSbCSEgzXadyQFm76sQ==", - "dev": true, - "requires": { - "deferred-leveldown": "~1.2.1", - "level-codec": "~7.0.0", - "level-errors": "~1.0.3", - "level-iterator-stream": "~1.3.0", - "prr": "~1.0.1", - "semver": "~5.4.1", - "xtend": "~4.0.0" - } - }, - "merkle-patricia-tree": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/merkle-patricia-tree/-/merkle-patricia-tree-2.3.2.tgz", - "integrity": "sha512-81PW5m8oz/pz3GvsAwbauj7Y00rqm81Tzad77tHBwU7pIAtN+TJnMSOJhxBKflSVYhptMMb9RskhqHqrSm1V+g==", - "dev": true, - "requires": { - "async": "^1.4.2", - "ethereumjs-util": "^5.0.0", - "level-ws": "0.0.0", - "levelup": "^1.2.1", - "memdown": "^1.0.0", - "readable-stream": "^2.0.0", - "rlp": "^2.0.0", - "semaphore": ">=1.0.1" - }, - "dependencies": { - "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", - "dev": true - } - } - }, - "ws": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", - "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", - "dev": true, - "requires": { - "async-limiter": "~1.0.0" - } - } - } - }, - "web3-providers": { - "version": "1.0.0-beta.48", - "resolved": "https://registry.npmjs.org/web3-providers/-/web3-providers-1.0.0-beta.48.tgz", - "integrity": "sha512-rqWe370lftaYqvTSe8b7vdaANEBeoME6f30yD8VIEkKD6iEbp5TqCtP6A22zC6CEcVnCUrXIKsBCSI71f+QEtw==", - "dev": true, - "requires": { - "@babel/runtime": "^7.3.1", - "@types/node": "^10.12.18", - "eventemitter3": "3.1.0", - "lodash": "^4.17.11", - "oboe": "2.1.4", - "url-parse": "1.4.4", - "websocket": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible", - "xhr2-cookies": "1.1.0" - }, - "dependencies": { - "eventemitter3": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz", - "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==", - "dev": true - }, - "oboe": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/oboe/-/oboe-2.1.4.tgz", - "integrity": "sha1-IMiM2wwVNxuwQRklfU/dNLCqSfY=", - "dev": true, - "requires": { - "http-https": "^1.0.0" - } - }, - "websocket": { - "version": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", - "from": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible", - "dev": true, - "requires": { - "debug": "^2.2.0", - "nan": "^2.3.3", - "typedarray-to-buffer": "^3.1.2", - "yaeti": "^0.0.6" - } - } - } - }, "web3-providers-http": { "version": "1.0.0-beta.37", "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.0.0-beta.37.tgz", @@ -10376,23 +6881,6 @@ } } }, - "websocket": { - "version": "1.0.26", - "resolved": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", - "dev": true, - "requires": { - "debug": "^2.2.0", - "nan": "^2.3.3", - "typedarray-to-buffer": "^3.1.2", - "yaeti": "^0.0.6" - } - }, - "whatwg-fetch": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz", - "integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==", - "dev": true - }, "which": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", @@ -10402,12 +6890,6 @@ "isexe": "^2.0.0" } }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, "window-size": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", @@ -10531,77 +7013,6 @@ "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", "dev": true }, - "yargs": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz", - "integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==", - "dev": true, - "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.1.1", - "find-up": "^2.1.0", - "get-caller-file": "^1.0.1", - "os-locale": "^2.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^9.0.2" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "yargs-parser": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", - "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", - "dev": true, - "requires": { - "camelcase": "^4.1.0" - } - }, "yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", diff --git a/package.json b/package.json index 6ba304ce5a8..4d3b62b8aaf 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "ethereumjs-util": "^6.0.0", "ethjs-abi": "^0.2.1", "ganache-cli": "^6.4.1", - "ganache-cli-coverage": "github:Agusx1211/ganache-cli#c462b3fc48fe9b16756f7799885c0741114d9ed3", + "ganache-cli-coverage": "github:frangio/ganache-cli#coverage", "openzeppelin-test-helpers": "^0.3.2", "pify": "^4.0.1", "solhint": "^1.5.0", From 1f8b3d66cbaeb8ec230e35abbb7de66b732270da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Thu, 11 Apr 2019 14:13:07 -0300 Subject: [PATCH 59/64] Fix linter errors. --- contracts/mocks/ERC777SenderRecipientMock.sol | 52 +++++++++---------- test/drafts/ERC777/ERC777.behavior.js | 11 +++- test/drafts/ERC777/ERC777.test.js | 5 +- 3 files changed, 38 insertions(+), 30 deletions(-) diff --git a/contracts/mocks/ERC777SenderRecipientMock.sol b/contracts/mocks/ERC777SenderRecipientMock.sol index e93bfbda2f7..5c77c978b41 100644 --- a/contracts/mocks/ERC777SenderRecipientMock.sol +++ b/contracts/mocks/ERC777SenderRecipientMock.sol @@ -39,32 +39,6 @@ contract ERC777SenderRecipientMock is IERC777Sender, IERC777Recipient, ERC1820Im bytes32 constant private TOKENS_SENDER_INTERFACE_HASH = keccak256("ERC777TokensSender"); bytes32 constant private TOKENS_RECIPIENT_INTERFACE_HASH = keccak256("ERC777TokensRecipient"); - function senderFor(address account) public { - _registerInterfaceForAddress(TOKENS_SENDER_INTERFACE_HASH, account); - - address self = address(this); - if (account == self) { - registerSender(self); - } - } - - function registerSender(address sender) public { - _erc1820.setInterfaceImplementer(address(this), TOKENS_SENDER_INTERFACE_HASH, sender); - } - - function recipientFor(address account) public { - _registerInterfaceForAddress(TOKENS_RECIPIENT_INTERFACE_HASH, account); - - address self = address(this); - if (account == self) { - registerRecipient(self); - } - } - - function registerRecipient(address recipient) public { - _erc1820.setInterfaceImplementer(address(this), TOKENS_RECIPIENT_INTERFACE_HASH, recipient); - } - function tokensToSend( address operator, address from, @@ -127,6 +101,32 @@ contract ERC777SenderRecipientMock is IERC777Sender, IERC777Recipient, ERC1820Im ); } + function senderFor(address account) public { + _registerInterfaceForAddress(TOKENS_SENDER_INTERFACE_HASH, account); + + address self = address(this); + if (account == self) { + registerSender(self); + } + } + + function registerSender(address sender) public { + _erc1820.setInterfaceImplementer(address(this), TOKENS_SENDER_INTERFACE_HASH, sender); + } + + function recipientFor(address account) public { + _registerInterfaceForAddress(TOKENS_RECIPIENT_INTERFACE_HASH, account); + + address self = address(this); + if (account == self) { + registerRecipient(self); + } + } + + function registerRecipient(address recipient) public { + _erc1820.setInterfaceImplementer(address(this), TOKENS_RECIPIENT_INTERFACE_HASH, recipient); + } + function setShouldRevertSend(bool shouldRevert) public { _shouldRevertSend = shouldRevert; } diff --git a/test/drafts/ERC777/ERC777.behavior.js b/test/drafts/ERC777/ERC777.behavior.js index 93320cb9b1d..9bcb3c3853a 100644 --- a/test/drafts/ERC777/ERC777.behavior.js +++ b/test/drafts/ERC777/ERC777.behavior.js @@ -365,7 +365,16 @@ function shouldBehaveLikeERC777SendBurnWithSendHook (operator, amount, data, ope const { tx } = await sendFromHolder(this.token, this.sender, this.recipient, amount, data); await assertTokensToSendCalled( - this.token, tx, this.sender, this.sender, this.recipient, amount, data, null, preSenderBalance, preRecipientBalance + this.token, + tx, + this.sender, + this.sender, + this.recipient, + amount, + data, + null, + preSenderBalance, + preRecipientBalance, ); }); diff --git a/test/drafts/ERC777/ERC777.test.js b/test/drafts/ERC777/ERC777.test.js index 78acd09f245..b6df32ed825 100644 --- a/test/drafts/ERC777/ERC777.test.js +++ b/test/drafts/ERC777/ERC777.test.js @@ -1,5 +1,4 @@ -const { BN, constants, expectEvent, shouldFail, singletons } = require('openzeppelin-test-helpers'); -const { ZERO_ADDRESS } = constants; +const { BN, expectEvent, shouldFail, singletons } = require('openzeppelin-test-helpers'); const { shouldBehaveLikeERC777DirectSendBurn, @@ -233,7 +232,7 @@ contract('ERC777', function ([ describe('send and receive hooks', function () { const amount = new BN('1'); const operator = defaultOperatorA; - // sender and recipient are stored inside 'this', since for some tests their addresses are determined dynamically + // sender and recipient are stored inside 'this', since in some tests their addresses are determined dynamically describe('tokensReceived', function () { beforeEach(async function () { From 1feeac374bb25892e16449da226d46f2dfa55758 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Fri, 12 Apr 2019 17:12:37 -0300 Subject: [PATCH 60/64] Add mint tests. --- contracts/mocks/ERC777Mock.sol | 12 ++++- test/drafts/ERC777/ERC777.behavior.js | 65 ++++++++++++++++++++++++++- test/drafts/ERC777/ERC777.test.js | 54 +++++++++++++++++++--- 3 files changed, 122 insertions(+), 9 deletions(-) diff --git a/contracts/mocks/ERC777Mock.sol b/contracts/mocks/ERC777Mock.sol index 0e2aa0a6d26..5c32e051ceb 100644 --- a/contracts/mocks/ERC777Mock.sol +++ b/contracts/mocks/ERC777Mock.sol @@ -3,7 +3,7 @@ pragma solidity ^0.5.2; import "../drafts/ERC777/ERC777.sol"; contract ERC777Mock is ERC777 { - constructor ( + constructor( address initialHolder, uint256 initialBalance, string memory name, @@ -13,4 +13,14 @@ contract ERC777Mock is ERC777 { ) public ERC777(name, symbol, granularity, defaultOperators) { _mint(msg.sender, initialHolder, initialBalance, "", ""); } + + function mintInternal ( + address operator, + address to, + uint256 amount, + bytes memory userData, + bytes memory operatorData + ) public { + _mint(operator, to, amount, userData, operatorData); + } } diff --git a/test/drafts/ERC777/ERC777.behavior.js b/test/drafts/ERC777/ERC777.behavior.js index 9bcb3c3853a..1339a42b7be 100644 --- a/test/drafts/ERC777/ERC777.behavior.js +++ b/test/drafts/ERC777/ERC777.behavior.js @@ -259,7 +259,38 @@ function shouldBurnTokens (from, operator, amount, data, operatorData) { }); } -function shouldBehaveLikeERC777SendBurnWithReceiveHook (operator, amount, data, operatorData) { +function shouldBehaveLikeERC777InternalMint (recipient, operator, amount, data, operatorData) { + shouldInternalMintTokens(recipient, operator, new BN('0'), data, operatorData); + shouldInternalMintTokens(recipient, operator, amount, data, operatorData); + + it('reverts when minting tokens for the zero address', async function () { + shouldFail.reverting(this.token.mintInternal(recipient, operator, amount, data, operatorData)); + }); +} + +function shouldInternalMintTokens (operator, to, amount, data, operatorData) { + it(`can (internal) mint an amount of ${amount}`, async function () { + const initialTotalSupply = await this.token.totalSupply(); + const initialToBalance = await this.token.balanceOf(to); + + const { logs } = await this.token.mintInternal(operator, to, amount, data, operatorData); + expectEvent.inLogs(logs, 'Minted', { + operator, + to, + amount, + data, + operatorData, + }); + + const finalTotalSupply = await this.token.totalSupply(); + const finalToBalance = await this.token.balanceOf(to); + + finalTotalSupply.sub(initialTotalSupply).should.be.bignumber.equal(amount); + finalToBalance.sub(initialToBalance).should.be.bignumber.equal(amount); + }); +} + +function shouldBehaveLikeERC777SendBurnMintInternalWithReceiveHook (operator, amount, data, operatorData) { context('when TokensRecipient reverts', function () { beforeEach(async function () { await this.tokensRecipientImplementer.setShouldRevertReceive(true); @@ -274,6 +305,12 @@ function shouldBehaveLikeERC777SendBurnWithReceiveHook (operator, amount, data, this.token.operatorSend(this.sender, this.recipient, amount, data, operatorData, { from: operator }) ); }); + + it('mint (internal) reverts', async function () { + await shouldFail.reverting( + this.token.mintInteral(this.recipient, operator, amount, data, operatorData) + ); + }); }); context('when TokensRecipient does not revert', function () { @@ -323,6 +360,27 @@ function shouldBehaveLikeERC777SendBurnWithReceiveHook (operator, amount, data, postRecipientBalance, ); }); + + it('TokensRecipient receives mint (internal) data and is called after state mutation', async function () { + const { tx } = await this.token.mintInternal( + this.recipient, operator, amount, data, operatorData, + ); + + const postRecipientBalance = await this.token.balanceOf(this.recipient); + + await assertTokensReceivedCalled( + this.token, + tx, + operator, + ZERO_ADDRESS, + this.recipient, + amount, + data, + operatorData, + postSenderBalance, + postRecipientBalance, + ); + }); }); } @@ -467,6 +525,9 @@ module.exports = { shouldBehaveLikeERC777OperatorSendBurn, shouldBehaveLikeERC777UnauthorizedOperatorSendBurn, shouldDirectSendTokens, - shouldBehaveLikeERC777SendBurnWithReceiveHook, + shouldDirectBurnTokens, + shouldBehaveLikeERC777InternalMint, + shouldInternalMintTokens, + shouldBehaveLikeERC777SendBurnMintInternalWithReceiveHook, shouldBehaveLikeERC777SendBurnWithSendHook, }; diff --git a/test/drafts/ERC777/ERC777.test.js b/test/drafts/ERC777/ERC777.test.js index b6df32ed825..2eb5ec2d329 100644 --- a/test/drafts/ERC777/ERC777.test.js +++ b/test/drafts/ERC777/ERC777.test.js @@ -5,7 +5,10 @@ const { shouldBehaveLikeERC777OperatorSendBurn, shouldBehaveLikeERC777UnauthorizedOperatorSendBurn, shouldDirectSendTokens, - shouldBehaveLikeERC777SendBurnWithReceiveHook, + shouldDirectBurnTokens, + shouldBehaveLikeERC777InternalMint, + shouldInternalMintTokens, + shouldBehaveLikeERC777SendBurnMintInternalWithReceiveHook, shouldBehaveLikeERC777SendBurnWithSendHook, } = require('./ERC777.behavior'); @@ -90,8 +93,8 @@ contract('ERC777', function ([ }); }); - describe('send/burn', function () { - context('with no ERC777TokensSender and no ERC777TokensRecipient implementers', function () { + context('with no ERC777TokensSender and no ERC777TokensRecipient implementers', function () { + describe('send/burn', function () { shouldBehaveLikeERC777DirectSendBurn(holder, anyone, data); context('with self operator', function () { @@ -126,6 +129,23 @@ contract('ERC777', function ([ }); }); }); + + describe('mint (internal)', function () { + const to = anyone; + const amount = new BN('5'); + + context('with default operator', async function () { + const operator = defaultOperatorA; + + shouldBehaveLikeERC777InternalMint(to, operator, amount, data, operatorData); + }); + + context('with non operator', async function () { + const operator = newOperator; + + shouldBehaveLikeERC777InternalMint(to, operator, amount, data, operatorData); + }); + }); }); describe('operator management', function () { @@ -257,6 +277,12 @@ contract('ERC777', function ([ this.token.operatorSend(this.sender, this.recipient, amount, data, operatorData, { from: operator }) ); }); + + it('mint (internal) reverts', async function () { + await shouldFail.reverting( + this.token.mintInternal(this.recipient, operator, amount, data, operatorData) + ); + }); }); }); @@ -275,7 +301,7 @@ contract('ERC777', function ([ ); }); - shouldBehaveLikeERC777SendBurnWithReceiveHook(operator, amount, data, operatorData); + shouldBehaveLikeERC777SendBurnMintInternalWithReceiveHook(operator, amount, data, operatorData); }); context('with contract as implementer for another contract', function () { @@ -288,7 +314,7 @@ contract('ERC777', function ([ await this.recipientContract.registerRecipient(this.tokensRecipientImplementer.address); }); - shouldBehaveLikeERC777SendBurnWithReceiveHook(operator, amount, data, operatorData); + shouldBehaveLikeERC777SendBurnMintInternalWithReceiveHook(operator, amount, data, operatorData); }); context('with contract as implementer for itself', function () { @@ -299,7 +325,7 @@ contract('ERC777', function ([ await this.tokensRecipientImplementer.recipientFor(this.recipient); }); - shouldBehaveLikeERC777SendBurnWithReceiveHook(operator, amount, data, operatorData); + shouldBehaveLikeERC777SendBurnMintInternalWithReceiveHook(operator, amount, data, operatorData); }); }); }); @@ -399,6 +425,22 @@ contract('ERC777', function ([ it('reverts when sending an amount non-multiple of the granularity', async function () { await shouldFail.reverting(this.token.send(anyone, granularity.subn(1), data, { from })); }); + + shouldDirectBurnTokens(from, new BN('0'), data); + shouldDirectBurnTokens(from, granularity, data); + shouldDirectBurnTokens(from, granularity.muln(2), data); + + it('reverts when burning an amount non-multiple of the granularity', async function () { + await shouldFail.reverting(this.token.burn(granularity.subn(1), data, { from })); + }); + }); + + shouldInternalMintTokens(anyone, defaultOperatorA, new BN('0'), data, operatorData); + shouldInternalMintTokens(anyone, defaultOperatorA, granularity, data, operatorData); + shouldInternalMintTokens(anyone, defaultOperatorA, granularity.muln(2), data, operatorData); + + it('reverts when sending an amount non-multiple of the granularity', async function () { + await shouldFail.reverting(this.token.mintInternal(anyone, defaultOperatorA, granularity.subn(1), data, operatorData)); }); }); }); From 1b04f88f647ee6261cebc4fccec8afec29dfb312 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Fri, 12 Apr 2019 17:30:49 -0300 Subject: [PATCH 61/64] Fix linter errors. --- test/drafts/ERC777/ERC777.behavior.js | 2 +- test/drafts/ERC777/ERC777.test.js | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/test/drafts/ERC777/ERC777.behavior.js b/test/drafts/ERC777/ERC777.behavior.js index 1339a42b7be..362e937f3eb 100644 --- a/test/drafts/ERC777/ERC777.behavior.js +++ b/test/drafts/ERC777/ERC777.behavior.js @@ -377,7 +377,7 @@ function shouldBehaveLikeERC777SendBurnMintInternalWithReceiveHook (operator, am amount, data, operatorData, - postSenderBalance, + new BN('0'), postRecipientBalance, ); }); diff --git a/test/drafts/ERC777/ERC777.test.js b/test/drafts/ERC777/ERC777.test.js index 2eb5ec2d329..caa523645b0 100644 --- a/test/drafts/ERC777/ERC777.test.js +++ b/test/drafts/ERC777/ERC777.test.js @@ -440,7 +440,9 @@ contract('ERC777', function ([ shouldInternalMintTokens(anyone, defaultOperatorA, granularity.muln(2), data, operatorData); it('reverts when sending an amount non-multiple of the granularity', async function () { - await shouldFail.reverting(this.token.mintInternal(anyone, defaultOperatorA, granularity.subn(1), data, operatorData)); + await shouldFail.reverting( + this.token.mintInternal(anyone, defaultOperatorA, granularity.subn(1), data, operatorData) + ); }); }); }); From 455e84a969d82bde53de222a8895dc0c9ad2bfb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Mon, 15 Apr 2019 16:22:42 -0300 Subject: [PATCH 62/64] Fix tests. --- package-lock.json | 4 ++-- package.json | 2 +- test/drafts/ERC777/ERC777.behavior.js | 10 +++++----- test/drafts/ERC777/ERC777.test.js | 12 ++++++------ 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/package-lock.json b/package-lock.json index 908f99272a0..c36c4d1ef3d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2613,8 +2613,8 @@ } }, "ganache-cli-coverage": { - "version": "github:frangio/ganache-cli#41ad7490dfcd165c7409f89898eb76e733dd4c88", - "from": "github:frangio/ganache-cli#coverage", + "version": "https://github.com/frangio/ganache-cli/releases/download/v6.4.1-coverage/ganache-cli-coverage-6.4.1.tgz", + "integrity": "sha512-/BJIoofYEN5DuyUUO9edBGhQpMQTAuN03a1K8eqtWFkO29wHnbsaG/aIzahRbngcmV+A0ctyvokiLa2FL1rHeQ==", "dev": true, "requires": { "bn.js": "4.11.8", diff --git a/package.json b/package.json index 7ca4e27a570..4d38522266d 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "eslint-plugin-standard": "^3.1.0", "ethereumjs-util": "^6.0.0", "ganache-cli": "^6.4.1", - "ganache-cli-coverage": "github:frangio/ganache-cli#coverage", + "ganache-cli-coverage": "https://github.com/frangio/ganache-cli/releases/download/v6.4.1-coverage/ganache-cli-coverage-6.4.1.tgz", "openzeppelin-test-helpers": "^0.3.2", "solhint": "^1.5.0", "solidity-coverage": "github:rotcivegaf/solidity-coverage#5875f5b7bc74d447f3312c9c0e9fc7814b482477", diff --git a/test/drafts/ERC777/ERC777.behavior.js b/test/drafts/ERC777/ERC777.behavior.js index 362e937f3eb..771f4a1f2e0 100644 --- a/test/drafts/ERC777/ERC777.behavior.js +++ b/test/drafts/ERC777/ERC777.behavior.js @@ -260,11 +260,11 @@ function shouldBurnTokens (from, operator, amount, data, operatorData) { } function shouldBehaveLikeERC777InternalMint (recipient, operator, amount, data, operatorData) { - shouldInternalMintTokens(recipient, operator, new BN('0'), data, operatorData); - shouldInternalMintTokens(recipient, operator, amount, data, operatorData); + shouldInternalMintTokens(operator, recipient, new BN('0'), data, operatorData); + shouldInternalMintTokens(operator, recipient, amount, data, operatorData); it('reverts when minting tokens for the zero address', async function () { - shouldFail.reverting(this.token.mintInternal(recipient, operator, amount, data, operatorData)); + await shouldFail.reverting(this.token.mintInternal(operator, ZERO_ADDRESS, amount, data, operatorData)); }); } @@ -308,7 +308,7 @@ function shouldBehaveLikeERC777SendBurnMintInternalWithReceiveHook (operator, am it('mint (internal) reverts', async function () { await shouldFail.reverting( - this.token.mintInteral(this.recipient, operator, amount, data, operatorData) + this.token.mintInternal(operator, this.recipient, amount, data, operatorData) ); }); }); @@ -363,7 +363,7 @@ function shouldBehaveLikeERC777SendBurnMintInternalWithReceiveHook (operator, am it('TokensRecipient receives mint (internal) data and is called after state mutation', async function () { const { tx } = await this.token.mintInternal( - this.recipient, operator, amount, data, operatorData, + operator, this.recipient, amount, data, operatorData, ); const postRecipientBalance = await this.token.balanceOf(this.recipient); diff --git a/test/drafts/ERC777/ERC777.test.js b/test/drafts/ERC777/ERC777.test.js index caa523645b0..5e082418245 100644 --- a/test/drafts/ERC777/ERC777.test.js +++ b/test/drafts/ERC777/ERC777.test.js @@ -134,13 +134,13 @@ contract('ERC777', function ([ const to = anyone; const amount = new BN('5'); - context('with default operator', async function () { + context('with default operator', function () { const operator = defaultOperatorA; shouldBehaveLikeERC777InternalMint(to, operator, amount, data, operatorData); }); - context('with non operator', async function () { + context('with non operator', function () { const operator = newOperator; shouldBehaveLikeERC777InternalMint(to, operator, amount, data, operatorData); @@ -255,7 +255,7 @@ contract('ERC777', function ([ // sender and recipient are stored inside 'this', since in some tests their addresses are determined dynamically describe('tokensReceived', function () { - beforeEach(async function () { + beforeEach(function () { this.sender = holder; }); @@ -280,7 +280,7 @@ contract('ERC777', function ([ it('mint (internal) reverts', async function () { await shouldFail.reverting( - this.token.mintInternal(this.recipient, operator, amount, data, operatorData) + this.token.mintInternal(operator, this.recipient, amount, data, operatorData) ); }); }); @@ -331,7 +331,7 @@ contract('ERC777', function ([ }); describe('tokensToSend', function () { - beforeEach(async function () { + beforeEach(function () { this.recipient = anyone; }); @@ -441,7 +441,7 @@ contract('ERC777', function ([ it('reverts when sending an amount non-multiple of the granularity', async function () { await shouldFail.reverting( - this.token.mintInternal(anyone, defaultOperatorA, granularity.subn(1), data, operatorData) + this.token.mintInternal(defaultOperatorA, anyone, granularity.subn(1), data, operatorData) ); }); }); From 3dd46a0e12f62ce27382ec62ce53521d8cefc3bc Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Mon, 15 Apr 2019 17:53:57 -0300 Subject: [PATCH 63/64] Update test/drafts/ERC777/ERC777.test.js Co-Authored-By: nventuro --- test/drafts/ERC777/ERC777.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/drafts/ERC777/ERC777.test.js b/test/drafts/ERC777/ERC777.test.js index 5e082418245..7cc60991729 100644 --- a/test/drafts/ERC777/ERC777.test.js +++ b/test/drafts/ERC777/ERC777.test.js @@ -439,7 +439,7 @@ contract('ERC777', function ([ shouldInternalMintTokens(anyone, defaultOperatorA, granularity, data, operatorData); shouldInternalMintTokens(anyone, defaultOperatorA, granularity.muln(2), data, operatorData); - it('reverts when sending an amount non-multiple of the granularity', async function () { + it('reverts when minting an amount non-multiple of the granularity', async function () { await shouldFail.reverting( this.token.mintInternal(defaultOperatorA, anyone, granularity.subn(1), data, operatorData) ); From d7be2a6b3c5997160af4d8d185386513cfb32866 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Tue, 16 Apr 2019 13:13:12 -0300 Subject: [PATCH 64/64] Add changelog entry. --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c3fd0f65160..aafd0d6178c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,9 @@ ## 2.3.0 (unreleased) ### New features: - * `ERC1820`: added support for interacting with the [ERC1820](https://eips.ethereum.org/EIPS/eip-1820) registry contract (`IERC1820Registry`), as well as base contracts that can be registered as implementers there. ([#1677](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1677)) + * `ERC1820`: added support for interacting with the [ERC1820](https://eips.ethereum.org/EIPS/eip-1820) registry contract (`IERC1820Registry`), as well as base contracts that can be registered as + implementers there. ([#1677](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1677)) + * `ERC777`: initial support for the [ERC777 token](https://eips.ethereum.org/EIPS/eip-777), which has multiple improvements over `ERC20` such as built-in burning, a more straightforward permission system, and optional sender and receiver hooks on transfer (mandatory for contracts!). ([#1684](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1684)) ## 2.2.0 (2019-03-14)