diff --git a/.solhint.json b/.solhint.json index 7f09dbb5a..09d6d744c 100644 --- a/.solhint.json +++ b/.solhint.json @@ -1,14 +1,9 @@ { "extends": "solhint:recommended", "rules": { - "indent": ["error", 4], "func-order": "off", - "bracket-align": "off", - "compiler-fixed": "off", - "no-simple-event-func-name": "off", - "separate-by-one-line-in-contract": "off", - "two-lines-top-level-separator": "off", "mark-callable-contracts": "off", - "compiler-version": ["error", "^0.5.0"] + "no-empty-blocks": "off", + "compiler-version": ["error", "^0.6.0"] } } diff --git a/contracts/GSN/Context.sol b/contracts/GSN/Context.sol index 107729583..227c9248f 100644 --- a/contracts/GSN/Context.sol +++ b/contracts/GSN/Context.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; /* * @dev Provides information about the current execution context, including the @@ -14,13 +14,12 @@ contract Context { // Empty internal constructor, to prevent people from mistakenly deploying // an instance of this contract, which should be used via inheritance. constructor () internal { } - // solhint-disable-previous-line no-empty-blocks - function _msgSender() internal view returns (address payable) { + function _msgSender() internal view virtual returns (address payable) { return msg.sender; } - function _msgData() internal view returns (bytes memory) { + function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } diff --git a/contracts/GSN/GSNRecipient.sol b/contracts/GSN/GSNRecipient.sol index fb5996e57..cb9f281ea 100644 --- a/contracts/GSN/GSNRecipient.sol +++ b/contracts/GSN/GSNRecipient.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "./IRelayRecipient.sol"; import "./IRelayHub.sol"; @@ -15,7 +15,7 @@ import "./Context.sol"; * information on how to use the pre-built {GSNRecipientSignature} and * {GSNRecipientERC20Fee}, or how to write your own. */ -contract GSNRecipient is IRelayRecipient, Context { +abstract contract GSNRecipient is IRelayRecipient, Context { // Default RelayHub address, deployed on mainnet and all testnets at the same address address private _relayHub = 0xD216153c06E857cD7f72665E0aF1d7D82172F494; @@ -33,7 +33,7 @@ contract GSNRecipient is IRelayRecipient, Context { /** * @dev Returns the address of the {IRelayHub} contract for this recipient. */ - function getHubAddr() public view returns (address) { + function getHubAddr() public view override returns (address) { return _relayHub; } @@ -44,7 +44,7 @@ contract GSNRecipient is IRelayRecipient, Context { * IMPORTANT: After upgrading, the {GSNRecipient} will no longer be able to receive relayed calls from the old * {IRelayHub} instance. Additionally, all funds should be previously withdrawn via {_withdrawDeposits}. */ - function _upgradeRelayHub(address newRelayHub) internal { + function _upgradeRelayHub(address newRelayHub) internal virtual { address currentRelayHub = _relayHub; require(newRelayHub != address(0), "GSNRecipient: new RelayHub is the zero address"); require(newRelayHub != currentRelayHub, "GSNRecipient: new RelayHub is the current one"); @@ -70,7 +70,7 @@ contract GSNRecipient is IRelayRecipient, Context { * * Derived contracts should expose this in an external interface with proper access control. */ - function _withdrawDeposits(uint256 amount, address payable payee) internal { + function _withdrawDeposits(uint256 amount, address payable payee) internal virtual { IRelayHub(_relayHub).withdraw(amount, payee); } @@ -85,7 +85,7 @@ contract GSNRecipient is IRelayRecipient, Context { * * IMPORTANT: Contracts derived from {GSNRecipient} should never use `msg.sender`, and use {_msgSender} instead. */ - function _msgSender() internal view returns (address payable) { + function _msgSender() internal view virtual override returns (address payable) { if (msg.sender != _relayHub) { return msg.sender; } else { @@ -99,7 +99,7 @@ contract GSNRecipient is IRelayRecipient, Context { * * IMPORTANT: Contracts derived from {GSNRecipient} should never use `msg.data`, and use {_msgData} instead. */ - function _msgData() internal view returns (bytes memory) { + function _msgData() internal view virtual override returns (bytes memory) { if (msg.sender != _relayHub) { return msg.data; } else { @@ -119,7 +119,7 @@ contract GSNRecipient is IRelayRecipient, Context { * * - the caller must be the `RelayHub` contract. */ - function preRelayedCall(bytes calldata context) external returns (bytes32) { + function preRelayedCall(bytes calldata context) external virtual override returns (bytes32) { require(msg.sender == getHubAddr(), "GSNRecipient: caller is not RelayHub"); return _preRelayedCall(context); } @@ -131,7 +131,7 @@ contract GSNRecipient is IRelayRecipient, Context { * must implement this function with any relayed-call preprocessing they may wish to do. * */ - function _preRelayedCall(bytes memory context) internal returns (bytes32); + function _preRelayedCall(bytes memory context) internal virtual returns (bytes32); /** * @dev See `IRelayRecipient.postRelayedCall`. @@ -142,7 +142,7 @@ contract GSNRecipient is IRelayRecipient, Context { * * - the caller must be the `RelayHub` contract. */ - function postRelayedCall(bytes calldata context, bool success, uint256 actualCharge, bytes32 preRetVal) external { + function postRelayedCall(bytes calldata context, bool success, uint256 actualCharge, bytes32 preRetVal) external virtual override { require(msg.sender == getHubAddr(), "GSNRecipient: caller is not RelayHub"); _postRelayedCall(context, success, actualCharge, preRetVal); } @@ -154,7 +154,7 @@ contract GSNRecipient is IRelayRecipient, Context { * must implement this function with any relayed-call postprocessing they may wish to do. * */ - function _postRelayedCall(bytes memory context, bool success, uint256 actualCharge, bytes32 preRetVal) internal; + function _postRelayedCall(bytes memory context, bool success, uint256 actualCharge, bytes32 preRetVal) internal virtual; /** * @dev Return this in acceptRelayedCall to proceed with the execution of a relayed call. Note that this contract diff --git a/contracts/GSN/GSNRecipientERC20Fee.sol b/contracts/GSN/GSNRecipientERC20Fee.sol index 8e649029c..b0c624154 100644 --- a/contracts/GSN/GSNRecipientERC20Fee.sol +++ b/contracts/GSN/GSNRecipientERC20Fee.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "./GSNRecipient.sol"; import "../math/SafeMath.sol"; @@ -43,7 +43,7 @@ contract GSNRecipientERC20Fee is GSNRecipient { /** * @dev Internal function that mints the gas payment token. Derived contracts should expose this function in their public API, with proper access control mechanisms. */ - function _mint(address account, uint256 amount) internal { + function _mint(address account, uint256 amount) internal virtual { _token.mint(account, amount); } @@ -63,6 +63,8 @@ contract GSNRecipientERC20Fee is GSNRecipient { ) external view + virtual + override returns (uint256, bytes memory) { if (_token.balanceOf(from) < maxPossibleCharge) { @@ -78,7 +80,7 @@ contract GSNRecipientERC20Fee is GSNRecipient { * actual charge, necessary because we cannot predict how much gas the execution will actually need. The remainder * is returned to the user in {_postRelayedCall}. */ - function _preRelayedCall(bytes memory context) internal returns (bytes32) { + function _preRelayedCall(bytes memory context) internal virtual override returns (bytes32) { (address from, uint256 maxPossibleCharge) = abi.decode(context, (address, uint256)); // The maximum token charge is pre-charged from the user @@ -88,7 +90,7 @@ contract GSNRecipientERC20Fee is GSNRecipient { /** * @dev Returns to the user the extra amount that was previously charged, once the actual execution cost is known. */ - function _postRelayedCall(bytes memory context, bool, uint256 actualCharge, bytes32) internal { + function _postRelayedCall(bytes memory context, bool, uint256 actualCharge, bytes32) internal virtual override { (address from, uint256 maxPossibleCharge, uint256 transactionFee, uint256 gasPrice) = abi.decode(context, (address, uint256, uint256, uint256)); @@ -113,9 +115,7 @@ contract GSNRecipientERC20Fee is GSNRecipient { contract __unstable__ERC20PrimaryAdmin is ERC20, ERC20Detailed, Secondary { uint256 private constant UINT256_MAX = 2**256 - 1; - constructor(string memory name, string memory symbol, uint8 decimals) public ERC20Detailed(name, symbol, decimals) { - // solhint-disable-previous-line no-empty-blocks - } + constructor(string memory name, string memory symbol, uint8 decimals) public ERC20Detailed(name, symbol, decimals) { } // The primary account (GSNRecipientERC20Fee) can mint tokens function mint(address account, uint256 amount) public onlyPrimary { @@ -123,7 +123,7 @@ contract __unstable__ERC20PrimaryAdmin is ERC20, ERC20Detailed, Secondary { } // The primary account has 'infinite' allowance for all token holders - function allowance(address owner, address spender) public view returns (uint256) { + function allowance(address owner, address spender) public view override(ERC20, IERC20) returns (uint256) { if (spender == primary()) { return UINT256_MAX; } else { @@ -132,7 +132,7 @@ contract __unstable__ERC20PrimaryAdmin is ERC20, ERC20Detailed, Secondary { } // Allowance for the primary account cannot be changed (it is always 'infinite') - function _approve(address owner, address spender, uint256 value) internal { + function _approve(address owner, address spender, uint256 value) internal override { if (spender == primary()) { return; } else { @@ -140,7 +140,7 @@ contract __unstable__ERC20PrimaryAdmin is ERC20, ERC20Detailed, Secondary { } } - function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) { + function transferFrom(address sender, address recipient, uint256 amount) public override(ERC20, IERC20) returns (bool) { if (recipient == primary()) { _transfer(sender, recipient, amount); return true; diff --git a/contracts/GSN/GSNRecipientSignature.sol b/contracts/GSN/GSNRecipientSignature.sol index c4c41a00d..055be8175 100644 --- a/contracts/GSN/GSNRecipientSignature.sol +++ b/contracts/GSN/GSNRecipientSignature.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "./GSNRecipient.sol"; import "../cryptography/ECDSA.sol"; @@ -42,6 +42,8 @@ contract GSNRecipientSignature is GSNRecipient { ) external view + virtual + override returns (uint256, bytes memory) { bytes memory blob = abi.encodePacked( @@ -62,11 +64,7 @@ contract GSNRecipientSignature is GSNRecipient { } } - function _preRelayedCall(bytes memory) internal returns (bytes32) { - // solhint-disable-previous-line no-empty-blocks - } + function _preRelayedCall(bytes memory) internal virtual override returns (bytes32) { } - function _postRelayedCall(bytes memory, bool, uint256, bytes32) internal { - // solhint-disable-previous-line no-empty-blocks - } + function _postRelayedCall(bytes memory, bool, uint256, bytes32) internal virtual override { } } diff --git a/contracts/GSN/IRelayHub.sol b/contracts/GSN/IRelayHub.sol index 017415e47..520aa374c 100644 --- a/contracts/GSN/IRelayHub.sol +++ b/contracts/GSN/IRelayHub.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; /** * @dev Interface for `RelayHub`, the core contract of the GSN. Users should not need to interact with this contract @@ -207,7 +207,7 @@ interface IRelayHub { event CanRelayFailed(address indexed relay, address indexed from, address indexed to, bytes4 selector, uint256 reason); /** - * @dev Emitted when a transaction is relayed. + * @dev Emitted when a transaction is relayed. * Useful when monitoring a relay's operation and relayed calls to a contract * * Note that the actual encoded function might be reverted: this is indicated in the `status` parameter. @@ -236,7 +236,7 @@ interface IRelayHub { */ function maxPossibleCharge(uint256 relayedCallStipend, uint256 gasPrice, uint256 transactionFee) external view returns (uint256); - // Relay penalization. + // Relay penalization. // Any account can penalize relays, removing them from the system immediately, and rewarding the // reporter with half of the relay's stake. The other half is burned so that, even if the relay penalizes itself, it // still loses half of its stake. diff --git a/contracts/GSN/IRelayRecipient.sol b/contracts/GSN/IRelayRecipient.sol index 405f9d358..cb5e6513e 100644 --- a/contracts/GSN/IRelayRecipient.sol +++ b/contracts/GSN/IRelayRecipient.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; /** * @dev Base interface for a contract that will be called via the GSN from {IRelayHub}. diff --git a/contracts/access/README.adoc b/contracts/access/README.adoc index 1efb4dec8..ec60be8da 100644 --- a/contracts/access/README.adoc +++ b/contracts/access/README.adoc @@ -5,17 +5,3 @@ NOTE: This page is incomplete. We're working to improve it for the next release. == Library {{Roles}} - -== Roles - -{{CapperRole}} - -{{MinterRole}} - -{{PauserRole}} - -{{SignerRole}} - -{{WhitelistAdminRole}} - -{{WhitelistedRole}} diff --git a/contracts/access/Roles.sol b/contracts/access/Roles.sol index 5f3eff6ae..e31debbe3 100644 --- a/contracts/access/Roles.sol +++ b/contracts/access/Roles.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; /** * @title Roles diff --git a/contracts/access/roles/CapperRole.sol b/contracts/access/roles/CapperRole.sol deleted file mode 100644 index 2b239c1f8..000000000 --- a/contracts/access/roles/CapperRole.sol +++ /dev/null @@ -1,44 +0,0 @@ -pragma solidity ^0.5.0; - -import "../../GSN/Context.sol"; -import "../Roles.sol"; - -contract CapperRole is Context { - using Roles for Roles.Role; - - event CapperAdded(address indexed account); - event CapperRemoved(address indexed account); - - Roles.Role private _cappers; - - constructor () internal { - _addCapper(_msgSender()); - } - - modifier onlyCapper() { - require(isCapper(_msgSender()), "CapperRole: caller does not have the Capper role"); - _; - } - - function isCapper(address account) public view returns (bool) { - return _cappers.has(account); - } - - function addCapper(address account) public onlyCapper { - _addCapper(account); - } - - function renounceCapper() public { - _removeCapper(_msgSender()); - } - - function _addCapper(address account) internal { - _cappers.add(account); - emit CapperAdded(account); - } - - function _removeCapper(address account) internal { - _cappers.remove(account); - emit CapperRemoved(account); - } -} diff --git a/contracts/access/roles/MinterRole.sol b/contracts/access/roles/MinterRole.sol deleted file mode 100644 index f881e3a73..000000000 --- a/contracts/access/roles/MinterRole.sol +++ /dev/null @@ -1,44 +0,0 @@ -pragma solidity ^0.5.0; - -import "../../GSN/Context.sol"; -import "../Roles.sol"; - -contract MinterRole is Context { - using Roles for Roles.Role; - - event MinterAdded(address indexed account); - event MinterRemoved(address indexed account); - - Roles.Role private _minters; - - constructor () internal { - _addMinter(_msgSender()); - } - - modifier onlyMinter() { - require(isMinter(_msgSender()), "MinterRole: caller does not have the Minter role"); - _; - } - - function isMinter(address account) public view returns (bool) { - return _minters.has(account); - } - - function addMinter(address account) public onlyMinter { - _addMinter(account); - } - - function renounceMinter() public { - _removeMinter(_msgSender()); - } - - function _addMinter(address account) internal { - _minters.add(account); - emit MinterAdded(account); - } - - function _removeMinter(address account) internal { - _minters.remove(account); - emit MinterRemoved(account); - } -} diff --git a/contracts/access/roles/PauserRole.sol b/contracts/access/roles/PauserRole.sol deleted file mode 100644 index 6ad238402..000000000 --- a/contracts/access/roles/PauserRole.sol +++ /dev/null @@ -1,44 +0,0 @@ -pragma solidity ^0.5.0; - -import "../../GSN/Context.sol"; -import "../Roles.sol"; - -contract PauserRole is Context { - using Roles for Roles.Role; - - event PauserAdded(address indexed account); - event PauserRemoved(address indexed account); - - Roles.Role private _pausers; - - constructor () internal { - _addPauser(_msgSender()); - } - - modifier onlyPauser() { - require(isPauser(_msgSender()), "PauserRole: caller does not have the Pauser role"); - _; - } - - function isPauser(address account) public view returns (bool) { - return _pausers.has(account); - } - - function addPauser(address account) public onlyPauser { - _addPauser(account); - } - - function renouncePauser() public { - _removePauser(_msgSender()); - } - - function _addPauser(address account) internal { - _pausers.add(account); - emit PauserAdded(account); - } - - function _removePauser(address account) internal { - _pausers.remove(account); - emit PauserRemoved(account); - } -} diff --git a/contracts/access/roles/SignerRole.sol b/contracts/access/roles/SignerRole.sol deleted file mode 100644 index 50535bead..000000000 --- a/contracts/access/roles/SignerRole.sol +++ /dev/null @@ -1,44 +0,0 @@ -pragma solidity ^0.5.0; - -import "../../GSN/Context.sol"; -import "../Roles.sol"; - -contract SignerRole is Context { - using Roles for Roles.Role; - - event SignerAdded(address indexed account); - event SignerRemoved(address indexed account); - - Roles.Role private _signers; - - constructor () internal { - _addSigner(_msgSender()); - } - - modifier onlySigner() { - require(isSigner(_msgSender()), "SignerRole: caller does not have the Signer role"); - _; - } - - function isSigner(address account) public view returns (bool) { - return _signers.has(account); - } - - function addSigner(address account) public onlySigner { - _addSigner(account); - } - - function renounceSigner() public { - _removeSigner(_msgSender()); - } - - function _addSigner(address account) internal { - _signers.add(account); - emit SignerAdded(account); - } - - function _removeSigner(address account) internal { - _signers.remove(account); - emit SignerRemoved(account); - } -} diff --git a/contracts/access/roles/WhitelistAdminRole.sol b/contracts/access/roles/WhitelistAdminRole.sol deleted file mode 100644 index b26f4ed6b..000000000 --- a/contracts/access/roles/WhitelistAdminRole.sol +++ /dev/null @@ -1,48 +0,0 @@ -pragma solidity ^0.5.0; - -import "../../GSN/Context.sol"; -import "../Roles.sol"; - -/** - * @title WhitelistAdminRole - * @dev WhitelistAdmins are responsible for assigning and removing Whitelisted accounts. - */ -contract WhitelistAdminRole is Context { - using Roles for Roles.Role; - - event WhitelistAdminAdded(address indexed account); - event WhitelistAdminRemoved(address indexed account); - - Roles.Role private _whitelistAdmins; - - constructor () internal { - _addWhitelistAdmin(_msgSender()); - } - - modifier onlyWhitelistAdmin() { - require(isWhitelistAdmin(_msgSender()), "WhitelistAdminRole: caller does not have the WhitelistAdmin role"); - _; - } - - function isWhitelistAdmin(address account) public view returns (bool) { - return _whitelistAdmins.has(account); - } - - function addWhitelistAdmin(address account) public onlyWhitelistAdmin { - _addWhitelistAdmin(account); - } - - function renounceWhitelistAdmin() public { - _removeWhitelistAdmin(_msgSender()); - } - - function _addWhitelistAdmin(address account) internal { - _whitelistAdmins.add(account); - emit WhitelistAdminAdded(account); - } - - function _removeWhitelistAdmin(address account) internal { - _whitelistAdmins.remove(account); - emit WhitelistAdminRemoved(account); - } -} diff --git a/contracts/access/roles/WhitelistedRole.sol b/contracts/access/roles/WhitelistedRole.sol deleted file mode 100644 index 5d749bfd3..000000000 --- a/contracts/access/roles/WhitelistedRole.sol +++ /dev/null @@ -1,51 +0,0 @@ -pragma solidity ^0.5.0; - -import "../../GSN/Context.sol"; -import "../Roles.sol"; -import "./WhitelistAdminRole.sol"; - -/** - * @title WhitelistedRole - * @dev Whitelisted accounts have been approved by a WhitelistAdmin to perform certain actions (e.g. participate in a - * crowdsale). This role is special in that the only accounts that can add it are WhitelistAdmins (who can also remove - * it), and not Whitelisteds themselves. - */ -contract WhitelistedRole is Context, WhitelistAdminRole { - using Roles for Roles.Role; - - event WhitelistedAdded(address indexed account); - event WhitelistedRemoved(address indexed account); - - Roles.Role private _whitelisteds; - - modifier onlyWhitelisted() { - require(isWhitelisted(_msgSender()), "WhitelistedRole: caller does not have the Whitelisted role"); - _; - } - - function isWhitelisted(address account) public view returns (bool) { - return _whitelisteds.has(account); - } - - function addWhitelisted(address account) public onlyWhitelistAdmin { - _addWhitelisted(account); - } - - function removeWhitelisted(address account) public onlyWhitelistAdmin { - _removeWhitelisted(account); - } - - function renounceWhitelisted() public { - _removeWhitelisted(_msgSender()); - } - - function _addWhitelisted(address account) internal { - _whitelisteds.add(account); - emit WhitelistedAdded(account); - } - - function _removeWhitelisted(address account) internal { - _whitelisteds.remove(account); - emit WhitelistedRemoved(account); - } -} diff --git a/contracts/crowdsale/Crowdsale.sol b/contracts/crowdsale/Crowdsale.sol deleted file mode 100644 index 5aec96193..000000000 --- a/contracts/crowdsale/Crowdsale.sol +++ /dev/null @@ -1,200 +0,0 @@ -pragma solidity ^0.5.0; - -import "../GSN/Context.sol"; -import "../token/ERC20/IERC20.sol"; -import "../math/SafeMath.sol"; -import "../token/ERC20/SafeERC20.sol"; -import "../utils/ReentrancyGuard.sol"; - -/** - * @title Crowdsale - * @dev Crowdsale is a base contract for managing a token crowdsale, - * allowing investors to purchase tokens with ether. This contract implements - * such functionality in its most fundamental form and can be extended to provide additional - * functionality and/or custom behavior. - * The external interface represents the basic interface for purchasing tokens, and conforms - * the base architecture for crowdsales. It is *not* intended to be modified / overridden. - * The internal interface conforms the extensible and modifiable surface of crowdsales. Override - * the methods to add functionality. Consider using 'super' where appropriate to concatenate - * behavior. - */ -contract Crowdsale is Context, ReentrancyGuard { - using SafeMath for uint256; - using SafeERC20 for IERC20; - - // The token being sold - IERC20 private _token; - - // Address where funds are collected - address payable private _wallet; - - // How many token units a buyer gets per wei. - // The rate is the conversion between wei and the smallest and indivisible token unit. - // So, if you are using a rate of 1 with a ERC20Detailed token with 3 decimals called TOK - // 1 wei will give you 1 unit, or 0.001 TOK. - uint256 private _rate; - - // Amount of wei raised - uint256 private _weiRaised; - - /** - * Event for token purchase logging - * @param purchaser who paid for the tokens - * @param beneficiary who got the tokens - * @param value weis paid for purchase - * @param amount amount of tokens purchased - */ - event TokensPurchased(address indexed purchaser, address indexed beneficiary, uint256 value, uint256 amount); - - /** - * @param rate Number of token units a buyer gets per wei - * @dev The rate is the conversion between wei and the smallest and indivisible - * token unit. So, if you are using a rate of 1 with a ERC20Detailed token - * with 3 decimals called TOK, 1 wei will give you 1 unit, or 0.001 TOK. - * @param wallet Address where collected funds will be forwarded to - * @param token Address of the token being sold - */ - constructor (uint256 rate, address payable wallet, IERC20 token) public { - require(rate > 0, "Crowdsale: rate is 0"); - require(wallet != address(0), "Crowdsale: wallet is the zero address"); - require(address(token) != address(0), "Crowdsale: token is the zero address"); - - _rate = rate; - _wallet = wallet; - _token = token; - } - - /** - * @dev fallback function ***DO NOT OVERRIDE*** - * Note that other contracts will transfer funds with a base gas stipend - * of 2300, which is not enough to call buyTokens. Consider calling - * buyTokens directly when purchasing tokens from a contract. - */ - function () external payable { - buyTokens(_msgSender()); - } - - /** - * @return the token being sold. - */ - function token() public view returns (IERC20) { - return _token; - } - - /** - * @return the address where funds are collected. - */ - function wallet() public view returns (address payable) { - return _wallet; - } - - /** - * @return the number of token units a buyer gets per wei. - */ - function rate() public view returns (uint256) { - return _rate; - } - - /** - * @return the amount of wei raised. - */ - function weiRaised() public view returns (uint256) { - return _weiRaised; - } - - /** - * @dev low level token purchase ***DO NOT OVERRIDE*** - * This function has a non-reentrancy guard, so it shouldn't be called by - * another `nonReentrant` function. - * @param beneficiary Recipient of the token purchase - */ - function buyTokens(address beneficiary) public nonReentrant payable { - uint256 weiAmount = msg.value; - _preValidatePurchase(beneficiary, weiAmount); - - // calculate token amount to be created - uint256 tokens = _getTokenAmount(weiAmount); - - // update state - _weiRaised = _weiRaised.add(weiAmount); - - _processPurchase(beneficiary, tokens); - emit TokensPurchased(_msgSender(), beneficiary, weiAmount, tokens); - - _updatePurchasingState(beneficiary, weiAmount); - - _forwardFunds(); - _postValidatePurchase(beneficiary, weiAmount); - } - - /** - * @dev Validation of an incoming purchase. Use require statements to revert state when conditions are not met. - * Use `super` in contracts that inherit from Crowdsale to extend their validations. - * Example from CappedCrowdsale.sol's _preValidatePurchase method: - * super._preValidatePurchase(beneficiary, weiAmount); - * require(weiRaised().add(weiAmount) <= cap); - * @param beneficiary Address performing the token purchase - * @param weiAmount Value in wei involved in the purchase - */ - function _preValidatePurchase(address beneficiary, uint256 weiAmount) internal view { - require(beneficiary != address(0), "Crowdsale: beneficiary is the zero address"); - require(weiAmount != 0, "Crowdsale: weiAmount is 0"); - this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 - } - - /** - * @dev Validation of an executed purchase. Observe state and use revert statements to undo rollback when valid - * conditions are not met. - * @param beneficiary Address performing the token purchase - * @param weiAmount Value in wei involved in the purchase - */ - function _postValidatePurchase(address beneficiary, uint256 weiAmount) internal view { - // solhint-disable-previous-line no-empty-blocks - } - - /** - * @dev Source of tokens. Override this method to modify the way in which the crowdsale ultimately gets and sends - * its tokens. - * @param beneficiary Address performing the token purchase - * @param tokenAmount Number of tokens to be emitted - */ - function _deliverTokens(address beneficiary, uint256 tokenAmount) internal { - _token.safeTransfer(beneficiary, tokenAmount); - } - - /** - * @dev Executed when a purchase has been validated and is ready to be executed. Doesn't necessarily emit/send - * tokens. - * @param beneficiary Address receiving the tokens - * @param tokenAmount Number of tokens to be purchased - */ - function _processPurchase(address beneficiary, uint256 tokenAmount) internal { - _deliverTokens(beneficiary, tokenAmount); - } - - /** - * @dev Override for extensions that require an internal state to check for validity (current user contributions, - * etc.) - * @param beneficiary Address receiving the tokens - * @param weiAmount Value in wei involved in the purchase - */ - function _updatePurchasingState(address beneficiary, uint256 weiAmount) internal { - // solhint-disable-previous-line no-empty-blocks - } - - /** - * @dev Override to extend the way in which ether is converted to tokens. - * @param weiAmount Value in wei to be converted into tokens - * @return Number of tokens that can be purchased with the specified _weiAmount - */ - function _getTokenAmount(uint256 weiAmount) internal view returns (uint256) { - return weiAmount.mul(_rate); - } - - /** - * @dev Determines how ETH is stored/forwarded on purchases. - */ - function _forwardFunds() internal { - _wallet.transfer(msg.value); - } -} diff --git a/contracts/crowdsale/README.adoc b/contracts/crowdsale/README.adoc deleted file mode 100644 index 3f64f9b33..000000000 --- a/contracts/crowdsale/README.adoc +++ /dev/null @@ -1,35 +0,0 @@ -= Crowdsales - -NOTE: This page is incomplete. We're working to improve it for the next release. Stay tuned! - -== Core - -{{Crowdsale}} - -== Emission - -{{AllowanceCrowdsale}} - -{{MintedCrowdsale}} - -== Validation - -{{CappedCrowdsale}} - -{{IndividuallyCappedCrowdsale}} - -{{PausableCrowdsale}} - -{{TimedCrowdsale}} - -{{WhitelistCrowdsale}} - -== Distribution - -{{FinalizableCrowdsale}} - -{{PostDeliveryCrowdsale}} - -{{RefundableCrowdsale}} - -{{RefundablePostDeliveryCrowdsale}} diff --git a/contracts/crowdsale/distribution/FinalizableCrowdsale.sol b/contracts/crowdsale/distribution/FinalizableCrowdsale.sol deleted file mode 100644 index 9c42e6146..000000000 --- a/contracts/crowdsale/distribution/FinalizableCrowdsale.sol +++ /dev/null @@ -1,51 +0,0 @@ -pragma solidity ^0.5.0; - -import "../../math/SafeMath.sol"; -import "../validation/TimedCrowdsale.sol"; - -/** - * @title FinalizableCrowdsale - * @dev Extension of TimedCrowdsale with a one-off finalization action, where one - * can do extra work after finishing. - */ -contract FinalizableCrowdsale is TimedCrowdsale { - using SafeMath for uint256; - - bool private _finalized; - - event CrowdsaleFinalized(); - - constructor () internal { - _finalized = false; - } - - /** - * @return true if the crowdsale is finalized, false otherwise. - */ - function finalized() public view returns (bool) { - return _finalized; - } - - /** - * @dev Must be called after crowdsale ends, to do some extra finalization - * work. Calls the contract's finalization function. - */ - function finalize() public { - require(!_finalized, "FinalizableCrowdsale: already finalized"); - require(hasClosed(), "FinalizableCrowdsale: not closed"); - - _finalized = true; - - _finalization(); - emit CrowdsaleFinalized(); - } - - /** - * @dev Can be overridden to add finalization logic. The overriding function - * should call super._finalization() to ensure the chain of finalization is - * executed entirely. - */ - function _finalization() internal { - // solhint-disable-previous-line no-empty-blocks - } -} diff --git a/contracts/crowdsale/distribution/PostDeliveryCrowdsale.sol b/contracts/crowdsale/distribution/PostDeliveryCrowdsale.sol deleted file mode 100644 index 41b9059b7..000000000 --- a/contracts/crowdsale/distribution/PostDeliveryCrowdsale.sol +++ /dev/null @@ -1,65 +0,0 @@ -pragma solidity ^0.5.0; - -import "../validation/TimedCrowdsale.sol"; -import "../../math/SafeMath.sol"; -import "../../ownership/Secondary.sol"; -import "../../token/ERC20/IERC20.sol"; - -/** - * @title PostDeliveryCrowdsale - * @dev Crowdsale that locks tokens from withdrawal until it ends. - */ -contract PostDeliveryCrowdsale is TimedCrowdsale { - using SafeMath for uint256; - - mapping(address => uint256) private _balances; - __unstable__TokenVault private _vault; - - constructor() public { - _vault = new __unstable__TokenVault(); - } - - /** - * @dev Withdraw tokens only after crowdsale ends. - * @param beneficiary Whose tokens will be withdrawn. - */ - function withdrawTokens(address beneficiary) public { - require(hasClosed(), "PostDeliveryCrowdsale: not closed"); - uint256 amount = _balances[beneficiary]; - require(amount > 0, "PostDeliveryCrowdsale: beneficiary is not due any tokens"); - - _balances[beneficiary] = 0; - _vault.transfer(token(), beneficiary, amount); - } - - /** - * @return the balance of an account. - */ - function balanceOf(address account) public view returns (uint256) { - return _balances[account]; - } - - /** - * @dev Overrides parent by storing due balances, and delivering tokens to the vault instead of the end user. This - * ensures that the tokens will be available by the time they are withdrawn (which may not be the case if - * `_deliverTokens` was called later). - * @param beneficiary Token purchaser - * @param tokenAmount Amount of tokens purchased - */ - function _processPurchase(address beneficiary, uint256 tokenAmount) internal { - _balances[beneficiary] = _balances[beneficiary].add(tokenAmount); - _deliverTokens(address(_vault), tokenAmount); - } -} - -/** - * @title __unstable__TokenVault - * @dev Similar to an Escrow for tokens, this contract allows its primary account to spend its tokens as it sees fit. - * This contract is an internal helper for PostDeliveryCrowdsale, and should not be used outside of this context. - */ -// solhint-disable-next-line contract-name-camelcase -contract __unstable__TokenVault is Secondary { - function transfer(IERC20 token, address to, uint256 amount) public onlyPrimary { - token.transfer(to, amount); - } -} diff --git a/contracts/crowdsale/distribution/RefundableCrowdsale.sol b/contracts/crowdsale/distribution/RefundableCrowdsale.sol deleted file mode 100644 index 9c42606fe..000000000 --- a/contracts/crowdsale/distribution/RefundableCrowdsale.sol +++ /dev/null @@ -1,83 +0,0 @@ -pragma solidity ^0.5.0; - -import "../../GSN/Context.sol"; -import "../../math/SafeMath.sol"; -import "./FinalizableCrowdsale.sol"; -import "../../payment/escrow/RefundEscrow.sol"; - -/** - * @title RefundableCrowdsale - * @dev Extension of `FinalizableCrowdsale` contract that adds a funding goal, and the possibility of users - * getting a refund if goal is not met. - * - * Deprecated, use `RefundablePostDeliveryCrowdsale` instead. Note that if you allow tokens to be traded before the goal - * is met, then an attack is possible in which the attacker purchases tokens from the crowdsale and when they sees that - * the goal is unlikely to be met, they sell their tokens (possibly at a discount). The attacker will be refunded when - * the crowdsale is finalized, and the users that purchased from them will be left with worthless tokens. - */ -contract RefundableCrowdsale is Context, FinalizableCrowdsale { - using SafeMath for uint256; - - // minimum amount of funds to be raised in weis - uint256 private _goal; - - // refund escrow used to hold funds while crowdsale is running - RefundEscrow private _escrow; - - /** - * @dev Constructor, creates RefundEscrow. - * @param goal Funding goal - */ - constructor (uint256 goal) public { - require(goal > 0, "RefundableCrowdsale: goal is 0"); - _escrow = new RefundEscrow(wallet()); - _goal = goal; - } - - /** - * @return minimum amount of funds to be raised in wei. - */ - function goal() public view returns (uint256) { - return _goal; - } - - /** - * @dev Investors can claim refunds here if crowdsale is unsuccessful. - * @param refundee Whose refund will be claimed. - */ - function claimRefund(address payable refundee) public { - require(finalized(), "RefundableCrowdsale: not finalized"); - require(!goalReached(), "RefundableCrowdsale: goal reached"); - - _escrow.withdraw(refundee); - } - - /** - * @dev Checks whether funding goal was reached. - * @return Whether funding goal was reached - */ - function goalReached() public view returns (bool) { - return weiRaised() >= _goal; - } - - /** - * @dev Escrow finalization task, called when finalize() is called. - */ - function _finalization() internal { - if (goalReached()) { - _escrow.close(); - _escrow.beneficiaryWithdraw(); - } else { - _escrow.enableRefunds(); - } - - super._finalization(); - } - - /** - * @dev Overrides Crowdsale fund forwarding, sending funds to escrow. - */ - function _forwardFunds() internal { - _escrow.deposit.value(msg.value)(_msgSender()); - } -} diff --git a/contracts/crowdsale/distribution/RefundablePostDeliveryCrowdsale.sol b/contracts/crowdsale/distribution/RefundablePostDeliveryCrowdsale.sol deleted file mode 100644 index 385aa195c..000000000 --- a/contracts/crowdsale/distribution/RefundablePostDeliveryCrowdsale.sol +++ /dev/null @@ -1,20 +0,0 @@ -pragma solidity ^0.5.0; - -import "./RefundableCrowdsale.sol"; -import "./PostDeliveryCrowdsale.sol"; - - -/** - * @title RefundablePostDeliveryCrowdsale - * @dev Extension of RefundableCrowdsale contract that only delivers the tokens - * once the crowdsale has closed and the goal met, preventing refunds to be issued - * to token holders. - */ -contract RefundablePostDeliveryCrowdsale is RefundableCrowdsale, PostDeliveryCrowdsale { - function withdrawTokens(address beneficiary) public { - require(finalized(), "RefundablePostDeliveryCrowdsale: not finalized"); - require(goalReached(), "RefundablePostDeliveryCrowdsale: goal not reached"); - - super.withdrawTokens(beneficiary); - } -} diff --git a/contracts/crowdsale/emission/AllowanceCrowdsale.sol b/contracts/crowdsale/emission/AllowanceCrowdsale.sol deleted file mode 100644 index beee692a6..000000000 --- a/contracts/crowdsale/emission/AllowanceCrowdsale.sol +++ /dev/null @@ -1,51 +0,0 @@ -pragma solidity ^0.5.0; - -import "../Crowdsale.sol"; -import "../../token/ERC20/IERC20.sol"; -import "../../token/ERC20/SafeERC20.sol"; -import "../../math/SafeMath.sol"; -import "../../math/Math.sol"; - -/** - * @title AllowanceCrowdsale - * @dev Extension of Crowdsale where tokens are held by a wallet, which approves an allowance to the crowdsale. - */ -contract AllowanceCrowdsale is Crowdsale { - using SafeMath for uint256; - using SafeERC20 for IERC20; - - address private _tokenWallet; - - /** - * @dev Constructor, takes token wallet address. - * @param tokenWallet Address holding the tokens, which has approved allowance to the crowdsale. - */ - constructor (address tokenWallet) public { - require(tokenWallet != address(0), "AllowanceCrowdsale: token wallet is the zero address"); - _tokenWallet = tokenWallet; - } - - /** - * @return the address of the wallet that will hold the tokens. - */ - function tokenWallet() public view returns (address) { - return _tokenWallet; - } - - /** - * @dev Checks the amount of tokens left in the allowance. - * @return Amount of tokens left in the allowance - */ - function remainingTokens() public view returns (uint256) { - return Math.min(token().balanceOf(_tokenWallet), token().allowance(_tokenWallet, address(this))); - } - - /** - * @dev Overrides parent behavior by transferring tokens from wallet. - * @param beneficiary Token purchaser - * @param tokenAmount Amount of tokens purchased - */ - function _deliverTokens(address beneficiary, uint256 tokenAmount) internal { - token().safeTransferFrom(_tokenWallet, beneficiary, tokenAmount); - } -} diff --git a/contracts/crowdsale/emission/MintedCrowdsale.sol b/contracts/crowdsale/emission/MintedCrowdsale.sol deleted file mode 100644 index 7815b8cac..000000000 --- a/contracts/crowdsale/emission/MintedCrowdsale.sol +++ /dev/null @@ -1,24 +0,0 @@ -pragma solidity ^0.5.0; - -import "../Crowdsale.sol"; -import "../../token/ERC20/ERC20Mintable.sol"; - -/** - * @title MintedCrowdsale - * @dev Extension of Crowdsale contract whose tokens are minted in each purchase. - * Token ownership should be transferred to MintedCrowdsale for minting. - */ -contract MintedCrowdsale is Crowdsale { - /** - * @dev Overrides delivery by minting tokens upon purchase. - * @param beneficiary Token purchaser - * @param tokenAmount Number of tokens to be minted - */ - function _deliverTokens(address beneficiary, uint256 tokenAmount) internal { - // Potentially dangerous assumption about the type of the token. - require( - ERC20Mintable(address(token())).mint(beneficiary, tokenAmount), - "MintedCrowdsale: minting failed" - ); - } -} diff --git a/contracts/crowdsale/price/IncreasingPriceCrowdsale.sol b/contracts/crowdsale/price/IncreasingPriceCrowdsale.sol deleted file mode 100644 index 964514ba2..000000000 --- a/contracts/crowdsale/price/IncreasingPriceCrowdsale.sol +++ /dev/null @@ -1,79 +0,0 @@ -pragma solidity ^0.5.0; - -import "../validation/TimedCrowdsale.sol"; -import "../../math/SafeMath.sol"; - -/** - * @title IncreasingPriceCrowdsale - * @dev Extension of Crowdsale contract that increases the price of tokens linearly in time. - * Note that what should be provided to the constructor is the initial and final _rates_, that is, - * the amount of tokens per wei contributed. Thus, the initial rate must be greater than the final rate. - */ -contract IncreasingPriceCrowdsale is TimedCrowdsale { - using SafeMath for uint256; - - uint256 private _initialRate; - uint256 private _finalRate; - - /** - * @dev Constructor, takes initial and final rates of tokens received per wei contributed. - * @param initialRate Number of tokens a buyer gets per wei at the start of the crowdsale - * @param finalRate Number of tokens a buyer gets per wei at the end of the crowdsale - */ - constructor (uint256 initialRate, uint256 finalRate) public { - require(finalRate > 0, "IncreasingPriceCrowdsale: final rate is 0"); - // solhint-disable-next-line max-line-length - require(initialRate > finalRate, "IncreasingPriceCrowdsale: initial rate is not greater than final rate"); - _initialRate = initialRate; - _finalRate = finalRate; - } - - /** - * The base rate function is overridden to revert, since this crowdsale doesn't use it, and - * all calls to it are a mistake. - */ - function rate() public view returns (uint256) { - revert("IncreasingPriceCrowdsale: rate() called"); - } - - /** - * @return the initial rate of the crowdsale. - */ - function initialRate() public view returns (uint256) { - return _initialRate; - } - - /** - * @return the final rate of the crowdsale. - */ - function finalRate() public view returns (uint256) { - return _finalRate; - } - - /** - * @dev Returns the rate of tokens per wei at the present time. - * Note that, as price _increases_ with time, the rate _decreases_. - * @return The number of tokens a buyer gets per wei at a given time - */ - function getCurrentRate() public view returns (uint256) { - if (!isOpen()) { - return 0; - } - - // solhint-disable-next-line not-rely-on-time - uint256 elapsedTime = block.timestamp.sub(openingTime()); - uint256 timeRange = closingTime().sub(openingTime()); - uint256 rateRange = _initialRate.sub(_finalRate); - return _initialRate.sub(elapsedTime.mul(rateRange).div(timeRange)); - } - - /** - * @dev Overrides parent method taking into account variable rate. - * @param weiAmount The value in wei to be converted into tokens - * @return The number of tokens _weiAmount wei will buy at present time - */ - function _getTokenAmount(uint256 weiAmount) internal view returns (uint256) { - uint256 currentRate = getCurrentRate(); - return currentRate.mul(weiAmount); - } -} diff --git a/contracts/crowdsale/validation/CappedCrowdsale.sol b/contracts/crowdsale/validation/CappedCrowdsale.sol deleted file mode 100644 index e8aeede14..000000000 --- a/contracts/crowdsale/validation/CappedCrowdsale.sol +++ /dev/null @@ -1,48 +0,0 @@ -pragma solidity ^0.5.0; - -import "../../math/SafeMath.sol"; -import "../Crowdsale.sol"; - -/** - * @title CappedCrowdsale - * @dev Crowdsale with a limit for total contributions. - */ -contract CappedCrowdsale is Crowdsale { - using SafeMath for uint256; - - uint256 private _cap; - - /** - * @dev Constructor, takes maximum amount of wei accepted in the crowdsale. - * @param cap Max amount of wei to be contributed - */ - constructor (uint256 cap) public { - require(cap > 0, "CappedCrowdsale: cap is 0"); - _cap = cap; - } - - /** - * @return the cap of the crowdsale. - */ - function cap() public view returns (uint256) { - return _cap; - } - - /** - * @dev Checks whether the cap has been reached. - * @return Whether the cap was reached - */ - function capReached() public view returns (bool) { - return weiRaised() >= _cap; - } - - /** - * @dev Extend parent behavior requiring purchase to respect the funding cap. - * @param beneficiary Token purchaser - * @param weiAmount Amount of wei contributed - */ - function _preValidatePurchase(address beneficiary, uint256 weiAmount) internal view { - super._preValidatePurchase(beneficiary, weiAmount); - require(weiRaised().add(weiAmount) <= _cap, "CappedCrowdsale: cap exceeded"); - } -} diff --git a/contracts/crowdsale/validation/IndividuallyCappedCrowdsale.sol b/contracts/crowdsale/validation/IndividuallyCappedCrowdsale.sol deleted file mode 100644 index 1f9df361d..000000000 --- a/contracts/crowdsale/validation/IndividuallyCappedCrowdsale.sol +++ /dev/null @@ -1,64 +0,0 @@ -pragma solidity ^0.5.0; - -import "../../math/SafeMath.sol"; -import "../Crowdsale.sol"; -import "../../access/roles/CapperRole.sol"; - -/** - * @title IndividuallyCappedCrowdsale - * @dev Crowdsale with per-beneficiary caps. - */ -contract IndividuallyCappedCrowdsale is Crowdsale, CapperRole { - using SafeMath for uint256; - - mapping(address => uint256) private _contributions; - mapping(address => uint256) private _caps; - - /** - * @dev Sets a specific beneficiary's maximum contribution. - * @param beneficiary Address to be capped - * @param cap Wei limit for individual contribution - */ - function setCap(address beneficiary, uint256 cap) external onlyCapper { - _caps[beneficiary] = cap; - } - - /** - * @dev Returns the cap of a specific beneficiary. - * @param beneficiary Address whose cap is to be checked - * @return Current cap for individual beneficiary - */ - function getCap(address beneficiary) public view returns (uint256) { - return _caps[beneficiary]; - } - - /** - * @dev Returns the amount contributed so far by a specific beneficiary. - * @param beneficiary Address of contributor - * @return Beneficiary contribution so far - */ - function getContribution(address beneficiary) public view returns (uint256) { - return _contributions[beneficiary]; - } - - /** - * @dev Extend parent behavior requiring purchase to respect the beneficiary's funding cap. - * @param beneficiary Token purchaser - * @param weiAmount Amount of wei contributed - */ - function _preValidatePurchase(address beneficiary, uint256 weiAmount) internal view { - super._preValidatePurchase(beneficiary, weiAmount); - // solhint-disable-next-line max-line-length - require(_contributions[beneficiary].add(weiAmount) <= _caps[beneficiary], "IndividuallyCappedCrowdsale: beneficiary's cap exceeded"); - } - - /** - * @dev Extend parent behavior to update beneficiary contributions. - * @param beneficiary Token purchaser - * @param weiAmount Amount of wei contributed - */ - function _updatePurchasingState(address beneficiary, uint256 weiAmount) internal { - super._updatePurchasingState(beneficiary, weiAmount); - _contributions[beneficiary] = _contributions[beneficiary].add(weiAmount); - } -} diff --git a/contracts/crowdsale/validation/PausableCrowdsale.sol b/contracts/crowdsale/validation/PausableCrowdsale.sol deleted file mode 100644 index cc89aebab..000000000 --- a/contracts/crowdsale/validation/PausableCrowdsale.sol +++ /dev/null @@ -1,21 +0,0 @@ -pragma solidity ^0.5.0; - -import "../Crowdsale.sol"; -import "../../lifecycle/Pausable.sol"; - -/** - * @title PausableCrowdsale - * @dev Extension of Crowdsale contract where purchases can be paused and unpaused by the pauser role. - */ -contract PausableCrowdsale is Crowdsale, Pausable { - /** - * @dev Validation of an incoming purchase. Use require statements to revert state when conditions are not met. - * Use super to concatenate validations. - * Adds the validation that the crowdsale must not be paused. - * @param _beneficiary Address performing the token purchase - * @param _weiAmount Value in wei involved in the purchase - */ - function _preValidatePurchase(address _beneficiary, uint256 _weiAmount) internal view whenNotPaused { - return super._preValidatePurchase(_beneficiary, _weiAmount); - } -} diff --git a/contracts/crowdsale/validation/TimedCrowdsale.sol b/contracts/crowdsale/validation/TimedCrowdsale.sol deleted file mode 100644 index 255a63f34..000000000 --- a/contracts/crowdsale/validation/TimedCrowdsale.sol +++ /dev/null @@ -1,98 +0,0 @@ -pragma solidity ^0.5.0; - -import "../../math/SafeMath.sol"; -import "../Crowdsale.sol"; - -/** - * @title TimedCrowdsale - * @dev Crowdsale accepting contributions only within a time frame. - */ -contract TimedCrowdsale is Crowdsale { - using SafeMath for uint256; - - uint256 private _openingTime; - uint256 private _closingTime; - - /** - * Event for crowdsale extending - * @param newClosingTime new closing time - * @param prevClosingTime old closing time - */ - event TimedCrowdsaleExtended(uint256 prevClosingTime, uint256 newClosingTime); - - /** - * @dev Reverts if not in crowdsale time range. - */ - modifier onlyWhileOpen { - require(isOpen(), "TimedCrowdsale: not open"); - _; - } - - /** - * @dev Constructor, takes crowdsale opening and closing times. - * @param openingTime Crowdsale opening time - * @param closingTime Crowdsale closing time - */ - constructor (uint256 openingTime, uint256 closingTime) public { - // solhint-disable-next-line not-rely-on-time - require(openingTime >= block.timestamp, "TimedCrowdsale: opening time is before current time"); - // solhint-disable-next-line max-line-length - require(closingTime > openingTime, "TimedCrowdsale: opening time is not before closing time"); - - _openingTime = openingTime; - _closingTime = closingTime; - } - - /** - * @return the crowdsale opening time. - */ - function openingTime() public view returns (uint256) { - return _openingTime; - } - - /** - * @return the crowdsale closing time. - */ - function closingTime() public view returns (uint256) { - return _closingTime; - } - - /** - * @return true if the crowdsale is open, false otherwise. - */ - function isOpen() public view returns (bool) { - // solhint-disable-next-line not-rely-on-time - return block.timestamp >= _openingTime && block.timestamp <= _closingTime; - } - - /** - * @dev Checks whether the period in which the crowdsale is open has already elapsed. - * @return Whether crowdsale period has elapsed - */ - function hasClosed() public view returns (bool) { - // solhint-disable-next-line not-rely-on-time - return block.timestamp > _closingTime; - } - - /** - * @dev Extend parent behavior requiring to be within contributing period. - * @param beneficiary Token purchaser - * @param weiAmount Amount of wei contributed - */ - function _preValidatePurchase(address beneficiary, uint256 weiAmount) internal onlyWhileOpen view { - super._preValidatePurchase(beneficiary, weiAmount); - } - - /** - * @dev Extend crowdsale. - * @param newClosingTime Crowdsale closing time - */ - function _extendTime(uint256 newClosingTime) internal { - require(!hasClosed(), "TimedCrowdsale: already closed"); - // solhint-disable-next-line max-line-length - require(newClosingTime > _closingTime, "TimedCrowdsale: new closing time is before current closing time"); - - emit TimedCrowdsaleExtended(_closingTime, newClosingTime); - _closingTime = newClosingTime; - } -} diff --git a/contracts/crowdsale/validation/WhitelistCrowdsale.sol b/contracts/crowdsale/validation/WhitelistCrowdsale.sol deleted file mode 100644 index 0f5965352..000000000 --- a/contracts/crowdsale/validation/WhitelistCrowdsale.sol +++ /dev/null @@ -1,21 +0,0 @@ -pragma solidity ^0.5.0; -import "../Crowdsale.sol"; -import "../../access/roles/WhitelistedRole.sol"; - - -/** - * @title WhitelistCrowdsale - * @dev Crowdsale in which only whitelisted users can contribute. - */ -contract WhitelistCrowdsale is WhitelistedRole, Crowdsale { - /** - * @dev Extend parent behavior requiring beneficiary to be whitelisted. Note that no - * restriction is imposed on the account sending the transaction. - * @param _beneficiary Token beneficiary - * @param _weiAmount Amount of wei contributed - */ - function _preValidatePurchase(address _beneficiary, uint256 _weiAmount) internal view { - require(isWhitelisted(_beneficiary), "WhitelistCrowdsale: beneficiary doesn't have the Whitelisted role"); - super._preValidatePurchase(_beneficiary, _weiAmount); - } -} diff --git a/contracts/cryptography/ECDSA.sol b/contracts/cryptography/ECDSA.sol index d85ce09de..4651cb421 100644 --- a/contracts/cryptography/ECDSA.sol +++ b/contracts/cryptography/ECDSA.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. diff --git a/contracts/cryptography/MerkleProof.sol b/contracts/cryptography/MerkleProof.sol index c84805905..2efdd968d 100644 --- a/contracts/cryptography/MerkleProof.sol +++ b/contracts/cryptography/MerkleProof.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; /** * @dev These functions deal with verification of Merkle trees (hash trees), diff --git a/contracts/drafts/Counters.sol b/contracts/drafts/Counters.sol index 15ecb775f..f4e791754 100644 --- a/contracts/drafts/Counters.sol +++ b/contracts/drafts/Counters.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../math/SafeMath.sol"; diff --git a/contracts/drafts/ERC1046/ERC20Metadata.sol b/contracts/drafts/ERC1046/ERC20Metadata.sol index 2311de1c5..1a768cfc1 100644 --- a/contracts/drafts/ERC1046/ERC20Metadata.sol +++ b/contracts/drafts/ERC1046/ERC20Metadata.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../../token/ERC20/IERC20.sol"; @@ -18,7 +18,7 @@ contract ERC20Metadata { return _tokenURI; } - function _setTokenURI(string memory tokenURI_) internal { + function _setTokenURI(string memory tokenURI_) internal virtual { _tokenURI = tokenURI_; } } diff --git a/contracts/drafts/ERC20Migrator.sol b/contracts/drafts/ERC20Migrator.sol deleted file mode 100644 index 44ab6e7fe..000000000 --- a/contracts/drafts/ERC20Migrator.sol +++ /dev/null @@ -1,103 +0,0 @@ -pragma solidity ^0.5.0; - -import "../token/ERC20/IERC20.sol"; -import "../token/ERC20/ERC20Mintable.sol"; -import "../token/ERC20/SafeERC20.sol"; -import "../math/Math.sol"; - -/** - * @title ERC20Migrator - * @dev This contract can be used to migrate an ERC20 token from one - * contract to another, where each token holder has to opt-in to the migration. - * To opt-in, users must approve for this contract the number of tokens they - * want to migrate. Once the allowance is set up, anyone can trigger the - * migration to the new token contract. In this way, token holders "turn in" - * their old balance and will be minted an equal amount in the new token. - * The new token contract must be mintable. For the precise interface refer to - * OpenZeppelin's {ERC20Mintable}, but the only functions that are needed are - * {MinterRole-isMinter} and {ERC20Mintable-mint}. The migrator will check - * that it is a minter for the token. - * The balance from the legacy token will be transferred to the migrator, as it - * is migrated, and remain there forever. - * Although this contract can be used in many different scenarios, the main - * motivation was to provide a way to migrate ERC20 tokens into an upgradeable - * version of it using ZeppelinOS. To read more about how this can be done - * using this implementation, please follow the official documentation site of - * ZeppelinOS: https://docs.zeppelinos.org/docs/erc20_onboarding.html - * - * Example of usage: - * ``` - * const migrator = await ERC20Migrator.new(legacyToken.address); - * await newToken.addMinter(migrator.address); - * await migrator.beginMigration(newToken.address); - * ``` - */ -contract ERC20Migrator { - using SafeERC20 for IERC20; - - /// Address of the old token contract - IERC20 private _legacyToken; - - /// Address of the new token contract - ERC20Mintable private _newToken; - - /** - * @param legacyToken address of the old token contract - */ - constructor (IERC20 legacyToken) public { - require(address(legacyToken) != address(0), "ERC20Migrator: legacy token is the zero address"); - _legacyToken = legacyToken; - } - - /** - * @dev Returns the legacy token that is being migrated. - */ - function legacyToken() public view returns (IERC20) { - return _legacyToken; - } - - /** - * @dev Returns the new token to which we are migrating. - */ - function newToken() public view returns (IERC20) { - return _newToken; - } - - /** - * @dev Begins the migration by setting which is the new token that will be - * minted. This contract must be a minter for the new token. - * @param newToken_ the token that will be minted - */ - function beginMigration(ERC20Mintable newToken_) public { - require(address(_newToken) == address(0), "ERC20Migrator: migration already started"); - require(address(newToken_) != address(0), "ERC20Migrator: new token is the zero address"); - //solhint-disable-next-line max-line-length - require(newToken_.isMinter(address(this)), "ERC20Migrator: not a minter for new token"); - - _newToken = newToken_; - } - - /** - * @dev Transfers part of an account's balance in the old token to this - * contract, and mints the same amount of new tokens for that account. - * @param account whose tokens will be migrated - * @param amount amount of tokens to be migrated - */ - function migrate(address account, uint256 amount) public { - require(address(_newToken) != address(0), "ERC20Migrator: migration not started"); - _legacyToken.safeTransferFrom(account, address(this), amount); - _newToken.mint(account, amount); - } - - /** - * @dev Transfers all of an account's allowed balance in the old token to - * this contract, and mints the same amount of new tokens for that account. - * @param account whose tokens will be migrated - */ - function migrateAll(address account) public { - uint256 balance = _legacyToken.balanceOf(account); - uint256 allowance = _legacyToken.allowance(account, address(this)); - uint256 amount = Math.min(balance, allowance); - migrate(account, amount); - } -} diff --git a/contracts/drafts/ERC20Snapshot.sol b/contracts/drafts/ERC20Snapshot.sol index d1f42ec39..9e2b1558a 100644 --- a/contracts/drafts/ERC20Snapshot.sol +++ b/contracts/drafts/ERC20Snapshot.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../math/SafeMath.sol"; import "../utils/Arrays.sol"; @@ -43,7 +43,7 @@ contract ERC20Snapshot is ERC20 { // Creates a new snapshot id. Balances are only stored in snapshots on demand: unless a snapshot was taken, a // balance change will not be recorded. This means the extra added cost of storing snapshotted balances is only paid // when required, but is also flexible enough that it allows for e.g. daily snapshots. - function snapshot() public returns (uint256) { + function snapshot() public virtual returns (uint256) { _currentSnapshotId.increment(); uint256 currentId = _currentSnapshotId.current(); @@ -66,21 +66,21 @@ contract ERC20Snapshot is ERC20 { // _transfer, _mint and _burn are the only functions where the balances are modified, so it is there that the // snapshots are updated. Note that the update happens _before_ the balance change, with the pre-modified value. // The same is true for the total supply and _mint and _burn. - function _transfer(address from, address to, uint256 value) internal { + function _transfer(address from, address to, uint256 value) internal virtual override { _updateAccountSnapshot(from); _updateAccountSnapshot(to); super._transfer(from, to, value); } - function _mint(address account, uint256 value) internal { + function _mint(address account, uint256 value) internal virtual override { _updateAccountSnapshot(account); _updateTotalSupplySnapshot(); super._mint(account, value); } - function _burn(address account, uint256 value) internal { + function _burn(address account, uint256 value) internal virtual override { _updateAccountSnapshot(account); _updateTotalSupplySnapshot(); diff --git a/contracts/drafts/SignedSafeMath.sol b/contracts/drafts/SignedSafeMath.sol index 161d21bc8..a9af41163 100644 --- a/contracts/drafts/SignedSafeMath.sol +++ b/contracts/drafts/SignedSafeMath.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; /** * @title SignedSafeMath diff --git a/contracts/drafts/Strings.sol b/contracts/drafts/Strings.sol index d5fcbf651..a441eaa60 100644 --- a/contracts/drafts/Strings.sol +++ b/contracts/drafts/Strings.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; /** * @title Strings diff --git a/contracts/drafts/TokenVesting.sol b/contracts/drafts/TokenVesting.sol index 626db459d..8981ef9f6 100644 --- a/contracts/drafts/TokenVesting.sol +++ b/contracts/drafts/TokenVesting.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../token/ERC20/SafeERC20.sol"; import "../ownership/Ownable.sol"; diff --git a/contracts/examples/SampleCrowdsale.sol b/contracts/examples/SampleCrowdsale.sol deleted file mode 100644 index fefed16fc..000000000 --- a/contracts/examples/SampleCrowdsale.sol +++ /dev/null @@ -1,53 +0,0 @@ -pragma solidity ^0.5.0; - -import "../crowdsale/validation/CappedCrowdsale.sol"; -import "../crowdsale/distribution/RefundableCrowdsale.sol"; -import "../crowdsale/emission/MintedCrowdsale.sol"; -import "../token/ERC20/ERC20Mintable.sol"; -import "../token/ERC20/ERC20Detailed.sol"; - -/** - * @title SampleCrowdsaleToken - * @dev Very simple ERC20 Token that can be minted. - * It is meant to be used in a crowdsale contract. - */ -contract SampleCrowdsaleToken is ERC20Mintable, ERC20Detailed { - constructor () public ERC20Detailed("Sample Crowdsale Token", "SCT", 18) { - // solhint-disable-previous-line no-empty-blocks - } -} - -/** - * @title SampleCrowdsale - * @dev This is an example of a fully fledged crowdsale. - * The way to add new features to a base crowdsale is by multiple inheritance. - * In this example we are providing following extensions: - * CappedCrowdsale - sets a max boundary for raised funds - * RefundableCrowdsale - set a min goal to be reached and returns funds if it's not met - * MintedCrowdsale - assumes the token can be minted by the crowdsale, which does so - * when receiving purchases. - * - * After adding multiple features it's good practice to run integration tests - * to ensure that subcontracts works together as intended. - */ -contract SampleCrowdsale is CappedCrowdsale, RefundableCrowdsale, MintedCrowdsale { - constructor ( - uint256 openingTime, - uint256 closingTime, - uint256 rate, - address payable wallet, - uint256 cap, - ERC20Mintable token, - uint256 goal - ) - public - Crowdsale(rate, wallet, token) - CappedCrowdsale(cap) - TimedCrowdsale(openingTime, closingTime) - RefundableCrowdsale(goal) - { - //As goal needs to be met for a successful crowdsale - //the value needs to less or equal than a cap which is limit for accepted funds - require(goal <= cap, "SampleCrowdSale: goal is greater than cap"); - } -} diff --git a/contracts/examples/SimpleToken.sol b/contracts/examples/SimpleToken.sol deleted file mode 100644 index 7c0e4778c..000000000 --- a/contracts/examples/SimpleToken.sol +++ /dev/null @@ -1,21 +0,0 @@ -pragma solidity ^0.5.0; - -import "../GSN/Context.sol"; -import "../token/ERC20/ERC20.sol"; -import "../token/ERC20/ERC20Detailed.sol"; - -/** - * @title SimpleToken - * @dev Very simple ERC20 Token example, where all tokens are pre-assigned to the creator. - * Note they can later distribute these tokens as they wish using `transfer` and other - * `ERC20` functions. - */ -contract SimpleToken is Context, ERC20, ERC20Detailed { - - /** - * @dev Constructor that gives _msgSender() all of existing tokens. - */ - constructor () public ERC20Detailed("SimpleToken", "SIM", 18) { - _mint(_msgSender(), 10000 * (10 ** uint256(decimals()))); - } -} diff --git a/contracts/introspection/ERC165.sol b/contracts/introspection/ERC165.sol index 86e7c9ae4..881a636e9 100644 --- a/contracts/introspection/ERC165.sol +++ b/contracts/introspection/ERC165.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "./IERC165.sol"; @@ -30,7 +30,7 @@ contract ERC165 is IERC165 { * * Time complexity O(1), guaranteed to always use less than 30 000 gas. */ - function supportsInterface(bytes4 interfaceId) external view returns (bool) { + function supportsInterface(bytes4 interfaceId) external view override returns (bool) { return _supportedInterfaces[interfaceId]; } @@ -45,7 +45,7 @@ contract ERC165 is IERC165 { * * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`). */ - function _registerInterface(bytes4 interfaceId) internal { + function _registerInterface(bytes4 interfaceId) internal virtual { require(interfaceId != 0xffffffff, "ERC165: invalid interface id"); _supportedInterfaces[interfaceId] = true; } diff --git a/contracts/introspection/ERC165Checker.sol b/contracts/introspection/ERC165Checker.sol index 31acc6024..eac14be96 100644 --- a/contracts/introspection/ERC165Checker.sol +++ b/contracts/introspection/ERC165Checker.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.10; +pragma solidity ^0.6.0; /** * @dev Library used to query support of an interface declared via {IERC165}. diff --git a/contracts/introspection/ERC1820Implementer.sol b/contracts/introspection/ERC1820Implementer.sol index 2aba6951b..306db8d6c 100644 --- a/contracts/introspection/ERC1820Implementer.sol +++ b/contracts/introspection/ERC1820Implementer.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "./IERC1820Implementer.sol"; @@ -18,7 +18,7 @@ contract ERC1820Implementer is IERC1820Implementer { /** * See {IERC1820Implementer-canImplementInterfaceForAddress}. */ - function canImplementInterfaceForAddress(bytes32 interfaceHash, address account) external view returns (bytes32) { + function canImplementInterfaceForAddress(bytes32 interfaceHash, address account) external view override returns (bytes32) { return _supportedInterfaces[interfaceHash][account] ? ERC1820_ACCEPT_MAGIC : bytes32(0x00); } @@ -29,7 +29,7 @@ contract ERC1820Implementer is IERC1820Implementer { * See {IERC1820Registry-setInterfaceImplementer} and * {IERC1820Registry-interfaceHash}. */ - function _registerInterfaceForAddress(bytes32 interfaceHash, address account) internal { + function _registerInterfaceForAddress(bytes32 interfaceHash, address account) internal virtual { _supportedInterfaces[interfaceHash][account] = true; } } diff --git a/contracts/introspection/IERC165.sol b/contracts/introspection/IERC165.sol index 07c6fac5f..69cfdf74c 100644 --- a/contracts/introspection/IERC165.sol +++ b/contracts/introspection/IERC165.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; /** * @dev Interface of the ERC165 standard, as defined in the diff --git a/contracts/introspection/IERC1820Implementer.sol b/contracts/introspection/IERC1820Implementer.sol index 21fe82753..2874fc5bc 100644 --- a/contracts/introspection/IERC1820Implementer.sol +++ b/contracts/introspection/IERC1820Implementer.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; /** * @dev Interface for an ERC1820 implementer, as defined in the diff --git a/contracts/introspection/IERC1820Registry.sol b/contracts/introspection/IERC1820Registry.sol index 6a7b2b165..618b6ef2b 100644 --- a/contracts/introspection/IERC1820Registry.sol +++ b/contracts/introspection/IERC1820Registry.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; /** * @dev Interface of the global ERC1820 Registry, as defined in the diff --git a/contracts/lifecycle/Pausable.sol b/contracts/lifecycle/Pausable.sol index 77d11e33b..0a434042f 100644 --- a/contracts/lifecycle/Pausable.sol +++ b/contracts/lifecycle/Pausable.sol @@ -1,7 +1,6 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../GSN/Context.sol"; -import "../access/roles/PauserRole.sol"; /** * @dev Contract module which allows children to implement an emergency stop @@ -12,7 +11,7 @@ import "../access/roles/PauserRole.sol"; * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ -contract Pausable is Context, PauserRole { +contract Pausable is Context { /** * @dev Emitted when the pause is triggered by a pauser (`account`). */ @@ -59,7 +58,7 @@ contract Pausable is Context, PauserRole { /** * @dev Called by a pauser to pause, triggers stopped state. */ - function pause() public onlyPauser whenNotPaused { + function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } @@ -67,7 +66,7 @@ contract Pausable is Context, PauserRole { /** * @dev Called by a pauser to unpause, returns to normal state. */ - function unpause() public onlyPauser whenPaused { + function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } diff --git a/contracts/math/Math.sol b/contracts/math/Math.sol index 4970a6cc6..a94bfa663 100644 --- a/contracts/math/Math.sol +++ b/contracts/math/Math.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; /** * @dev Standard math utilities missing in the Solidity language. diff --git a/contracts/math/SafeMath.sol b/contracts/math/SafeMath.sol index e7091fb22..bb6d86d78 100644 --- a/contracts/math/SafeMath.sol +++ b/contracts/math/SafeMath.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow diff --git a/contracts/mocks/AddressImpl.sol b/contracts/mocks/AddressImpl.sol index 52563608f..d0f5fa836 100644 --- a/contracts/mocks/AddressImpl.sol +++ b/contracts/mocks/AddressImpl.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../utils/Address.sol"; @@ -15,5 +15,6 @@ contract AddressImpl { Address.sendValue(receiver, amount); } - function () external payable { } // sendValue's tests require the contract to hold Ether + // sendValue's tests require the contract to hold Ether + receive () external payable { } } diff --git a/contracts/mocks/AllowanceCrowdsaleImpl.sol b/contracts/mocks/AllowanceCrowdsaleImpl.sol deleted file mode 100644 index 9c6fdb511..000000000 --- a/contracts/mocks/AllowanceCrowdsaleImpl.sol +++ /dev/null @@ -1,14 +0,0 @@ -pragma solidity ^0.5.0; - -import "../token/ERC20/IERC20.sol"; -import "../crowdsale/emission/AllowanceCrowdsale.sol"; - -contract AllowanceCrowdsaleImpl is AllowanceCrowdsale { - constructor (uint256 rate, address payable wallet, IERC20 token, address tokenWallet) - public - Crowdsale(rate, wallet, token) - AllowanceCrowdsale(tokenWallet) - { - // solhint-disable-previous-line no-empty-blocks - } -} diff --git a/contracts/mocks/ArraysImpl.sol b/contracts/mocks/ArraysImpl.sol index b2067526d..c0f93e912 100644 --- a/contracts/mocks/ArraysImpl.sol +++ b/contracts/mocks/ArraysImpl.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../utils/Arrays.sol"; diff --git a/contracts/mocks/CappedCrowdsaleImpl.sol b/contracts/mocks/CappedCrowdsaleImpl.sol deleted file mode 100644 index d0c59db4c..000000000 --- a/contracts/mocks/CappedCrowdsaleImpl.sol +++ /dev/null @@ -1,14 +0,0 @@ -pragma solidity ^0.5.0; - -import "../token/ERC20/IERC20.sol"; -import "../crowdsale/validation/CappedCrowdsale.sol"; - -contract CappedCrowdsaleImpl is CappedCrowdsale { - constructor (uint256 rate, address payable wallet, IERC20 token, uint256 cap) - public - Crowdsale(rate, wallet, token) - CappedCrowdsale(cap) - { - // solhint-disable-previous-line no-empty-blocks - } -} diff --git a/contracts/mocks/CapperRoleMock.sol b/contracts/mocks/CapperRoleMock.sol deleted file mode 100644 index 0090d1ff6..000000000 --- a/contracts/mocks/CapperRoleMock.sol +++ /dev/null @@ -1,18 +0,0 @@ -pragma solidity ^0.5.0; - -import "../access/roles/CapperRole.sol"; - -contract CapperRoleMock is CapperRole { - function removeCapper(address account) public { - _removeCapper(account); - } - - function onlyCapperMock() public view onlyCapper { - // solhint-disable-previous-line no-empty-blocks - } - - // Causes a compilation error if super._removeCapper is not internal - function _removeCapper(address account) internal { - super._removeCapper(account); - } -} diff --git a/contracts/mocks/ConditionalEscrowMock.sol b/contracts/mocks/ConditionalEscrowMock.sol index 4b39ba386..453eab153 100644 --- a/contracts/mocks/ConditionalEscrowMock.sol +++ b/contracts/mocks/ConditionalEscrowMock.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../payment/escrow/ConditionalEscrow.sol"; @@ -10,7 +10,7 @@ contract ConditionalEscrowMock is ConditionalEscrow { _allowed[payee] = allowed; } - function withdrawalAllowed(address payee) public view returns (bool) { + function withdrawalAllowed(address payee) public view override returns (bool) { return _allowed[payee]; } } diff --git a/contracts/mocks/ContextMock.sol b/contracts/mocks/ContextMock.sol index 1cf1d61cc..7e1ecff80 100644 --- a/contracts/mocks/ContextMock.sol +++ b/contracts/mocks/ContextMock.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../GSN/Context.sol"; diff --git a/contracts/mocks/CountersImpl.sol b/contracts/mocks/CountersImpl.sol index cc53139f7..2f3b008a1 100644 --- a/contracts/mocks/CountersImpl.sol +++ b/contracts/mocks/CountersImpl.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../drafts/Counters.sol"; diff --git a/contracts/mocks/Create2Impl.sol b/contracts/mocks/Create2Impl.sol index de3a14f23..5a67b3110 100644 --- a/contracts/mocks/Create2Impl.sol +++ b/contracts/mocks/Create2Impl.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../utils/Create2.sol"; import "../token/ERC20/ERC20.sol"; diff --git a/contracts/mocks/CrowdsaleMock.sol b/contracts/mocks/CrowdsaleMock.sol deleted file mode 100644 index 6dafa4b7e..000000000 --- a/contracts/mocks/CrowdsaleMock.sol +++ /dev/null @@ -1,9 +0,0 @@ -pragma solidity ^0.5.0; - -import "../crowdsale/Crowdsale.sol"; - -contract CrowdsaleMock is Crowdsale { - constructor (uint256 rate, address payable wallet, IERC20 token) public Crowdsale(rate, wallet, token) { - // solhint-disable-previous-line no-empty-blocks - } -} diff --git a/contracts/mocks/ECDSAMock.sol b/contracts/mocks/ECDSAMock.sol index 977f324ac..7184227f4 100644 --- a/contracts/mocks/ECDSAMock.sol +++ b/contracts/mocks/ECDSAMock.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../cryptography/ECDSA.sol"; diff --git a/contracts/mocks/ERC165/ERC165InterfacesSupported.sol b/contracts/mocks/ERC165/ERC165InterfacesSupported.sol index ab4d5a5df..1f184db64 100644 --- a/contracts/mocks/ERC165/ERC165InterfacesSupported.sol +++ b/contracts/mocks/ERC165/ERC165InterfacesSupported.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../../introspection/IERC165.sol"; @@ -34,7 +34,7 @@ contract SupportsInterfaceWithLookupMock is IERC165 { /** * @dev Implement supportsInterface(bytes4) using a lookup table. */ - function supportsInterface(bytes4 interfaceId) external view returns (bool) { + function supportsInterface(bytes4 interfaceId) external view override returns (bool) { return _supportedInterfaces[interfaceId]; } diff --git a/contracts/mocks/ERC165/ERC165NotSupported.sol b/contracts/mocks/ERC165/ERC165NotSupported.sol index d154da33e..098db9271 100644 --- a/contracts/mocks/ERC165/ERC165NotSupported.sol +++ b/contracts/mocks/ERC165/ERC165NotSupported.sol @@ -1,5 +1,3 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; -contract ERC165NotSupported { - // solhint-disable-previous-line no-empty-blocks -} +contract ERC165NotSupported { } diff --git a/contracts/mocks/ERC165CheckerMock.sol b/contracts/mocks/ERC165CheckerMock.sol index db1853de0..1ed380b75 100644 --- a/contracts/mocks/ERC165CheckerMock.sol +++ b/contracts/mocks/ERC165CheckerMock.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../introspection/ERC165Checker.sol"; diff --git a/contracts/mocks/ERC165Mock.sol b/contracts/mocks/ERC165Mock.sol index e21581b52..dcfe86cca 100644 --- a/contracts/mocks/ERC165Mock.sol +++ b/contracts/mocks/ERC165Mock.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../introspection/ERC165.sol"; diff --git a/contracts/mocks/ERC1820ImplementerMock.sol b/contracts/mocks/ERC1820ImplementerMock.sol index e3b2e3a05..6e9bb8c32 100644 --- a/contracts/mocks/ERC1820ImplementerMock.sol +++ b/contracts/mocks/ERC1820ImplementerMock.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../introspection/ERC1820Implementer.sol"; diff --git a/contracts/mocks/ERC20BurnableMock.sol b/contracts/mocks/ERC20BurnableMock.sol index 20db0b9a4..17bf07150 100644 --- a/contracts/mocks/ERC20BurnableMock.sol +++ b/contracts/mocks/ERC20BurnableMock.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../token/ERC20/ERC20Burnable.sol"; diff --git a/contracts/mocks/ERC20CappedMock.sol b/contracts/mocks/ERC20CappedMock.sol new file mode 100644 index 000000000..605d5f78e --- /dev/null +++ b/contracts/mocks/ERC20CappedMock.sol @@ -0,0 +1,11 @@ +pragma solidity ^0.6.0; + +import "../token/ERC20/ERC20Capped.sol"; + +contract ERC20CappedMock is ERC20Capped { + constructor (uint256 cap) public ERC20Capped(cap) { } + + function mint(address to, uint256 tokenId) public { + _mint(to, tokenId); + } +} diff --git a/contracts/mocks/ERC20DetailedMock.sol b/contracts/mocks/ERC20DetailedMock.sol index f2761b348..fcd5403c5 100644 --- a/contracts/mocks/ERC20DetailedMock.sol +++ b/contracts/mocks/ERC20DetailedMock.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../token/ERC20/ERC20.sol"; import "../token/ERC20/ERC20Detailed.sol"; @@ -8,6 +8,6 @@ contract ERC20DetailedMock is ERC20, ERC20Detailed { public ERC20Detailed(name, symbol, decimals) { - // solhint-disable-previous-line no-empty-blocks + } } diff --git a/contracts/mocks/ERC20MetadataMock.sol b/contracts/mocks/ERC20MetadataMock.sol index 9807cc4ae..f18845e11 100644 --- a/contracts/mocks/ERC20MetadataMock.sol +++ b/contracts/mocks/ERC20MetadataMock.sol @@ -1,12 +1,10 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../token/ERC20/ERC20.sol"; import "../drafts/ERC1046/ERC20Metadata.sol"; contract ERC20MetadataMock is ERC20, ERC20Metadata { - constructor (string memory tokenURI) public ERC20Metadata(tokenURI) { - // solhint-disable-previous-line no-empty-blocks - } + constructor (string memory tokenURI) public ERC20Metadata(tokenURI) { } function setTokenURI(string memory tokenURI) public { _setTokenURI(tokenURI); diff --git a/contracts/mocks/ERC20MintableMock.sol b/contracts/mocks/ERC20MintableMock.sol deleted file mode 100644 index 3ea65ef62..000000000 --- a/contracts/mocks/ERC20MintableMock.sol +++ /dev/null @@ -1,8 +0,0 @@ -pragma solidity ^0.5.0; - -import "../token/ERC20/ERC20Mintable.sol"; -import "./MinterRoleMock.sol"; - -contract ERC20MintableMock is ERC20Mintable, MinterRoleMock { - // solhint-disable-previous-line no-empty-blocks -} diff --git a/contracts/mocks/ERC20Mock.sol b/contracts/mocks/ERC20Mock.sol index 0fdfa6953..ab0390927 100644 --- a/contracts/mocks/ERC20Mock.sol +++ b/contracts/mocks/ERC20Mock.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../token/ERC20/ERC20.sol"; diff --git a/contracts/mocks/ERC20PausableMock.sol b/contracts/mocks/ERC20PausableMock.sol index 6b9584e02..d15b0237e 100644 --- a/contracts/mocks/ERC20PausableMock.sol +++ b/contracts/mocks/ERC20PausableMock.sol @@ -1,11 +1,18 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../token/ERC20/ERC20Pausable.sol"; -import "./PauserRoleMock.sol"; // mock class using ERC20Pausable -contract ERC20PausableMock is ERC20Pausable, PauserRoleMock { +contract ERC20PausableMock is ERC20Pausable { constructor (address initialAccount, uint256 initialBalance) public { _mint(initialAccount, initialBalance); } + + function pause() external { + _pause(); + } + + function unpause() external { + _unpause(); + } } diff --git a/contracts/mocks/ERC20SnapshotMock.sol b/contracts/mocks/ERC20SnapshotMock.sol index a877a9209..5333a964f 100644 --- a/contracts/mocks/ERC20SnapshotMock.sol +++ b/contracts/mocks/ERC20SnapshotMock.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../drafts/ERC20Snapshot.sol"; diff --git a/contracts/mocks/ERC721BurnableMock.sol b/contracts/mocks/ERC721BurnableMock.sol new file mode 100644 index 000000000..bb69ffb00 --- /dev/null +++ b/contracts/mocks/ERC721BurnableMock.sol @@ -0,0 +1,9 @@ +pragma solidity ^0.6.0; + +import "../token/ERC721/ERC721Burnable.sol"; + +contract ERC721BurnableMock is ERC721Burnable { + function mint(address to, uint256 tokenId) public { + _mint(to, tokenId); + } +} diff --git a/contracts/mocks/ERC721FullMock.sol b/contracts/mocks/ERC721FullMock.sol index bbd1e32bc..9aef7c1be 100644 --- a/contracts/mocks/ERC721FullMock.sol +++ b/contracts/mocks/ERC721FullMock.sol @@ -1,8 +1,6 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../token/ERC721/ERC721Full.sol"; -import "../token/ERC721/ERC721Mintable.sol"; -import "../token/ERC721/ERC721MetadataMintable.sol"; import "../token/ERC721/ERC721Burnable.sol"; /** @@ -10,10 +8,8 @@ import "../token/ERC721/ERC721Burnable.sol"; * This mock just provides public functions for setting metadata URI, getting all tokens of an owner, * checking token existence, removal of a token from an address */ -contract ERC721FullMock is ERC721Full, ERC721Mintable, ERC721MetadataMintable, ERC721Burnable { - constructor (string memory name, string memory symbol) public ERC721Mintable() ERC721Full(name, symbol) { - // solhint-disable-previous-line no-empty-blocks - } +contract ERC721FullMock is ERC721Full, ERC721Burnable { + constructor (string memory name, string memory symbol) public ERC721Full(name, symbol) { } function exists(uint256 tokenId) public view returns (bool) { return _exists(tokenId); @@ -30,4 +26,12 @@ contract ERC721FullMock is ERC721Full, ERC721Mintable, ERC721MetadataMintable, E function setBaseURI(string memory baseURI) public { _setBaseURI(baseURI); } + + function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual override(ERC721, ERC721Full) { + super._beforeTokenTransfer(from, to, tokenId); + } + + function mint(address to, uint256 tokenId) public { + _mint(to, tokenId); + } } diff --git a/contracts/mocks/ERC721GSNRecipientMock.sol b/contracts/mocks/ERC721GSNRecipientMock.sol index 109cf16ae..c5f7f3e85 100644 --- a/contracts/mocks/ERC721GSNRecipientMock.sol +++ b/contracts/mocks/ERC721GSNRecipientMock.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../token/ERC721/ERC721.sol"; import "../GSN/GSNRecipient.sol"; @@ -10,9 +10,16 @@ import "../GSN/GSNRecipientSignature.sol"; */ contract ERC721GSNRecipientMock is ERC721, GSNRecipient, GSNRecipientSignature { constructor(address trustedSigner) public GSNRecipientSignature(trustedSigner) { } - // solhint-disable-previous-line no-empty-blocks function mint(uint256 tokenId) public { _mint(_msgSender(), tokenId); } + + function _msgSender() internal view override(Context, GSNRecipient) returns (address payable) { + return GSNRecipient._msgSender(); + } + + function _msgData() internal view override(Context, GSNRecipient) returns (bytes memory) { + return GSNRecipient._msgData(); + } } diff --git a/contracts/mocks/ERC721MintableBurnableImpl.sol b/contracts/mocks/ERC721MintableBurnableImpl.sol deleted file mode 100644 index fcb692723..000000000 --- a/contracts/mocks/ERC721MintableBurnableImpl.sol +++ /dev/null @@ -1,15 +0,0 @@ -pragma solidity ^0.5.0; - -import "../token/ERC721/ERC721Full.sol"; -import "../token/ERC721/ERC721Mintable.sol"; -import "../token/ERC721/ERC721MetadataMintable.sol"; -import "../token/ERC721/ERC721Burnable.sol"; - -/** - * @title ERC721MintableBurnableImpl - */ -contract ERC721MintableBurnableImpl is ERC721Full, ERC721Mintable, ERC721MetadataMintable, ERC721Burnable { - constructor () public ERC721Mintable() ERC721Full("Test", "TEST") { - // solhint-disable-previous-line no-empty-blocks - } -} diff --git a/contracts/mocks/ERC721Mock.sol b/contracts/mocks/ERC721Mock.sol index c868a866a..1931afb64 100644 --- a/contracts/mocks/ERC721Mock.sol +++ b/contracts/mocks/ERC721Mock.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../token/ERC721/ERC721.sol"; diff --git a/contracts/mocks/ERC721PausableMock.sol b/contracts/mocks/ERC721PausableMock.sol index f46f9e776..5d845c95b 100644 --- a/contracts/mocks/ERC721PausableMock.sol +++ b/contracts/mocks/ERC721PausableMock.sol @@ -1,13 +1,12 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../token/ERC721/ERC721Pausable.sol"; -import "./PauserRoleMock.sol"; /** * @title ERC721PausableMock * This mock just provides a public mint, burn and exists functions for testing purposes */ -contract ERC721PausableMock is ERC721Pausable, PauserRoleMock { +contract ERC721PausableMock is ERC721Pausable { function mint(address to, uint256 tokenId) public { super._mint(to, tokenId); } @@ -19,4 +18,12 @@ contract ERC721PausableMock is ERC721Pausable, PauserRoleMock { function exists(uint256 tokenId) public view returns (bool) { return super._exists(tokenId); } + + function pause() external { + _pause(); + } + + function unpause() external { + _unpause(); + } } diff --git a/contracts/mocks/ERC721ReceiverMock.sol b/contracts/mocks/ERC721ReceiverMock.sol index a0932eca6..a779ad764 100644 --- a/contracts/mocks/ERC721ReceiverMock.sol +++ b/contracts/mocks/ERC721ReceiverMock.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../token/ERC721/IERC721Receiver.sol"; @@ -14,7 +14,7 @@ contract ERC721ReceiverMock is IERC721Receiver { } function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data) - public returns (bytes4) + public override returns (bytes4) { require(!_reverts, "ERC721ReceiverMock: reverting"); emit Received(operator, from, tokenId, data, gasleft()); diff --git a/contracts/mocks/ERC777Mock.sol b/contracts/mocks/ERC777Mock.sol index 314be2ea7..da89a15a0 100644 --- a/contracts/mocks/ERC777Mock.sol +++ b/contracts/mocks/ERC777Mock.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../GSN/Context.sol"; import "../token/ERC777/ERC777.sol"; diff --git a/contracts/mocks/ERC777SenderRecipientMock.sol b/contracts/mocks/ERC777SenderRecipientMock.sol index a1db31c55..023eba90d 100644 --- a/contracts/mocks/ERC777SenderRecipientMock.sol +++ b/contracts/mocks/ERC777SenderRecipientMock.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../GSN/Context.sol"; import "../token/ERC777/IERC777.sol"; @@ -47,7 +47,7 @@ contract ERC777SenderRecipientMock is Context, IERC777Sender, IERC777Recipient, uint256 amount, bytes calldata userData, bytes calldata operatorData - ) external { + ) external override { if (_shouldRevertSend) { revert(); } @@ -78,7 +78,7 @@ contract ERC777SenderRecipientMock is Context, IERC777Sender, IERC777Recipient, uint256 amount, bytes calldata userData, bytes calldata operatorData - ) external{ + ) external override { if (_shouldRevertReceive) { revert(); } diff --git a/contracts/mocks/EnumerableSetMock.sol b/contracts/mocks/EnumerableSetMock.sol index d2dc13d1e..7eeb49513 100644 --- a/contracts/mocks/EnumerableSetMock.sol +++ b/contracts/mocks/EnumerableSetMock.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../utils/EnumerableSet.sol"; diff --git a/contracts/mocks/EtherReceiverMock.sol b/contracts/mocks/EtherReceiverMock.sol index a2355b803..4092abeeb 100644 --- a/contracts/mocks/EtherReceiverMock.sol +++ b/contracts/mocks/EtherReceiverMock.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; contract EtherReceiverMock { bool private _acceptEther; @@ -7,7 +7,7 @@ contract EtherReceiverMock { _acceptEther = acceptEther; } - function () external payable { + receive () external payable { if (!_acceptEther) { revert(); } diff --git a/contracts/mocks/FinalizableCrowdsaleImpl.sol b/contracts/mocks/FinalizableCrowdsaleImpl.sol deleted file mode 100644 index 99f7a255d..000000000 --- a/contracts/mocks/FinalizableCrowdsaleImpl.sol +++ /dev/null @@ -1,14 +0,0 @@ -pragma solidity ^0.5.0; - -import "../token/ERC20/IERC20.sol"; -import "../crowdsale/distribution/FinalizableCrowdsale.sol"; - -contract FinalizableCrowdsaleImpl is FinalizableCrowdsale { - constructor (uint256 openingTime, uint256 closingTime, uint256 rate, address payable wallet, IERC20 token) - public - Crowdsale(rate, wallet, token) - TimedCrowdsale(openingTime, closingTime) - { - // solhint-disable-previous-line no-empty-blocks - } -} diff --git a/contracts/mocks/GSNRecipientERC20FeeMock.sol b/contracts/mocks/GSNRecipientERC20FeeMock.sol index 83d5e21a1..abc522849 100644 --- a/contracts/mocks/GSNRecipientERC20FeeMock.sol +++ b/contracts/mocks/GSNRecipientERC20FeeMock.sol @@ -1,12 +1,10 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../GSN/GSNRecipient.sol"; import "../GSN/GSNRecipientERC20Fee.sol"; contract GSNRecipientERC20FeeMock is GSNRecipient, GSNRecipientERC20Fee { - constructor(string memory name, string memory symbol) public GSNRecipientERC20Fee(name, symbol) { - // solhint-disable-previous-line no-empty-blocks - } + constructor(string memory name, string memory symbol) public GSNRecipientERC20Fee(name, symbol) { } function mint(address account, uint256 amount) public { _mint(account, amount); diff --git a/contracts/mocks/GSNRecipientMock.sol b/contracts/mocks/GSNRecipientMock.sol index 7a8c49391..c3575afda 100644 --- a/contracts/mocks/GSNRecipientMock.sol +++ b/contracts/mocks/GSNRecipientMock.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "./ContextMock.sol"; import "../GSN/GSNRecipient.sol"; @@ -12,20 +12,25 @@ contract GSNRecipientMock is ContextMock, GSNRecipient { function acceptRelayedCall(address, address, bytes calldata, uint256, uint256, uint256, uint256, bytes calldata, uint256) external view + override returns (uint256, bytes memory) { return (0, ""); } - function _preRelayedCall(bytes memory) internal returns (bytes32) { - // solhint-disable-previous-line no-empty-blocks - } + function _preRelayedCall(bytes memory) internal override returns (bytes32) { } - function _postRelayedCall(bytes memory, bool, uint256, bytes32) internal { - // solhint-disable-previous-line no-empty-blocks - } + function _postRelayedCall(bytes memory, bool, uint256, bytes32) internal override { } function upgradeRelayHub(address newRelayHub) public { return _upgradeRelayHub(newRelayHub); } + + function _msgSender() internal override(Context, GSNRecipient) view virtual returns (address payable) { + return GSNRecipient._msgSender(); + } + + function _msgData() internal override(Context, GSNRecipient) view virtual returns (bytes memory) { + return GSNRecipient._msgData(); + } } diff --git a/contracts/mocks/GSNRecipientSignatureMock.sol b/contracts/mocks/GSNRecipientSignatureMock.sol index e2004b9c9..36b30357c 100644 --- a/contracts/mocks/GSNRecipientSignatureMock.sol +++ b/contracts/mocks/GSNRecipientSignatureMock.sol @@ -1,12 +1,10 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../GSN/GSNRecipient.sol"; import "../GSN/GSNRecipientSignature.sol"; contract GSNRecipientSignatureMock is GSNRecipient, GSNRecipientSignature { - constructor(address trustedSigner) public GSNRecipientSignature(trustedSigner) { - // solhint-disable-previous-line no-empty-blocks - } + constructor(address trustedSigner) public GSNRecipientSignature(trustedSigner) { } event MockFunctionCalled(); diff --git a/contracts/mocks/IncreasingPriceCrowdsaleImpl.sol b/contracts/mocks/IncreasingPriceCrowdsaleImpl.sol deleted file mode 100644 index c5b0e7957..000000000 --- a/contracts/mocks/IncreasingPriceCrowdsaleImpl.sol +++ /dev/null @@ -1,22 +0,0 @@ -pragma solidity ^0.5.0; - -import "../crowdsale/price/IncreasingPriceCrowdsale.sol"; -import "../math/SafeMath.sol"; - -contract IncreasingPriceCrowdsaleImpl is IncreasingPriceCrowdsale { - constructor ( - uint256 openingTime, - uint256 closingTime, - address payable wallet, - IERC20 token, - uint256 initialRate, - uint256 finalRate - ) - public - Crowdsale(initialRate, wallet, token) - TimedCrowdsale(openingTime, closingTime) - IncreasingPriceCrowdsale(initialRate, finalRate) - { - // solhint-disable-previous-line no-empty-blocks - } -} diff --git a/contracts/mocks/IndividuallyCappedCrowdsaleImpl.sol b/contracts/mocks/IndividuallyCappedCrowdsaleImpl.sol deleted file mode 100644 index 43b0366ee..000000000 --- a/contracts/mocks/IndividuallyCappedCrowdsaleImpl.sol +++ /dev/null @@ -1,11 +0,0 @@ -pragma solidity ^0.5.0; - -import "../token/ERC20/IERC20.sol"; -import "../crowdsale/validation/IndividuallyCappedCrowdsale.sol"; -import "./CapperRoleMock.sol"; - -contract IndividuallyCappedCrowdsaleImpl is IndividuallyCappedCrowdsale, CapperRoleMock { - constructor (uint256 rate, address payable wallet, IERC20 token) public Crowdsale(rate, wallet, token) { - // solhint-disable-previous-line no-empty-blocks - } -} diff --git a/contracts/mocks/MathMock.sol b/contracts/mocks/MathMock.sol index 2461fe902..4750a87c6 100644 --- a/contracts/mocks/MathMock.sol +++ b/contracts/mocks/MathMock.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../math/Math.sol"; diff --git a/contracts/mocks/MerkleProofWrapper.sol b/contracts/mocks/MerkleProofWrapper.sol index 23c72b269..9ec675111 100644 --- a/contracts/mocks/MerkleProofWrapper.sol +++ b/contracts/mocks/MerkleProofWrapper.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import { MerkleProof } from "../cryptography/MerkleProof.sol"; diff --git a/contracts/mocks/MintedCrowdsaleImpl.sol b/contracts/mocks/MintedCrowdsaleImpl.sol deleted file mode 100644 index 22f4d36c0..000000000 --- a/contracts/mocks/MintedCrowdsaleImpl.sol +++ /dev/null @@ -1,10 +0,0 @@ -pragma solidity ^0.5.0; - -import "../token/ERC20/ERC20Mintable.sol"; -import "../crowdsale/emission/MintedCrowdsale.sol"; - -contract MintedCrowdsaleImpl is MintedCrowdsale { - constructor (uint256 rate, address payable wallet, ERC20Mintable token) public Crowdsale(rate, wallet, token) { - // solhint-disable-previous-line no-empty-blocks - } -} diff --git a/contracts/mocks/MinterRoleMock.sol b/contracts/mocks/MinterRoleMock.sol deleted file mode 100644 index 4b0401d87..000000000 --- a/contracts/mocks/MinterRoleMock.sol +++ /dev/null @@ -1,18 +0,0 @@ -pragma solidity ^0.5.0; - -import "../access/roles/MinterRole.sol"; - -contract MinterRoleMock is MinterRole { - function removeMinter(address account) public { - _removeMinter(account); - } - - function onlyMinterMock() public view onlyMinter { - // solhint-disable-previous-line no-empty-blocks - } - - // Causes a compilation error if super._removeMinter is not internal - function _removeMinter(address account) internal { - super._removeMinter(account); - } -} diff --git a/contracts/mocks/OwnableInterfaceId.sol b/contracts/mocks/OwnableInterfaceId.sol index 996ab88e9..19dc680bb 100644 --- a/contracts/mocks/OwnableInterfaceId.sol +++ b/contracts/mocks/OwnableInterfaceId.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../ownership/Ownable.sol"; diff --git a/contracts/mocks/OwnableMock.sol b/contracts/mocks/OwnableMock.sol index c7b1cf5c7..85e829198 100644 --- a/contracts/mocks/OwnableMock.sol +++ b/contracts/mocks/OwnableMock.sol @@ -1,7 +1,5 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../ownership/Ownable.sol"; -contract OwnableMock is Ownable { - // solhint-disable-previous-line no-empty-blocks -} +contract OwnableMock is Ownable { } diff --git a/contracts/mocks/PausableCrowdsaleImpl.sol b/contracts/mocks/PausableCrowdsaleImpl.sol deleted file mode 100644 index 11f44c7b8..000000000 --- a/contracts/mocks/PausableCrowdsaleImpl.sol +++ /dev/null @@ -1,10 +0,0 @@ -pragma solidity ^0.5.0; - -import "../token/ERC20/ERC20.sol"; -import "../crowdsale/validation/PausableCrowdsale.sol"; - -contract PausableCrowdsaleImpl is PausableCrowdsale { - constructor (uint256 _rate, address payable _wallet, ERC20 _token) public Crowdsale(_rate, _wallet, _token) { - // solhint-disable-previous-line no-empty-blocks - } -} diff --git a/contracts/mocks/PausableMock.sol b/contracts/mocks/PausableMock.sol index 8e9ae03d3..2f48a1ad1 100644 --- a/contracts/mocks/PausableMock.sol +++ b/contracts/mocks/PausableMock.sol @@ -1,10 +1,8 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../lifecycle/Pausable.sol"; -import "./PauserRoleMock.sol"; -// mock class using Pausable -contract PausableMock is Pausable, PauserRoleMock { +contract PausableMock is Pausable { bool public drasticMeasureTaken; uint256 public count; @@ -20,4 +18,12 @@ contract PausableMock is Pausable, PauserRoleMock { function drasticMeasure() external whenPaused { drasticMeasureTaken = true; } + + function pause() external { + _pause(); + } + + function unpause() external { + _unpause(); + } } diff --git a/contracts/mocks/PauserRoleMock.sol b/contracts/mocks/PauserRoleMock.sol deleted file mode 100644 index fc2ed16d9..000000000 --- a/contracts/mocks/PauserRoleMock.sol +++ /dev/null @@ -1,18 +0,0 @@ -pragma solidity ^0.5.0; - -import "../access/roles/PauserRole.sol"; - -contract PauserRoleMock is PauserRole { - function removePauser(address account) public { - _removePauser(account); - } - - function onlyPauserMock() public view onlyPauser { - // solhint-disable-previous-line no-empty-blocks - } - - // Causes a compilation error if super._removePauser is not internal - function _removePauser(address account) internal { - super._removePauser(account); - } -} diff --git a/contracts/mocks/PostDeliveryCrowdsaleImpl.sol b/contracts/mocks/PostDeliveryCrowdsaleImpl.sol deleted file mode 100644 index efb67c084..000000000 --- a/contracts/mocks/PostDeliveryCrowdsaleImpl.sol +++ /dev/null @@ -1,14 +0,0 @@ -pragma solidity ^0.5.0; - -import "../token/ERC20/IERC20.sol"; -import "../crowdsale/distribution/PostDeliveryCrowdsale.sol"; - -contract PostDeliveryCrowdsaleImpl is PostDeliveryCrowdsale { - constructor (uint256 openingTime, uint256 closingTime, uint256 rate, address payable wallet, IERC20 token) - public - TimedCrowdsale(openingTime, closingTime) - Crowdsale(rate, wallet, token) - { - // solhint-disable-previous-line no-empty-blocks - } -} diff --git a/contracts/mocks/PullPaymentMock.sol b/contracts/mocks/PullPaymentMock.sol index 1a26b6242..7bdde19f1 100644 --- a/contracts/mocks/PullPaymentMock.sol +++ b/contracts/mocks/PullPaymentMock.sol @@ -1,12 +1,10 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../payment/PullPayment.sol"; // mock class using PullPayment contract PullPaymentMock is PullPayment { - constructor () public payable { - // solhint-disable-previous-line no-empty-blocks - } + constructor () public payable { } // test helper function to call asyncTransfer function callTransfer(address dest, uint256 amount) public { diff --git a/contracts/mocks/ReentrancyAttack.sol b/contracts/mocks/ReentrancyAttack.sol index 2b8b6be36..bd01223fa 100644 --- a/contracts/mocks/ReentrancyAttack.sol +++ b/contracts/mocks/ReentrancyAttack.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../GSN/Context.sol"; contract ReentrancyAttack is Context { diff --git a/contracts/mocks/ReentrancyMock.sol b/contracts/mocks/ReentrancyMock.sol index 50233287d..7452f0ad2 100644 --- a/contracts/mocks/ReentrancyMock.sol +++ b/contracts/mocks/ReentrancyMock.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../utils/ReentrancyGuard.sol"; import "./ReentrancyAttack.sol"; diff --git a/contracts/mocks/RefundableCrowdsaleImpl.sol b/contracts/mocks/RefundableCrowdsaleImpl.sol deleted file mode 100644 index 5ed5d1ed5..000000000 --- a/contracts/mocks/RefundableCrowdsaleImpl.sol +++ /dev/null @@ -1,22 +0,0 @@ -pragma solidity ^0.5.0; - -import "../token/ERC20/IERC20.sol"; -import "../crowdsale/distribution/RefundableCrowdsale.sol"; - -contract RefundableCrowdsaleImpl is RefundableCrowdsale { - constructor ( - uint256 openingTime, - uint256 closingTime, - uint256 rate, - address payable wallet, - IERC20 token, - uint256 goal - ) - public - Crowdsale(rate, wallet, token) - TimedCrowdsale(openingTime, closingTime) - RefundableCrowdsale(goal) - { - // solhint-disable-previous-line no-empty-blocks - } -} diff --git a/contracts/mocks/RefundablePostDeliveryCrowdsaleImpl.sol b/contracts/mocks/RefundablePostDeliveryCrowdsaleImpl.sol deleted file mode 100644 index b81f0757c..000000000 --- a/contracts/mocks/RefundablePostDeliveryCrowdsaleImpl.sol +++ /dev/null @@ -1,22 +0,0 @@ -pragma solidity ^0.5.0; - -import "../token/ERC20/IERC20.sol"; -import "../crowdsale/distribution/RefundablePostDeliveryCrowdsale.sol"; - -contract RefundablePostDeliveryCrowdsaleImpl is RefundablePostDeliveryCrowdsale { - constructor ( - uint256 openingTime, - uint256 closingTime, - uint256 rate, - address payable wallet, - IERC20 token, - uint256 goal - ) - public - Crowdsale(rate, wallet, token) - TimedCrowdsale(openingTime, closingTime) - RefundableCrowdsale(goal) - { - // solhint-disable-previous-line no-empty-blocks - } -} diff --git a/contracts/mocks/RolesMock.sol b/contracts/mocks/RolesMock.sol index 4b0f0de0a..586342a78 100644 --- a/contracts/mocks/RolesMock.sol +++ b/contracts/mocks/RolesMock.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../access/Roles.sol"; diff --git a/contracts/mocks/SafeCastMock.sol b/contracts/mocks/SafeCastMock.sol index b6dd779a5..daa2fe6de 100644 --- a/contracts/mocks/SafeCastMock.sol +++ b/contracts/mocks/SafeCastMock.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../utils/SafeCast.sol"; diff --git a/contracts/mocks/SafeERC20Helper.sol b/contracts/mocks/SafeERC20Helper.sol index 8a1590262..ae04b4e88 100644 --- a/contracts/mocks/SafeERC20Helper.sol +++ b/contracts/mocks/SafeERC20Helper.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../GSN/Context.sol"; import "../token/ERC20/IERC20.sol"; diff --git a/contracts/mocks/SafeMathMock.sol b/contracts/mocks/SafeMathMock.sol index 43dac5ec2..10b340a20 100644 --- a/contracts/mocks/SafeMathMock.sol +++ b/contracts/mocks/SafeMathMock.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../math/SafeMath.sol"; diff --git a/contracts/mocks/SecondaryMock.sol b/contracts/mocks/SecondaryMock.sol index 1ff45b11e..b5ebd22f7 100644 --- a/contracts/mocks/SecondaryMock.sol +++ b/contracts/mocks/SecondaryMock.sol @@ -1,9 +1,7 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../ownership/Secondary.sol"; contract SecondaryMock is Secondary { - function onlyPrimaryMock() public view onlyPrimary { - // solhint-disable-previous-line no-empty-blocks - } + function onlyPrimaryMock() public view onlyPrimary { } } diff --git a/contracts/mocks/SignedSafeMathMock.sol b/contracts/mocks/SignedSafeMathMock.sol index 90a3ee642..33f705f0d 100644 --- a/contracts/mocks/SignedSafeMathMock.sol +++ b/contracts/mocks/SignedSafeMathMock.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../drafts/SignedSafeMath.sol"; diff --git a/contracts/mocks/SignerRoleMock.sol b/contracts/mocks/SignerRoleMock.sol deleted file mode 100644 index 71b4c792a..000000000 --- a/contracts/mocks/SignerRoleMock.sol +++ /dev/null @@ -1,18 +0,0 @@ -pragma solidity ^0.5.0; - -import "../access/roles/SignerRole.sol"; - -contract SignerRoleMock is SignerRole { - function removeSigner(address account) public { - _removeSigner(account); - } - - function onlySignerMock() public view onlySigner { - // solhint-disable-previous-line no-empty-blocks - } - - // Causes a compilation error if super._removeSigner is not internal - function _removeSigner(address account) internal { - super._removeSigner(account); - } -} diff --git a/contracts/mocks/StringsMock.sol b/contracts/mocks/StringsMock.sol index 3b28a70e8..bc19b40c9 100644 --- a/contracts/mocks/StringsMock.sol +++ b/contracts/mocks/StringsMock.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../drafts/Strings.sol"; diff --git a/contracts/mocks/TimedCrowdsaleImpl.sol b/contracts/mocks/TimedCrowdsaleImpl.sol deleted file mode 100644 index b85817c77..000000000 --- a/contracts/mocks/TimedCrowdsaleImpl.sol +++ /dev/null @@ -1,18 +0,0 @@ -pragma solidity ^0.5.0; - -import "../token/ERC20/IERC20.sol"; -import "../crowdsale/validation/TimedCrowdsale.sol"; - -contract TimedCrowdsaleImpl is TimedCrowdsale { - constructor (uint256 openingTime, uint256 closingTime, uint256 rate, address payable wallet, IERC20 token) - public - Crowdsale(rate, wallet, token) - TimedCrowdsale(openingTime, closingTime) - { - // solhint-disable-previous-line no-empty-blocks - } - - function extendTime(uint256 closingTime) public { - _extendTime(closingTime); - } -} diff --git a/contracts/mocks/WhitelistAdminRoleMock.sol b/contracts/mocks/WhitelistAdminRoleMock.sol deleted file mode 100644 index 7a267ca21..000000000 --- a/contracts/mocks/WhitelistAdminRoleMock.sol +++ /dev/null @@ -1,18 +0,0 @@ -pragma solidity ^0.5.0; - -import "../access/roles/WhitelistAdminRole.sol"; - -contract WhitelistAdminRoleMock is WhitelistAdminRole { - function removeWhitelistAdmin(address account) public { - _removeWhitelistAdmin(account); - } - - function onlyWhitelistAdminMock() public view onlyWhitelistAdmin { - // solhint-disable-previous-line no-empty-blocks - } - - // Causes a compilation error if super._removeWhitelistAdmin is not internal - function _removeWhitelistAdmin(address account) internal { - super._removeWhitelistAdmin(account); - } -} diff --git a/contracts/mocks/WhitelistCrowdsaleImpl.sol b/contracts/mocks/WhitelistCrowdsaleImpl.sol deleted file mode 100644 index 0200f7f7f..000000000 --- a/contracts/mocks/WhitelistCrowdsaleImpl.sol +++ /dev/null @@ -1,12 +0,0 @@ -pragma solidity ^0.5.0; - -import "../token/ERC20/IERC20.sol"; -import "../crowdsale/validation/WhitelistCrowdsale.sol"; -import "../crowdsale/Crowdsale.sol"; - - -contract WhitelistCrowdsaleImpl is Crowdsale, WhitelistCrowdsale { - constructor (uint256 _rate, address payable _wallet, IERC20 _token) public Crowdsale(_rate, _wallet, _token) { - // solhint-disable-previous-line no-empty-blocks - } -} diff --git a/contracts/mocks/WhitelistedRoleMock.sol b/contracts/mocks/WhitelistedRoleMock.sol deleted file mode 100644 index 7f7c89412..000000000 --- a/contracts/mocks/WhitelistedRoleMock.sol +++ /dev/null @@ -1,9 +0,0 @@ -pragma solidity ^0.5.0; - -import "../access/roles/WhitelistedRole.sol"; - -contract WhitelistedRoleMock is WhitelistedRole { - function onlyWhitelistedMock() public view onlyWhitelisted { - // solhint-disable-previous-line no-empty-blocks - } -} diff --git a/contracts/ownership/Ownable.sol b/contracts/ownership/Ownable.sol index cd9c061d0..c1168054e 100644 --- a/contracts/ownership/Ownable.sol +++ b/contracts/ownership/Ownable.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../GSN/Context.sol"; /** @@ -53,7 +53,7 @@ contract Ownable is Context { * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ - function renounceOwnership() public onlyOwner { + function renounceOwnership() public virtual onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } @@ -62,14 +62,14 @@ contract Ownable is Context { * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ - function transferOwnership(address newOwner) public onlyOwner { + function transferOwnership(address newOwner) public virtual onlyOwner { _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). */ - function _transferOwnership(address newOwner) internal { + function _transferOwnership(address newOwner) internal virtual { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; diff --git a/contracts/ownership/Secondary.sol b/contracts/ownership/Secondary.sol index cc474d43e..0eb796f4b 100644 --- a/contracts/ownership/Secondary.sol +++ b/contracts/ownership/Secondary.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../GSN/Context.sol"; /** @@ -42,7 +42,7 @@ contract Secondary is Context { * @dev Transfers contract to a new primary. * @param recipient The address of new primary. */ - function transferPrimary(address recipient) public onlyPrimary { + function transferPrimary(address recipient) public virtual onlyPrimary { require(recipient != address(0), "Secondary: new primary is the zero address"); _primary = recipient; emit PrimaryTransferred(recipient); diff --git a/contracts/payment/PaymentSplitter.sol b/contracts/payment/PaymentSplitter.sol index 561af437c..d3a73cf5e 100644 --- a/contracts/payment/PaymentSplitter.sol +++ b/contracts/payment/PaymentSplitter.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../GSN/Context.sol"; import "../math/SafeMath.sol"; @@ -56,7 +56,7 @@ contract PaymentSplitter is Context { * https://solidity.readthedocs.io/en/latest/contracts.html#fallback-function[fallback * functions]. */ - function () external payable { + receive () external payable virtual { emit PaymentReceived(_msgSender(), msg.value); } @@ -99,7 +99,7 @@ contract PaymentSplitter is Context { * @dev Triggers a transfer to `account` of the amount of Ether they are owed, according to their percentage of the * total shares and their previous withdrawals. */ - function release(address payable account) public { + function release(address payable account) public virtual { require(_shares[account] > 0, "PaymentSplitter: account has no shares"); uint256 totalReceived = address(this).balance.add(_totalReleased); diff --git a/contracts/payment/PullPayment.sol b/contracts/payment/PullPayment.sol index 601445846..58bc099d0 100644 --- a/contracts/payment/PullPayment.sol +++ b/contracts/payment/PullPayment.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "./escrow/Escrow.sol"; @@ -42,7 +42,7 @@ contract PullPayment { * * @param payee Whose payments will be withdrawn. */ - function withdrawPayments(address payable payee) public { + function withdrawPayments(address payable payee) public virtual { _escrow.withdraw(payee); } @@ -55,7 +55,7 @@ contract PullPayment { * * _Available since v2.4.0._ */ - function withdrawPaymentsWithGas(address payable payee) external { + function withdrawPaymentsWithGas(address payable payee) external virtual { _escrow.withdrawWithGas(payee); } @@ -75,7 +75,7 @@ contract PullPayment { * @param dest The destination address of the funds. * @param amount The amount to transfer. */ - function _asyncTransfer(address dest, uint256 amount) internal { + function _asyncTransfer(address dest, uint256 amount) internal virtual { _escrow.deposit.value(amount)(dest); } } diff --git a/contracts/payment/escrow/ConditionalEscrow.sol b/contracts/payment/escrow/ConditionalEscrow.sol index d1f8e1eba..a057efb18 100644 --- a/contracts/payment/escrow/ConditionalEscrow.sol +++ b/contracts/payment/escrow/ConditionalEscrow.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "./Escrow.sol"; @@ -7,15 +7,15 @@ import "./Escrow.sol"; * @dev Base abstract escrow to only allow withdrawal if a condition is met. * @dev Intended usage: See {Escrow}. Same usage guidelines apply here. */ -contract ConditionalEscrow is Escrow { +abstract contract ConditionalEscrow is Escrow { /** * @dev Returns whether an address is allowed to withdraw their funds. To be * implemented by derived contracts. * @param payee The destination address of the funds. */ - function withdrawalAllowed(address payee) public view returns (bool); + function withdrawalAllowed(address payee) public view virtual returns (bool); - function withdraw(address payable payee) public { + function withdraw(address payable payee) public virtual override { require(withdrawalAllowed(payee), "ConditionalEscrow: payee is not allowed to withdraw"); super.withdraw(payee); } diff --git a/contracts/payment/escrow/Escrow.sol b/contracts/payment/escrow/Escrow.sol index 01ef2cdef..3744c2b39 100644 --- a/contracts/payment/escrow/Escrow.sol +++ b/contracts/payment/escrow/Escrow.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../../math/SafeMath.sol"; import "../../ownership/Secondary.sol"; @@ -34,7 +34,7 @@ contract Escrow is Secondary { * @dev Stores the sent amount as credit to be withdrawn. * @param payee The destination address of the funds. */ - function deposit(address payee) public onlyPrimary payable { + function deposit(address payee) public virtual payable onlyPrimary { uint256 amount = msg.value; _deposits[payee] = _deposits[payee].add(amount); @@ -52,7 +52,7 @@ contract Escrow is Secondary { * * @param payee The address whose funds will be withdrawn and transferred to. */ - function withdraw(address payable payee) public onlyPrimary { + function withdraw(address payable payee) public virtual onlyPrimary { uint256 payment = _deposits[payee]; _deposits[payee] = 0; @@ -71,7 +71,7 @@ contract Escrow is Secondary { * * _Available since v2.4.0._ */ - function withdrawWithGas(address payable payee) public onlyPrimary { + function withdrawWithGas(address payable payee) public virtual onlyPrimary { uint256 payment = _deposits[payee]; _deposits[payee] = 0; diff --git a/contracts/payment/escrow/RefundEscrow.sol b/contracts/payment/escrow/RefundEscrow.sol index 9eb164cb8..aed8e620a 100644 --- a/contracts/payment/escrow/RefundEscrow.sol +++ b/contracts/payment/escrow/RefundEscrow.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "./ConditionalEscrow.sol"; @@ -50,7 +50,7 @@ contract RefundEscrow is ConditionalEscrow { * @dev Stores funds that may later be refunded. * @param refundee The address funds will be sent to if a refund occurs. */ - function deposit(address refundee) public payable { + function deposit(address refundee) public payable virtual override { require(_state == State.Active, "RefundEscrow: can only deposit while active"); super.deposit(refundee); } @@ -59,7 +59,7 @@ contract RefundEscrow is ConditionalEscrow { * @dev Allows for the beneficiary to withdraw their funds, rejecting * further deposits. */ - function close() public onlyPrimary { + function close() public onlyPrimary virtual { require(_state == State.Active, "RefundEscrow: can only close while active"); _state = State.Closed; emit RefundsClosed(); @@ -68,7 +68,7 @@ contract RefundEscrow is ConditionalEscrow { /** * @dev Allows for refunds to take place, rejecting further deposits. */ - function enableRefunds() public onlyPrimary { + function enableRefunds() public onlyPrimary virtual { require(_state == State.Active, "RefundEscrow: can only enable refunds while active"); _state = State.Refunding; emit RefundsEnabled(); @@ -77,7 +77,7 @@ contract RefundEscrow is ConditionalEscrow { /** * @dev Withdraws the beneficiary's funds. */ - function beneficiaryWithdraw() public { + function beneficiaryWithdraw() public virtual { require(_state == State.Closed, "RefundEscrow: beneficiary can only withdraw while closed"); _beneficiary.transfer(address(this).balance); } @@ -86,7 +86,7 @@ contract RefundEscrow is ConditionalEscrow { * @dev Returns whether refundees can withdraw their deposits (be refunded). The overridden function receives a * 'payee' argument, but we ignore it here since the condition is global, not per-payee. */ - function withdrawalAllowed(address) public view returns (bool) { + function withdrawalAllowed(address) public view override returns (bool) { return _state == State.Refunding; } } diff --git a/contracts/token/ERC20/ERC20.sol b/contracts/token/ERC20/ERC20.sol index 0846fb2cb..429488f60 100644 --- a/contracts/token/ERC20/ERC20.sol +++ b/contracts/token/ERC20/ERC20.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../../GSN/Context.sol"; import "./IERC20.sol"; @@ -40,14 +40,14 @@ contract ERC20 is Context, IERC20 { /** * @dev See {IERC20-totalSupply}. */ - function totalSupply() public view returns (uint256) { + function totalSupply() public view override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ - function balanceOf(address account) public view returns (uint256) { + function balanceOf(address account) public view override returns (uint256) { return _balances[account]; } @@ -59,7 +59,7 @@ contract ERC20 is Context, IERC20 { * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ - function transfer(address recipient, uint256 amount) public returns (bool) { + function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } @@ -67,7 +67,7 @@ contract ERC20 is Context, IERC20 { /** * @dev See {IERC20-allowance}. */ - function allowance(address owner, address spender) public view returns (uint256) { + function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } @@ -78,7 +78,7 @@ contract ERC20 is Context, IERC20 { * * - `spender` cannot be the zero address. */ - function approve(address spender, uint256 amount) public returns (bool) { + function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), spender, amount); return true; } @@ -95,7 +95,7 @@ contract ERC20 is Context, IERC20 { * - the caller must have allowance for `sender`'s tokens of at least * `amount`. */ - function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) { + function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { _transfer(sender, recipient, amount); _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); return true; @@ -113,7 +113,7 @@ contract ERC20 is Context, IERC20 { * * - `spender` cannot be the zero address. */ - function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { + function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); return true; } @@ -132,7 +132,7 @@ contract ERC20 is Context, IERC20 { * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ - function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { + function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); return true; } @@ -151,10 +151,12 @@ contract ERC20 is Context, IERC20 { * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ - function _transfer(address sender, address recipient, uint256 amount) internal { + function _transfer(address sender, address recipient, uint256 amount) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); + _beforeTokenTransfer(sender, recipient, amount); + _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); @@ -169,9 +171,11 @@ contract ERC20 is Context, IERC20 { * * - `to` cannot be the zero address. */ - function _mint(address account, uint256 amount) internal { + function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); + _beforeTokenTransfer(address(0), account, amount); + _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); @@ -188,9 +192,11 @@ contract ERC20 is Context, IERC20 { * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ - function _burn(address account, uint256 amount) internal { + function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); + _beforeTokenTransfer(account, address(0), amount); + _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); @@ -209,7 +215,7 @@ contract ERC20 is Context, IERC20 { * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ - function _approve(address owner, address spender, uint256 amount) internal { + function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); @@ -223,8 +229,24 @@ contract ERC20 is Context, IERC20 { * * See {_burn} and {_approve}. */ - function _burnFrom(address account, uint256 amount) internal { + function _burnFrom(address account, uint256 amount) internal virtual { _burn(account, amount); _approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "ERC20: burn amount exceeds allowance")); } + + /** + * @dev Hook that is called before any transfer of tokens. This includes + * minting and burning. + * + * Calling conditions: + * + * - when `from` and `to` are both non-zero, `amount` of `from`'s tokens + * will be to transferred to `to`. + * - when `from` is zero, `amount` tokens will be minted for `to`. + * - when `to` is zero, `amount` of `from`'s tokens will be burned. + * - `from` and `to` are never both zero. + * + * To learn more about hooks, head to xref:ROOT:using-hooks.adoc[Using Hooks]. + */ + function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { } } diff --git a/contracts/token/ERC20/ERC20Burnable.sol b/contracts/token/ERC20/ERC20Burnable.sol index e58b72b25..250e7325b 100644 --- a/contracts/token/ERC20/ERC20Burnable.sol +++ b/contracts/token/ERC20/ERC20Burnable.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../../GSN/Context.sol"; import "./ERC20.sol"; @@ -14,14 +14,14 @@ contract ERC20Burnable is Context, ERC20 { * * See {ERC20-_burn}. */ - function burn(uint256 amount) public { + function burn(uint256 amount) public virtual { _burn(_msgSender(), amount); } /** * @dev See {ERC20-_burnFrom}. */ - function burnFrom(address account, uint256 amount) public { + function burnFrom(address account, uint256 amount) public virtual { _burnFrom(account, amount); } } diff --git a/contracts/token/ERC20/ERC20Capped.sol b/contracts/token/ERC20/ERC20Capped.sol index 17efca0c4..5f695c818 100644 --- a/contracts/token/ERC20/ERC20Capped.sol +++ b/contracts/token/ERC20/ERC20Capped.sol @@ -1,11 +1,11 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; -import "./ERC20Mintable.sol"; +import "./ERC20.sol"; /** - * @dev Extension of {ERC20Mintable} that adds a cap to the supply of tokens. + * @dev Extension of {ERC20} that adds a cap to the supply of tokens. */ -contract ERC20Capped is ERC20Mintable { +contract ERC20Capped is ERC20 { uint256 private _cap; /** @@ -25,14 +25,17 @@ contract ERC20Capped is ERC20Mintable { } /** - * @dev See {ERC20Mintable-mint}. + * @dev See {ERC20-_beforeTokenTransfer}. * * Requirements: * - * - `value` must not cause the total supply to go over the cap. + * - minted tokens must not cause the total supply to go over the cap. */ - function _mint(address account, uint256 value) internal { - require(totalSupply().add(value) <= _cap, "ERC20Capped: cap exceeded"); - super._mint(account, value); + function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override { + super._beforeTokenTransfer(from, to, amount); + + if (from == address(0)) { // When minting tokens + require(totalSupply().add(amount) <= _cap, "ERC20Capped: cap exceeded"); + } } } diff --git a/contracts/token/ERC20/ERC20Detailed.sol b/contracts/token/ERC20/ERC20Detailed.sol index 61d4ab922..fd44f834f 100644 --- a/contracts/token/ERC20/ERC20Detailed.sol +++ b/contracts/token/ERC20/ERC20Detailed.sol @@ -1,11 +1,11 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "./IERC20.sol"; /** * @dev Optional functions from the ERC20 standard. */ -contract ERC20Detailed is IERC20 { +abstract contract ERC20Detailed is IERC20 { string private _name; string private _symbol; uint8 private _decimals; diff --git a/contracts/token/ERC20/ERC20Mintable.sol b/contracts/token/ERC20/ERC20Mintable.sol deleted file mode 100644 index d2fd5b737..000000000 --- a/contracts/token/ERC20/ERC20Mintable.sol +++ /dev/null @@ -1,24 +0,0 @@ -pragma solidity ^0.5.0; - -import "./ERC20.sol"; -import "../../access/roles/MinterRole.sol"; - -/** - * @dev Extension of {ERC20} that adds a set of accounts with the {MinterRole}, - * which have permission to mint (create) new tokens as they see fit. - * - * At construction, the deployer of the contract is the only minter. - */ -contract ERC20Mintable is ERC20, MinterRole { - /** - * @dev See {ERC20-_mint}. - * - * Requirements: - * - * - the caller must have the {MinterRole}. - */ - function mint(address account, uint256 amount) public onlyMinter returns (bool) { - _mint(account, amount); - return true; - } -} diff --git a/contracts/token/ERC20/ERC20Pausable.sol b/contracts/token/ERC20/ERC20Pausable.sol index 5e8641ebc..f11d6676d 100644 --- a/contracts/token/ERC20/ERC20Pausable.sol +++ b/contracts/token/ERC20/ERC20Pausable.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "./ERC20.sol"; import "../../lifecycle/Pausable.sol"; @@ -12,23 +12,16 @@ import "../../lifecycle/Pausable.sol"; * bug. */ contract ERC20Pausable is ERC20, Pausable { - function transfer(address to, uint256 value) public whenNotPaused returns (bool) { - return super.transfer(to, value); - } + /** + * @dev See {ERC20-_beforeTokenTransfer}. + * + * Requirements: + * + * - the contract must not be paused. + */ + function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override { + super._beforeTokenTransfer(from, to, amount); - function transferFrom(address from, address to, uint256 value) public whenNotPaused returns (bool) { - return super.transferFrom(from, to, value); - } - - function approve(address spender, uint256 value) public whenNotPaused returns (bool) { - return super.approve(spender, value); - } - - function increaseAllowance(address spender, uint256 addedValue) public whenNotPaused returns (bool) { - return super.increaseAllowance(spender, addedValue); - } - - function decreaseAllowance(address spender, uint256 subtractedValue) public whenNotPaused returns (bool) { - return super.decreaseAllowance(spender, subtractedValue); + require(!paused(), "ERC20Pausable: token transfer while paused"); } } diff --git a/contracts/token/ERC20/IERC20.sol b/contracts/token/ERC20/IERC20.sol index bf5245ff0..462fa5437 100644 --- a/contracts/token/ERC20/IERC20.sol +++ b/contracts/token/ERC20/IERC20.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. Does not include diff --git a/contracts/token/ERC20/SafeERC20.sol b/contracts/token/ERC20/SafeERC20.sol index 8cbc7b2f7..b3dab1288 100644 --- a/contracts/token/ERC20/SafeERC20.sol +++ b/contracts/token/ERC20/SafeERC20.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "./IERC20.sol"; import "../../math/SafeMath.sol"; diff --git a/contracts/token/ERC20/TokenTimelock.sol b/contracts/token/ERC20/TokenTimelock.sol index 542b22d83..3f398b16b 100644 --- a/contracts/token/ERC20/TokenTimelock.sol +++ b/contracts/token/ERC20/TokenTimelock.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "./SafeERC20.sol"; @@ -55,7 +55,7 @@ contract TokenTimelock { /** * @notice Transfers tokens held by timelock to beneficiary. */ - function release() public { + function release() public virtual { // solhint-disable-next-line not-rely-on-time require(block.timestamp >= _releaseTime, "TokenTimelock: current time is before release time"); diff --git a/contracts/token/ERC721/ERC721.sol b/contracts/token/ERC721/ERC721.sol index 67742b842..b8470fa9e 100644 --- a/contracts/token/ERC721/ERC721.sol +++ b/contracts/token/ERC721/ERC721.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../../GSN/Context.sol"; import "./IERC721.sol"; @@ -59,7 +59,7 @@ contract ERC721 is Context, ERC165, IERC721 { * @param owner address to query the balance of * @return uint256 representing the amount owned by the passed address */ - function balanceOf(address owner) public view returns (uint256) { + function balanceOf(address owner) public view override returns (uint256) { require(owner != address(0), "ERC721: balance query for the zero address"); return _ownedTokensCount[owner].current(); @@ -70,7 +70,7 @@ contract ERC721 is Context, ERC165, IERC721 { * @param tokenId uint256 ID of the token to query the owner of * @return address currently marked as the owner of the given token ID */ - function ownerOf(uint256 tokenId) public view returns (address) { + function ownerOf(uint256 tokenId) public view override returns (address) { address owner = _tokenOwner[tokenId]; require(owner != address(0), "ERC721: owner query for nonexistent token"); @@ -85,7 +85,7 @@ contract ERC721 is Context, ERC165, IERC721 { * @param to address to be approved for the given token ID * @param tokenId uint256 ID of the token to be approved */ - function approve(address to, uint256 tokenId) public { + function approve(address to, uint256 tokenId) public virtual override { address owner = ownerOf(tokenId); require(to != owner, "ERC721: approval to current owner"); @@ -93,8 +93,7 @@ contract ERC721 is Context, ERC165, IERC721 { "ERC721: approve caller is not owner nor approved for all" ); - _tokenApprovals[tokenId] = to; - emit Approval(owner, to, tokenId); + _approve(to, tokenId); } /** @@ -103,7 +102,7 @@ contract ERC721 is Context, ERC165, IERC721 { * @param tokenId uint256 ID of the token to query the approval of * @return address currently approved for the given token ID */ - function getApproved(uint256 tokenId) public view returns (address) { + function getApproved(uint256 tokenId) public view override returns (address) { require(_exists(tokenId), "ERC721: approved query for nonexistent token"); return _tokenApprovals[tokenId]; @@ -112,14 +111,14 @@ contract ERC721 is Context, ERC165, IERC721 { /** * @dev Sets or unsets the approval of a given operator * An operator is allowed to transfer all tokens of the sender on their behalf. - * @param to operator address to set the approval + * @param operator operator address to set the approval * @param approved representing the status of the approval to be set */ - function setApprovalForAll(address to, bool approved) public { - require(to != _msgSender(), "ERC721: approve to caller"); + function setApprovalForAll(address operator, bool approved) public virtual override { + require(operator != _msgSender(), "ERC721: approve to caller"); - _operatorApprovals[_msgSender()][to] = approved; - emit ApprovalForAll(_msgSender(), to, approved); + _operatorApprovals[_msgSender()][operator] = approved; + emit ApprovalForAll(_msgSender(), operator, approved); } /** @@ -128,7 +127,7 @@ contract ERC721 is Context, ERC165, IERC721 { * @param operator operator address which you want to query the approval of * @return bool whether the given operator is approved by the given owner */ - function isApprovedForAll(address owner, address operator) public view returns (bool) { + function isApprovedForAll(address owner, address operator) public view override returns (bool) { return _operatorApprovals[owner][operator]; } @@ -140,7 +139,7 @@ contract ERC721 is Context, ERC165, IERC721 { * @param to address to receive the ownership of the given token ID * @param tokenId uint256 ID of the token to be transferred */ - function transferFrom(address from, address to, uint256 tokenId) public { + function transferFrom(address from, address to, uint256 tokenId) public virtual override { //solhint-disable-next-line max-line-length require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); @@ -158,7 +157,7 @@ contract ERC721 is Context, ERC165, IERC721 { * @param to address to receive the ownership of the given token ID * @param tokenId uint256 ID of the token to be transferred */ - function safeTransferFrom(address from, address to, uint256 tokenId) public { + function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override { safeTransferFrom(from, to, tokenId, ""); } @@ -174,7 +173,7 @@ contract ERC721 is Context, ERC165, IERC721 { * @param tokenId uint256 ID of the token to be transferred * @param _data bytes data to send along with a safe transfer check */ - function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public { + function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public virtual override { require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); _safeTransferFrom(from, to, tokenId, _data); } @@ -191,7 +190,7 @@ contract ERC721 is Context, ERC165, IERC721 { * @param tokenId uint256 ID of the token to be transferred * @param _data bytes data to send along with a safe transfer check */ - function _safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) internal { + function _safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) internal virtual { _transferFrom(from, to, tokenId); require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); } @@ -229,7 +228,7 @@ contract ERC721 is Context, ERC165, IERC721 { * @param to The address that will own the minted token * @param tokenId uint256 ID of the token to be minted */ - function _safeMint(address to, uint256 tokenId) internal { + function _safeMint(address to, uint256 tokenId) internal virtual { _safeMint(to, tokenId, ""); } @@ -244,7 +243,7 @@ contract ERC721 is Context, ERC165, IERC721 { * @param tokenId uint256 ID of the token to be minted * @param _data bytes data to send along with a safe transfer check */ - function _safeMint(address to, uint256 tokenId, bytes memory _data) internal { + function _safeMint(address to, uint256 tokenId, bytes memory _data) internal virtual { _mint(to, tokenId); require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); } @@ -255,10 +254,12 @@ contract ERC721 is Context, ERC165, IERC721 { * @param to The address that will own the minted token * @param tokenId uint256 ID of the token to be minted */ - function _mint(address to, uint256 tokenId) internal { + function _mint(address to, uint256 tokenId) internal virtual { require(to != address(0), "ERC721: mint to the zero address"); require(!_exists(tokenId), "ERC721: token already minted"); + _beforeTokenTransfer(address(0), to, tokenId); + _tokenOwner[tokenId] = to; _ownedTokensCount[to].increment(); @@ -272,10 +273,13 @@ contract ERC721 is Context, ERC165, IERC721 { * @param owner owner of the token to burn * @param tokenId uint256 ID of the token being burned */ - function _burn(address owner, uint256 tokenId) internal { + function _burn(address owner, uint256 tokenId) internal virtual { require(ownerOf(tokenId) == owner, "ERC721: burn of token that is not own"); - _clearApproval(tokenId); + _beforeTokenTransfer(owner, address(0), tokenId); + + // Clear approvals + _approve(address(0), tokenId); _ownedTokensCount[owner].decrement(); _tokenOwner[tokenId] = address(0); @@ -288,7 +292,7 @@ contract ERC721 is Context, ERC165, IERC721 { * Reverts if the token does not exist. * @param tokenId uint256 ID of the token being burned */ - function _burn(uint256 tokenId) internal { + function _burn(uint256 tokenId) internal virtual { _burn(ownerOf(tokenId), tokenId); } @@ -299,11 +303,14 @@ contract ERC721 is Context, ERC165, IERC721 { * @param to address to receive the ownership of the given token ID * @param tokenId uint256 ID of the token to be transferred */ - function _transferFrom(address from, address to, uint256 tokenId) internal { + function _transferFrom(address from, address to, uint256 tokenId) internal virtual { require(ownerOf(tokenId) == from, "ERC721: transfer of token that is not own"); require(to != address(0), "ERC721: transfer to the zero address"); - _clearApproval(tokenId); + _beforeTokenTransfer(from, to, tokenId); + + // Clear approvals + _approve(address(0), tokenId); _ownedTokensCount[from].decrement(); _ownedTokensCount[to].increment(); @@ -325,7 +332,7 @@ contract ERC721 is Context, ERC165, IERC721 { * @return bool whether the call correctly returned the expected magic value */ function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data) - internal returns (bool) + internal virtual returns (bool) { if (!to.isContract()) { return true; @@ -354,13 +361,24 @@ contract ERC721 is Context, ERC165, IERC721 { } } - /** - * @dev Private function to clear current approval of a given token ID. - * @param tokenId uint256 ID of the token to be transferred - */ - function _clearApproval(uint256 tokenId) private { - if (_tokenApprovals[tokenId] != address(0)) { - _tokenApprovals[tokenId] = address(0); - } + function _approve(address to, uint256 tokenId) private { + _tokenApprovals[tokenId] = to; + emit Approval(ownerOf(tokenId), to, tokenId); } + + /** + * @dev Hook that is called before any token transfer. This includes minting + * and burning. + * + * Calling conditions: + * + * - when `from` and `to` are both non-zero, `from`'s `tokenId` will be + * transferred to `to`. + * - when `from` is zero, `tokenId` will be minted for `to`. + * - when `to` is zero, `from`'s `tokenId` will be burned. + * - `from` and `to` are never both zero. + * + * To learn more about hooks, head to xref:ROOT:using-hooks.adoc[Using Hooks]. + */ + function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual { } } diff --git a/contracts/token/ERC721/ERC721Burnable.sol b/contracts/token/ERC721/ERC721Burnable.sol index e35796b9e..5c6e3efab 100644 --- a/contracts/token/ERC721/ERC721Burnable.sol +++ b/contracts/token/ERC721/ERC721Burnable.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../../GSN/Context.sol"; import "./ERC721.sol"; @@ -12,7 +12,7 @@ contract ERC721Burnable is Context, ERC721 { * @dev Burns a specific ERC721 token. * @param tokenId uint256 id of the ERC721 token to be burned. */ - function burn(uint256 tokenId) public { + function burn(uint256 tokenId) public virtual { //solhint-disable-next-line max-line-length require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721Burnable: caller is not owner nor approved"); _burn(tokenId); diff --git a/contracts/token/ERC721/ERC721Enumerable.sol b/contracts/token/ERC721/ERC721Enumerable.sol index ff7a15843..2a2508622 100644 --- a/contracts/token/ERC721/ERC721Enumerable.sol +++ b/contracts/token/ERC721/ERC721Enumerable.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../../GSN/Context.sol"; import "./IERC721Enumerable.sol"; @@ -45,7 +45,7 @@ contract ERC721Enumerable is Context, ERC165, ERC721, IERC721Enumerable { * @param index uint256 representing the index to be accessed of the requested tokens list * @return uint256 token ID at the given index of the tokens list owned by the requested address */ - function tokenOfOwnerByIndex(address owner, uint256 index) public view returns (uint256) { + function tokenOfOwnerByIndex(address owner, uint256 index) public view override returns (uint256) { require(index < balanceOf(owner), "ERC721Enumerable: owner index out of bounds"); return _ownedTokens[owner][index]; } @@ -54,7 +54,7 @@ contract ERC721Enumerable is Context, ERC165, ERC721, IERC721Enumerable { * @dev Gets the total amount of tokens stored by the contract. * @return uint256 representing the total amount of tokens */ - function totalSupply() public view returns (uint256) { + function totalSupply() public view override returns (uint256) { return _allTokens.length; } @@ -64,55 +64,29 @@ contract ERC721Enumerable is Context, ERC165, ERC721, IERC721Enumerable { * @param index uint256 representing the index to be accessed of the tokens list * @return uint256 token ID at the given index of the tokens list */ - function tokenByIndex(uint256 index) public view returns (uint256) { + function tokenByIndex(uint256 index) public view override returns (uint256) { require(index < totalSupply(), "ERC721Enumerable: global index out of bounds"); return _allTokens[index]; } - /** - * @dev Internal function to transfer ownership of a given token ID to another address. - * As opposed to transferFrom, this imposes no restrictions on msg.sender. - * @param from current owner of the token - * @param to address to receive the ownership of the given token ID - * @param tokenId uint256 ID of the token to be transferred - */ - function _transferFrom(address from, address to, uint256 tokenId) internal { - super._transferFrom(from, to, tokenId); + function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual override { + super._beforeTokenTransfer(from, to, tokenId); - _removeTokenFromOwnerEnumeration(from, tokenId); + if (from == address(0)) { + // When minting + _addTokenToOwnerEnumeration(to, tokenId); + _addTokenToAllTokensEnumeration(tokenId); + } else if (to == address(0)) { + // When burning + _removeTokenFromOwnerEnumeration(from, tokenId); + // Since tokenId will be deleted, we can clear its slot in _ownedTokensIndex to trigger a gas refund + _ownedTokensIndex[tokenId] = 0; - _addTokenToOwnerEnumeration(to, tokenId); - } - - /** - * @dev Internal function to mint a new token. - * Reverts if the given token ID already exists. - * @param to address the beneficiary that will own the minted token - * @param tokenId uint256 ID of the token to be minted - */ - function _mint(address to, uint256 tokenId) internal { - super._mint(to, tokenId); - - _addTokenToOwnerEnumeration(to, tokenId); - - _addTokenToAllTokensEnumeration(tokenId); - } - - /** - * @dev Internal function to burn a specific token. - * Reverts if the token does not exist. - * Deprecated, use {ERC721-_burn} instead. - * @param owner owner of the token to burn - * @param tokenId uint256 ID of the token being burned - */ - function _burn(address owner, uint256 tokenId) internal { - super._burn(owner, tokenId); - - _removeTokenFromOwnerEnumeration(owner, tokenId); - // Since tokenId will be deleted, we can clear its slot in _ownedTokensIndex to trigger a gas refund - _ownedTokensIndex[tokenId] = 0; - - _removeTokenFromAllTokensEnumeration(tokenId); + _removeTokenFromAllTokensEnumeration(tokenId); + } else { + _removeTokenFromOwnerEnumeration(from, tokenId); + _addTokenToOwnerEnumeration(to, tokenId); + } } /** @@ -166,8 +140,8 @@ contract ERC721Enumerable is Context, ERC165, ERC721, IERC721Enumerable { _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index } - // This also deletes the contents at the last position of the array - _ownedTokens[from].length--; + // Deletes the contents at the last position of the array + _ownedTokens[from].pop(); // Note that _ownedTokensIndex[tokenId] hasn't been cleared: it still points to the old slot (now occupied by // lastTokenId, or just over the end of the array if the token was the last one). @@ -193,8 +167,9 @@ contract ERC721Enumerable is Context, ERC165, ERC721, IERC721Enumerable { _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index - // This also deletes the contents at the last position of the array - _allTokens.length--; + // Delete the contents at the last position of the array + _allTokens.pop(); + _allTokensIndex[tokenId] = 0; } } diff --git a/contracts/token/ERC721/ERC721Full.sol b/contracts/token/ERC721/ERC721Full.sol index a6fce2734..f22845b6e 100644 --- a/contracts/token/ERC721/ERC721Full.sol +++ b/contracts/token/ERC721/ERC721Full.sol @@ -1,6 +1,5 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; -import "./ERC721.sol"; import "./ERC721Enumerable.sol"; import "./ERC721Metadata.sol"; @@ -11,8 +10,14 @@ import "./ERC721Metadata.sol"; * * See https://eips.ethereum.org/EIPS/eip-721 */ -contract ERC721Full is ERC721, ERC721Enumerable, ERC721Metadata { - constructor (string memory name, string memory symbol) public ERC721Metadata(name, symbol) { - // solhint-disable-previous-line no-empty-blocks +contract ERC721Full is ERC721Enumerable, ERC721Metadata { + constructor (string memory name, string memory symbol) public ERC721Metadata(name, symbol) { } + + function _beforeTokenTransfer(address from, address to, uint256 tokenId) + virtual + override(ERC721Enumerable, ERC721Metadata) + internal + { + super._beforeTokenTransfer(from, to, tokenId); } } diff --git a/contracts/token/ERC721/ERC721Holder.sol b/contracts/token/ERC721/ERC721Holder.sol index bcc10d7e2..ab2dbfc00 100644 --- a/contracts/token/ERC721/ERC721Holder.sol +++ b/contracts/token/ERC721/ERC721Holder.sol @@ -1,9 +1,9 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "./IERC721Receiver.sol"; contract ERC721Holder is IERC721Receiver { - function onERC721Received(address, address, uint256, bytes memory) public returns (bytes4) { + function onERC721Received(address, address, uint256, bytes memory) public virtual override returns (bytes4) { return this.onERC721Received.selector; } } diff --git a/contracts/token/ERC721/ERC721Metadata.sol b/contracts/token/ERC721/ERC721Metadata.sol index c83b5e16f..7a8b1259a 100644 --- a/contracts/token/ERC721/ERC721Metadata.sol +++ b/contracts/token/ERC721/ERC721Metadata.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../../GSN/Context.sol"; import "./ERC721.sol"; @@ -42,7 +42,7 @@ contract ERC721Metadata is Context, ERC165, ERC721, IERC721Metadata { * @dev Gets the token name. * @return string representing the token name */ - function name() external view returns (string memory) { + function name() external view override returns (string memory) { return _name; } @@ -50,7 +50,7 @@ contract ERC721Metadata is Context, ERC165, ERC721, IERC721Metadata { * @dev Gets the token symbol. * @return string representing the token symbol */ - function symbol() external view returns (string memory) { + function symbol() external view override returns (string memory) { return _symbol; } @@ -62,7 +62,7 @@ contract ERC721Metadata is Context, ERC165, ERC721, IERC721Metadata { * * Reverts if the token ID does not exist. */ - function tokenURI(uint256 tokenId) external view returns (string memory) { + function tokenURI(uint256 tokenId) external view override returns (string memory) { require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token"); string memory _tokenURI = _tokenURIs[tokenId]; @@ -85,7 +85,7 @@ contract ERC721Metadata is Context, ERC165, ERC721, IERC721Metadata { * `http://api.myproject.com/token/`), use {_setBaseURI} to store * it and save gas. */ - function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal { + function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual { require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token"); _tokenURIs[tokenId] = _tokenURI; } @@ -96,7 +96,7 @@ contract ERC721Metadata is Context, ERC165, ERC721, IERC721Metadata { * * _Available since v2.5.0._ */ - function _setBaseURI(string memory baseURI) internal { + function _setBaseURI(string memory baseURI) internal virtual { _baseURI = baseURI; } @@ -111,19 +111,15 @@ contract ERC721Metadata is Context, ERC165, ERC721, IERC721Metadata { return _baseURI; } - /** - * @dev Internal function to burn a specific token. - * Reverts if the token does not exist. - * Deprecated, use _burn(uint256) instead. - * @param owner owner of the token to burn - * @param tokenId uint256 ID of the token being burned by the msg.sender - */ - function _burn(address owner, uint256 tokenId) internal { - super._burn(owner, tokenId); - // Clear metadata (if any) - if (bytes(_tokenURIs[tokenId]).length != 0) { - delete _tokenURIs[tokenId]; + function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual override { + super._beforeTokenTransfer(from, to, tokenId); + + if (to == address(0)) { // When burning tokens + // Clear metadata (if any) + if (bytes(_tokenURIs[tokenId]).length != 0) { + delete _tokenURIs[tokenId]; + } } } } diff --git a/contracts/token/ERC721/ERC721MetadataMintable.sol b/contracts/token/ERC721/ERC721MetadataMintable.sol deleted file mode 100644 index a1421d1dd..000000000 --- a/contracts/token/ERC721/ERC721MetadataMintable.sol +++ /dev/null @@ -1,24 +0,0 @@ -pragma solidity ^0.5.0; - -import "./ERC721Metadata.sol"; -import "../../access/roles/MinterRole.sol"; - - -/** - * @title ERC721MetadataMintable - * @dev ERC721 minting logic with metadata. - */ -contract ERC721MetadataMintable is ERC721, ERC721Metadata, MinterRole { - /** - * @dev Function to mint tokens. - * @param to The address that will receive the minted tokens. - * @param tokenId The token id to mint. - * @param tokenURI The token URI of the minted token. - * @return A boolean that indicates if the operation was successful. - */ - function mintWithTokenURI(address to, uint256 tokenId, string memory tokenURI) public onlyMinter returns (bool) { - _mint(to, tokenId); - _setTokenURI(tokenId, tokenURI); - return true; - } -} diff --git a/contracts/token/ERC721/ERC721Mintable.sol b/contracts/token/ERC721/ERC721Mintable.sol deleted file mode 100644 index faed7ad85..000000000 --- a/contracts/token/ERC721/ERC721Mintable.sol +++ /dev/null @@ -1,44 +0,0 @@ -pragma solidity ^0.5.0; - -import "./ERC721.sol"; -import "../../access/roles/MinterRole.sol"; - -/** - * @title ERC721Mintable - * @dev ERC721 minting logic. - */ -contract ERC721Mintable is ERC721, MinterRole { - /** - * @dev Function to mint tokens. - * @param to The address that will receive the minted token. - * @param tokenId The token id to mint. - * @return A boolean that indicates if the operation was successful. - */ - function mint(address to, uint256 tokenId) public onlyMinter returns (bool) { - _mint(to, tokenId); - return true; - } - - /** - * @dev Function to safely mint tokens. - * @param to The address that will receive the minted token. - * @param tokenId The token id to mint. - * @return A boolean that indicates if the operation was successful. - */ - function safeMint(address to, uint256 tokenId) public onlyMinter returns (bool) { - _safeMint(to, tokenId); - return true; - } - - /** - * @dev Function to safely mint tokens. - * @param to The address that will receive the minted token. - * @param tokenId The token id to mint. - * @param _data bytes data to send along with a safe transfer check. - * @return A boolean that indicates if the operation was successful. - */ - function safeMint(address to, uint256 tokenId, bytes memory _data) public onlyMinter returns (bool) { - _safeMint(to, tokenId, _data); - return true; - } -} diff --git a/contracts/token/ERC721/ERC721Pausable.sol b/contracts/token/ERC721/ERC721Pausable.sol index 5080d3808..efe9309be 100644 --- a/contracts/token/ERC721/ERC721Pausable.sol +++ b/contracts/token/ERC721/ERC721Pausable.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "./ERC721.sol"; import "../../lifecycle/Pausable.sol"; @@ -8,15 +8,9 @@ import "../../lifecycle/Pausable.sol"; * @dev ERC721 modified with pausable transfers. */ contract ERC721Pausable is ERC721, Pausable { - function approve(address to, uint256 tokenId) public whenNotPaused { - super.approve(to, tokenId); - } + function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual override { + super._beforeTokenTransfer(from, to, tokenId); - function setApprovalForAll(address to, bool approved) public whenNotPaused { - super.setApprovalForAll(to, approved); - } - - function _transferFrom(address from, address to, uint256 tokenId) internal whenNotPaused { - super._transferFrom(from, to, tokenId); + require(!paused(), "ERC721Pausable: token transfer while paused"); } } diff --git a/contracts/token/ERC721/IERC721.sol b/contracts/token/ERC721/IERC721.sol index b8efac231..e4c9a78e2 100644 --- a/contracts/token/ERC721/IERC721.sol +++ b/contracts/token/ERC721/IERC721.sol @@ -1,11 +1,11 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../../introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ -contract IERC721 is IERC165 { +abstract contract IERC721 is IERC165 { event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); event ApprovalForAll(address indexed owner, address indexed operator, bool approved); @@ -13,12 +13,12 @@ contract IERC721 is IERC165 { /** * @dev Returns the number of NFTs in `owner`'s account. */ - function balanceOf(address owner) public view returns (uint256 balance); + function balanceOf(address owner) public view virtual returns (uint256 balance); /** * @dev Returns the owner of the NFT specified by `tokenId`. */ - function ownerOf(uint256 tokenId) public view returns (address owner); + function ownerOf(uint256 tokenId) public view virtual returns (address owner); /** * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to @@ -32,7 +32,7 @@ contract IERC721 is IERC165 { * - If the caller is not `from`, it must be have been allowed to move this * NFT by either {approve} or {setApprovalForAll}. */ - function safeTransferFrom(address from, address to, uint256 tokenId) public; + function safeTransferFrom(address from, address to, uint256 tokenId) public virtual; /** * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to * another (`to`). @@ -41,13 +41,13 @@ contract IERC721 is IERC165 { * - If the caller is not `from`, it must be approved to move this NFT by * either {approve} or {setApprovalForAll}. */ - function transferFrom(address from, address to, uint256 tokenId) public; - function approve(address to, uint256 tokenId) public; - function getApproved(uint256 tokenId) public view returns (address operator); + function transferFrom(address from, address to, uint256 tokenId) public virtual; + function approve(address to, uint256 tokenId) public virtual; + function getApproved(uint256 tokenId) public view virtual returns (address operator); - function setApprovalForAll(address operator, bool _approved) public; - function isApprovedForAll(address owner, address operator) public view returns (bool); + function setApprovalForAll(address operator, bool _approved) public virtual; + function isApprovedForAll(address owner, address operator) public view virtual returns (bool); - function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public; + function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public virtual; } diff --git a/contracts/token/ERC721/IERC721Enumerable.sol b/contracts/token/ERC721/IERC721Enumerable.sol index 4c1dfb564..1fd35f401 100644 --- a/contracts/token/ERC721/IERC721Enumerable.sol +++ b/contracts/token/ERC721/IERC721Enumerable.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "./IERC721.sol"; @@ -6,9 +6,9 @@ import "./IERC721.sol"; * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ -contract IERC721Enumerable is IERC721 { - function totalSupply() public view returns (uint256); - function tokenOfOwnerByIndex(address owner, uint256 index) public view returns (uint256 tokenId); +abstract contract IERC721Enumerable is IERC721 { + function totalSupply() public view virtual returns (uint256); + function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual returns (uint256 tokenId); - function tokenByIndex(uint256 index) public view returns (uint256); + function tokenByIndex(uint256 index) public view virtual returns (uint256); } diff --git a/contracts/token/ERC721/IERC721Full.sol b/contracts/token/ERC721/IERC721Full.sol index e543aefeb..af4ee87f6 100644 --- a/contracts/token/ERC721/IERC721Full.sol +++ b/contracts/token/ERC721/IERC721Full.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "./IERC721.sol"; import "./IERC721Enumerable.sol"; @@ -8,6 +8,4 @@ import "./IERC721Metadata.sol"; * @title ERC-721 Non-Fungible Token Standard, full implementation interface * @dev See https://eips.ethereum.org/EIPS/eip-721 */ -contract IERC721Full is IERC721, IERC721Enumerable, IERC721Metadata { - // solhint-disable-previous-line no-empty-blocks -} +abstract contract IERC721Full is IERC721, IERC721Enumerable, IERC721Metadata { } diff --git a/contracts/token/ERC721/IERC721Metadata.sol b/contracts/token/ERC721/IERC721Metadata.sol index 05835aff8..7c0c16619 100644 --- a/contracts/token/ERC721/IERC721Metadata.sol +++ b/contracts/token/ERC721/IERC721Metadata.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "./IERC721.sol"; @@ -6,8 +6,8 @@ import "./IERC721.sol"; * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ -contract IERC721Metadata is IERC721 { - function name() external view returns (string memory); - function symbol() external view returns (string memory); - function tokenURI(uint256 tokenId) external view returns (string memory); +abstract contract IERC721Metadata is IERC721 { + function name() external view virtual returns (string memory); + function symbol() external view virtual returns (string memory); + function tokenURI(uint256 tokenId) external view virtual returns (string memory); } diff --git a/contracts/token/ERC721/IERC721Receiver.sol b/contracts/token/ERC721/IERC721Receiver.sol index 94eeb75cf..d1b2e23e0 100644 --- a/contracts/token/ERC721/IERC721Receiver.sol +++ b/contracts/token/ERC721/IERC721Receiver.sol @@ -1,11 +1,11 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ -contract IERC721Receiver { +abstract contract IERC721Receiver { /** * @notice Handle the receipt of an NFT * @dev The ERC721 smart contract calls this function on the recipient @@ -21,5 +21,5 @@ contract IERC721Receiver { * @return bytes4 `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` */ function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data) - public returns (bytes4); + public virtual returns (bytes4); } diff --git a/contracts/token/ERC777/ERC777.sol b/contracts/token/ERC777/ERC777.sol index 2a91f25df..26e03efb9 100644 --- a/contracts/token/ERC777/ERC777.sol +++ b/contracts/token/ERC777/ERC777.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../../GSN/Context.sol"; import "./IERC777.sol"; @@ -85,14 +85,14 @@ contract ERC777 is Context, IERC777, IERC20 { /** * @dev See {IERC777-name}. */ - function name() public view returns (string memory) { + function name() public view override returns (string memory) { return _name; } /** * @dev See {IERC777-symbol}. */ - function symbol() public view returns (string memory) { + function symbol() public view override returns (string memory) { return _symbol; } @@ -111,21 +111,21 @@ contract ERC777 is Context, IERC777, IERC20 { * * This implementation always returns `1`. */ - function granularity() public view returns (uint256) { + function granularity() public view override returns (uint256) { return 1; } /** * @dev See {IERC777-totalSupply}. */ - function totalSupply() public view returns (uint256) { + function totalSupply() public view override(IERC20, IERC777) returns (uint256) { return _totalSupply; } /** * @dev Returns the amount of tokens owned by an account (`tokenHolder`). */ - function balanceOf(address tokenHolder) public view returns (uint256) { + function balanceOf(address tokenHolder) public view override(IERC20, IERC777) returns (uint256) { return _balances[tokenHolder]; } @@ -134,7 +134,7 @@ contract ERC777 is Context, IERC777, IERC20 { * * Also emits a {IERC20-Transfer} event for ERC20 compatibility. */ - function send(address recipient, uint256 amount, bytes memory data) public { + function send(address recipient, uint256 amount, bytes memory data) public override { _send(_msgSender(), _msgSender(), recipient, amount, data, "", true); } @@ -146,7 +146,7 @@ contract ERC777 is Context, IERC777, IERC20 { * * Also emits a {Sent} event. */ - function transfer(address recipient, uint256 amount) public returns (bool) { + function transfer(address recipient, uint256 amount) public override returns (bool) { require(recipient != address(0), "ERC777: transfer to the zero address"); address from = _msgSender(); @@ -165,7 +165,7 @@ contract ERC777 is Context, IERC777, IERC20 { * * Also emits a {IERC20-Transfer} event for ERC20 compatibility. */ - function burn(uint256 amount, bytes memory data) public { + function burn(uint256 amount, bytes memory data) public override { _burn(_msgSender(), _msgSender(), amount, data, ""); } @@ -175,7 +175,7 @@ contract ERC777 is Context, IERC777, IERC20 { function isOperatorFor( address operator, address tokenHolder - ) public view returns (bool) { + ) public view override returns (bool) { return operator == tokenHolder || (_defaultOperators[operator] && !_revokedDefaultOperators[tokenHolder][operator]) || _operators[tokenHolder][operator]; @@ -184,7 +184,7 @@ contract ERC777 is Context, IERC777, IERC20 { /** * @dev See {IERC777-authorizeOperator}. */ - function authorizeOperator(address operator) public { + function authorizeOperator(address operator) public override { require(_msgSender() != operator, "ERC777: authorizing self as operator"); if (_defaultOperators[operator]) { @@ -199,7 +199,7 @@ contract ERC777 is Context, IERC777, IERC20 { /** * @dev See {IERC777-revokeOperator}. */ - function revokeOperator(address operator) public { + function revokeOperator(address operator) public override { require(operator != _msgSender(), "ERC777: revoking self as operator"); if (_defaultOperators[operator]) { @@ -214,7 +214,7 @@ contract ERC777 is Context, IERC777, IERC20 { /** * @dev See {IERC777-defaultOperators}. */ - function defaultOperators() public view returns (address[] memory) { + function defaultOperators() public view override returns (address[] memory) { return _defaultOperatorsArray; } @@ -230,7 +230,7 @@ contract ERC777 is Context, IERC777, IERC20 { bytes memory data, bytes memory operatorData ) - public + public override { require(isOperatorFor(_msgSender(), sender), "ERC777: caller is not an operator for holder"); _send(_msgSender(), sender, recipient, amount, data, operatorData, true); @@ -241,7 +241,7 @@ contract ERC777 is Context, IERC777, IERC20 { * * Emits {Burned} and {IERC20-Transfer} events. */ - function operatorBurn(address account, uint256 amount, bytes memory data, bytes memory operatorData) public { + function operatorBurn(address account, uint256 amount, bytes memory data, bytes memory operatorData) public override { require(isOperatorFor(_msgSender(), account), "ERC777: caller is not an operator for holder"); _burn(_msgSender(), account, amount, data, operatorData); } @@ -253,7 +253,7 @@ contract ERC777 is Context, IERC777, IERC20 { * not have allowance, and accounts with allowance may not be operators * themselves. */ - function allowance(address holder, address spender) public view returns (uint256) { + function allowance(address holder, address spender) public view override returns (uint256) { return _allowances[holder][spender]; } @@ -262,7 +262,7 @@ contract ERC777 is Context, IERC777, IERC20 { * * Note that accounts cannot have allowance issued by their operators. */ - function approve(address spender, uint256 value) public returns (bool) { + function approve(address spender, uint256 value) public override returns (bool) { address holder = _msgSender(); _approve(holder, spender, value); return true; @@ -277,7 +277,7 @@ contract ERC777 is Context, IERC777, IERC20 { * * Emits {Sent}, {IERC20-Transfer} and {IERC20-Approval} events. */ - function transferFrom(address holder, address recipient, uint256 amount) public returns (bool) { + function transferFrom(address holder, address recipient, uint256 amount) public override returns (bool) { require(recipient != address(0), "ERC777: transfer to the zero address"); require(holder != address(0), "ERC777: transfer from the zero address"); @@ -317,7 +317,7 @@ contract ERC777 is Context, IERC777, IERC20 { bytes memory userData, bytes memory operatorData ) - internal + internal virtual { require(account != address(0), "ERC777: mint to the zero address"); @@ -377,7 +377,7 @@ contract ERC777 is Context, IERC777, IERC20 { bytes memory data, bytes memory operatorData ) - internal + internal virtual { require(from != address(0), "ERC777: burn from the zero address"); @@ -401,6 +401,8 @@ contract ERC777 is Context, IERC777, IERC20 { ) private { + _beforeTokenTransfer(operator, from, to, amount); + _balances[from] = _balances[from].sub(amount, "ERC777: transfer amount exceeds balance"); _balances[to] = _balances[to].add(amount); @@ -472,4 +474,20 @@ contract ERC777 is Context, IERC777, IERC20 { require(!to.isContract(), "ERC777: token recipient contract has no implementer for ERC777TokensRecipient"); } } + + /** + * @dev Hook that is called before any token transfer. This includes + * calls to {send}, {transfer}, {operatorSend}, minting and burning. + * + * Calling conditions: + * + * - when `from` and `to` are both non-zero, `from`'s `tokenId` will be + * transferred to `to`. + * - when `from` is zero, `tokenId` will be minted for `to`. + * - when `to` is zero, `from`'s `tokenId` will be burned. + * - `from` and `to` are never both zero. + * + * To learn more about hooks, head to xref:ROOT:using-hooks.adoc[Using Hooks]. + */ + function _beforeTokenTransfer(address operator, address from, address to, uint256 tokenId) internal virtual { } } diff --git a/contracts/token/ERC777/IERC777.sol b/contracts/token/ERC777/IERC777.sol index b7f60da9c..f4a6e2cdd 100644 --- a/contracts/token/ERC777/IERC777.sol +++ b/contracts/token/ERC777/IERC777.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; /** * @dev Interface of the ERC777Token standard as defined in the EIP. diff --git a/contracts/token/ERC777/IERC777Recipient.sol b/contracts/token/ERC777/IERC777Recipient.sol index bde2e7c54..96fe7b4a6 100644 --- a/contracts/token/ERC777/IERC777Recipient.sol +++ b/contracts/token/ERC777/IERC777Recipient.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; /** * @dev Interface of the ERC777TokensRecipient standard as defined in the EIP. diff --git a/contracts/token/ERC777/IERC777Sender.sol b/contracts/token/ERC777/IERC777Sender.sol index d0662ca1d..358bacb65 100644 --- a/contracts/token/ERC777/IERC777Sender.sol +++ b/contracts/token/ERC777/IERC777Sender.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; /** * @dev Interface of the ERC777TokensSender standard as defined in the EIP. diff --git a/contracts/utils/Address.sol b/contracts/utils/Address.sol index 3dc496d40..d31cf5c54 100644 --- a/contracts/utils/Address.sol +++ b/contracts/utils/Address.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.5; +pragma solidity ^0.6.0; /** * @dev Collection of functions related to the address type @@ -12,7 +12,7 @@ library Address { * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * - * Among others, `isContract` will return false for the following + * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account @@ -63,7 +63,7 @@ library Address { function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); - // solhint-disable-next-line avoid-call-value + // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call.value(amount)(""); require(success, "Address: unable to send value, recipient may have reverted"); } diff --git a/contracts/utils/Arrays.sol b/contracts/utils/Arrays.sol index eb0deb169..3b4013781 100644 --- a/contracts/utils/Arrays.sol +++ b/contracts/utils/Arrays.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; import "../math/Math.sol"; diff --git a/contracts/utils/Create2.sol b/contracts/utils/Create2.sol index e055ea85b..4361fddf5 100644 --- a/contracts/utils/Create2.sol +++ b/contracts/utils/Create2.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; /** * @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer. diff --git a/contracts/utils/EnumerableSet.sol b/contracts/utils/EnumerableSet.sol index 2ea0d169e..1c9424487 100644 --- a/contracts/utils/EnumerableSet.sol +++ b/contracts/utils/EnumerableSet.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; /** * @dev Library for managing @@ -36,8 +36,11 @@ library EnumerableSet { internal returns (bool) { - if (!contains(set, value)){ - set.index[value] = set.values.push(value); + if (!contains(set, value)) { + set.values.push(value); + // The element is stored at length-1, but we add 1 to all indexes + // and use 0 as a sentinel value + set.index[value] = set.values.length; return true; } else { return false; diff --git a/contracts/utils/ReentrancyGuard.sol b/contracts/utils/ReentrancyGuard.sol index 762938d93..ab5387d41 100644 --- a/contracts/utils/ReentrancyGuard.sol +++ b/contracts/utils/ReentrancyGuard.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; /** * @dev Contract module that helps prevent reentrant calls to a function. diff --git a/contracts/utils/SafeCast.sol b/contracts/utils/SafeCast.sol index 5846190e9..27f6f2db0 100644 --- a/contracts/utils/SafeCast.sol +++ b/contracts/utils/SafeCast.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; /** diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index 7a2e5530f..d9fdacba5 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -9,6 +9,8 @@ ** xref:erc721.adoc[ERC721] ** xref:erc777.adoc[ERC777] +* xref:using-hooks.adoc[Using Hooks] + * xref:gsn.adoc[Gas Station Network] ** xref:gsn-strategies.adoc[Strategies] diff --git a/docs/modules/ROOT/pages/using-hooks.adoc b/docs/modules/ROOT/pages/using-hooks.adoc new file mode 100644 index 000000000..dcb8413ac --- /dev/null +++ b/docs/modules/ROOT/pages/using-hooks.adoc @@ -0,0 +1,7 @@ +# Using Hooks + +is a good idea. + +using hooks: + super.hook() must _always_ be called + if you want to cancel the process, revert. works both in before and after diff --git a/package-lock.json b/package-lock.json index 47b7da4d9..db0ff6d65 100644 --- a/package-lock.json +++ b/package-lock.json @@ -346,6 +346,12 @@ "integrity": "sha512-VlTurkvs4v7EVFWESBZGOPghFEokQhU5au5CP9WqA8B2/PcQRDsaaQlQCA6VATuEnW+vtSiSBvTiOc4004f8xg==", "dev": true }, + "@fvictorio/solidity-parser": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/@fvictorio/solidity-parser/-/solidity-parser-0.4.15.tgz", + "integrity": "sha512-DacgMagmysautS/MzbEmvgUOyoLxS6LSpMLFjINhUJFrG3OJXiihHMId6kOc08aiwlWHo+pd7C/z3ixm/gPPsQ==", + "dev": true + }, "@grpc/proto-loader": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.5.3.tgz", @@ -622,14 +628,14 @@ } }, "@openzeppelin/cli": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@openzeppelin/cli/-/cli-2.6.0.tgz", - "integrity": "sha512-zbWD0sagC2KnpXTYF7IVeQZkIGVQFdW8E/S8ft2LA9VWzPn1F2vhnMeXQP5pcCA4EjieoJZL12IBE/cIjfr3MQ==", + "version": "2.7.0-rc.2", + "resolved": "https://registry.npmjs.org/@openzeppelin/cli/-/cli-2.7.0-rc.2.tgz", + "integrity": "sha512-QACc4AYmkosB0Uink1OL1c1/mJRtxHstQhNXp3OQFevcONjib71SPtDx6rLovMKPjJEa9jjeJL+LwxsyjIjIqw==", "dev": true, "requires": { - "@openzeppelin/resolver-engine-core": "^0.3.3", - "@openzeppelin/resolver-engine-imports-fs": "^0.3.3", - "@openzeppelin/upgrades": "^2.6.0", + "@openzeppelin/fuzzy-solidity-import-parser": "^0.1.0", + "@openzeppelin/test-environment": "^0.1.0", + "@openzeppelin/upgrades": "2.7.0-rc.2", "@types/fs-extra": "^7.0.0", "@types/npm": "^2.0.29", "@types/semver": "^5.5.0", @@ -644,6 +650,7 @@ "find-up": "^3.0.0", "firebase": "^6.6.0", "fs-extra": "^7.0.1", + "glob": "^7.1.6", "inquirer": "^6.4.1", "is-url": "^1.2.4", "lockfile": "^1.0.4", @@ -680,18 +687,24 @@ "lodash.pick": "^4.4.0", "lodash.pickby": "^4.6.0", "lodash.reverse": "^4.0.1", + "lodash.sortby": "^4.7.0", "lodash.topairs": "^4.3.0", "lodash.uniq": "^4.5.0", "lodash.uniqby": "^4.7.0", "lodash.uniqwith": "^4.5.0", + "lodash.zipwith": "^4.2.0", "npm-programmatic": "0.0.12", "rlp": "^2.2.3", "semver": "^5.5.0", "simple-git": "^1.110.0", "solc-wrapper": "^0.5.8", - "solidity-parser-antlr": "^0.4.2", "spinnies": "^0.3.0", + "toposort": "^2.0.2", "truffle-config": "1.1.16", + "ts-generator": "^0.0.8", + "typechain": "^1.0.3", + "typechain-target-truffle": "^1.0.1", + "typechain-target-web3-v1": "^1.0.1", "underscore": "^1.9.1", "uuid": "^3.3.3", "web3": "1.2.2", @@ -701,12 +714,12 @@ }, "dependencies": { "ajv": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", - "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.11.0.tgz", + "integrity": "sha512-nCprB/0syFYy9fVYU1ox1l2KN8S9I+tziH8D4zdZuLT3N6RMlGSGt5FSTpAiHB/Whv8Qs1cWHma1aMKZyaHRKA==", "dev": true, "requires": { - "fast-deep-equal": "^2.0.1", + "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" @@ -734,13 +747,21 @@ } }, "ethereumjs-tx": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ethereumjs-tx/-/ethereumjs-tx-2.1.1.tgz", - "integrity": "sha512-QtVriNqowCFA19X9BCRPMgdVNJ0/gMBS91TQb1DfrhsbR748g4STwxZptFAwfqehMyrF8rDwB23w87PQwru0wA==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ethereumjs-tx/-/ethereumjs-tx-2.1.2.tgz", + "integrity": "sha512-zZEK1onCeiORb0wyCXUvg94Ve5It/K6GD1K+26KfFKodiBiS6d9lfCXlUKGBBdQ+bv7Day+JK0tj1K+BeNFRAw==", "dev": true, "requires": { - "ethereumjs-common": "^1.3.1", + "ethereumjs-common": "^1.5.0", "ethereumjs-util": "^6.0.0" + }, + "dependencies": { + "ethereumjs-common": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/ethereumjs-common/-/ethereumjs-common-1.5.0.tgz", + "integrity": "sha512-SZOjgK1356hIY7MRj3/ma5qtfr/4B5BL+G4rP/XSMYr2z1H5el4RX5GReYCKmQmYI/nSBmRnwrZ17IfHuG0viQ==", + "dev": true + } } }, "ethers": { @@ -762,9 +783,9 @@ }, "dependencies": { "@types/node": { - "version": "10.17.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.6.tgz", - "integrity": "sha512-0a2X6cgN3RdPBL2MIlR6Lt0KlM7fOFsutuXcdglcOq6WvLnYXgPQSh0Mx6tO1KCAE8MxbHSOSTWDoUxRq+l3DA==", + "version": "10.17.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.14.tgz", + "integrity": "sha512-G0UmX5uKEmW+ZAhmZ6PLTQ5eu/VPaT+d/tdLd5IFsKRPcbe6lPxocBtcYBFSaLaCW8O60AX90e91Nsp8lVHCNw==", "dev": true }, "elliptic": { @@ -788,9 +809,9 @@ } }, "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", + "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==", "dev": true }, "find-up": { @@ -813,6 +834,20 @@ "universalify": "^0.1.0" } }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "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" + } + }, "is-buffer": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", @@ -863,9 +898,9 @@ "dev": true }, "uuid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", - "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", "dev": true }, "web3": { @@ -897,9 +932,9 @@ }, "dependencies": { "@types/node": { - "version": "10.17.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.6.tgz", - "integrity": "sha512-0a2X6cgN3RdPBL2MIlR6Lt0KlM7fOFsutuXcdglcOq6WvLnYXgPQSh0Mx6tO1KCAE8MxbHSOSTWDoUxRq+l3DA==", + "version": "10.17.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.14.tgz", + "integrity": "sha512-G0UmX5uKEmW+ZAhmZ6PLTQ5eu/VPaT+d/tdLd5IFsKRPcbe6lPxocBtcYBFSaLaCW8O60AX90e91Nsp8lVHCNw==", "dev": true } } @@ -1177,6 +1212,12 @@ "try-require": "^1.2.1" } }, + "@openzeppelin/fuzzy-solidity-import-parser": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@openzeppelin/fuzzy-solidity-import-parser/-/fuzzy-solidity-import-parser-0.1.1.tgz", + "integrity": "sha512-fQCg+YzHRdIQi4Y1S3Q1A7xnyoCm7EXu9m3JacmvaGA9YtQ4ExQg4B3g8CSvK++Ziy+JfzpMO/GZizvSNSgq9g==", + "dev": true + }, "@openzeppelin/gsn-helpers": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/@openzeppelin/gsn-helpers/-/gsn-helpers-0.2.3.tgz", @@ -1238,120 +1279,6 @@ } } }, - "@openzeppelin/resolver-engine-core": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@openzeppelin/resolver-engine-core/-/resolver-engine-core-0.3.3.tgz", - "integrity": "sha512-PVUlxy8VlkslLaedl8IXz+dvjZz5inQoo5a12P0YZAmiCEo0Ct98ME4JN3LvxZx9YLLrjiShE/Jpaw+hjfO78A==", - "dev": true, - "requires": { - "@types/is-url": "^1.2.28", - "debug": "^3.1.0", - "is-url": "^1.2.4", - "request": "^2.85.0" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "@openzeppelin/resolver-engine-fs": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@openzeppelin/resolver-engine-fs/-/resolver-engine-fs-0.3.3.tgz", - "integrity": "sha512-L0hZ51xj95JYtJcnmfPO9RdmJSN3h3Q8DuJBrc5pUx9ifCTp2gPCck6OH1ueYfKoeqt99yzMrVuqYoNLOG929Q==", - "dev": true, - "requires": { - "@openzeppelin/resolver-engine-core": "^0.3.3", - "debug": "^3.1.0" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "@openzeppelin/resolver-engine-imports": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@openzeppelin/resolver-engine-imports/-/resolver-engine-imports-0.3.3.tgz", - "integrity": "sha512-+VCTAWgHUjZVTcwo8KL7SvRiqtscVJvJimn5PBT+anbgoIEp0xR6n1PmOfJv83OHNoOvTfkF2jYL6tt1J59xfg==", - "dev": true, - "requires": { - "@openzeppelin/resolver-engine-core": "^0.3.3", - "debug": "^3.1.0", - "hosted-git-info": "^2.6.0", - "path-browserify": "^1.0.0", - "url": "^0.11.0" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "@openzeppelin/resolver-engine-imports-fs": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@openzeppelin/resolver-engine-imports-fs/-/resolver-engine-imports-fs-0.3.3.tgz", - "integrity": "sha512-PvtXHC2FxGvi6XcydQo96muDlCTH0wLzCPFc1svaZr/9FjxhukaUk3KwfZZAhfZ/hMfEEgNK2nNFJ2QNC1OaFg==", - "dev": true, - "requires": { - "@openzeppelin/resolver-engine-fs": "^0.3.3", - "@openzeppelin/resolver-engine-imports": "^0.3.3", - "debug": "^3.1.0" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, "@openzeppelin/test-environment": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/@openzeppelin/test-environment/-/test-environment-0.1.2.tgz", @@ -1804,9 +1731,9 @@ } }, "@openzeppelin/upgrades": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades/-/upgrades-2.6.0.tgz", - "integrity": "sha512-vqL3ny0Z2M023H5cLiAS4qY+bjFYqhkPvxpfvYtTeaB2Bt/UeRD2Qk8+VvCFpojYOr9OBHu3RJWrFDcvgPcVxA==", + "version": "2.7.0-rc.2", + "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades/-/upgrades-2.7.0-rc.2.tgz", + "integrity": "sha512-q4b9lONd73owC/QROpRY8no6Q/PTwfvU0RsaZKZ24nFG4LRHo/uZnsbawg+bgVFWz4qXJLmFEp4m1XEc5S720g==", "dev": true, "requires": { "@types/cbor": "^2.0.0", @@ -1838,6 +1765,7 @@ "lodash.values": "^4.3.0", "lodash.without": "^4.4.0", "semver": "^5.5.1", + "solidity-docgen": "^0.3.5", "spinnies": "^0.4.2", "truffle-flattener": "^1.4.0", "web3": "1.2.2", @@ -1889,13 +1817,21 @@ } }, "ethereumjs-tx": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ethereumjs-tx/-/ethereumjs-tx-2.1.1.tgz", - "integrity": "sha512-QtVriNqowCFA19X9BCRPMgdVNJ0/gMBS91TQb1DfrhsbR748g4STwxZptFAwfqehMyrF8rDwB23w87PQwru0wA==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ethereumjs-tx/-/ethereumjs-tx-2.1.2.tgz", + "integrity": "sha512-zZEK1onCeiORb0wyCXUvg94Ve5It/K6GD1K+26KfFKodiBiS6d9lfCXlUKGBBdQ+bv7Day+JK0tj1K+BeNFRAw==", "dev": true, "requires": { - "ethereumjs-common": "^1.3.1", + "ethereumjs-common": "^1.5.0", "ethereumjs-util": "^6.0.0" + }, + "dependencies": { + "ethereumjs-common": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/ethereumjs-common/-/ethereumjs-common-1.5.0.tgz", + "integrity": "sha512-SZOjgK1356hIY7MRj3/ma5qtfr/4B5BL+G4rP/XSMYr2z1H5el4RX5GReYCKmQmYI/nSBmRnwrZ17IfHuG0viQ==", + "dev": true + } } }, "glob": { @@ -2016,9 +1952,9 @@ }, "dependencies": { "@types/node": { - "version": "10.17.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.6.tgz", - "integrity": "sha512-0a2X6cgN3RdPBL2MIlR6Lt0KlM7fOFsutuXcdglcOq6WvLnYXgPQSh0Mx6tO1KCAE8MxbHSOSTWDoUxRq+l3DA==", + "version": "10.17.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.14.tgz", + "integrity": "sha512-G0UmX5uKEmW+ZAhmZ6PLTQ5eu/VPaT+d/tdLd5IFsKRPcbe6lPxocBtcYBFSaLaCW8O60AX90e91Nsp8lVHCNw==", "dev": true } } @@ -2128,9 +2064,9 @@ }, "dependencies": { "@types/node": { - "version": "10.17.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.6.tgz", - "integrity": "sha512-0a2X6cgN3RdPBL2MIlR6Lt0KlM7fOFsutuXcdglcOq6WvLnYXgPQSh0Mx6tO1KCAE8MxbHSOSTWDoUxRq+l3DA==", + "version": "10.17.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.14.tgz", + "integrity": "sha512-G0UmX5uKEmW+ZAhmZ6PLTQ5eu/VPaT+d/tdLd5IFsKRPcbe6lPxocBtcYBFSaLaCW8O60AX90e91Nsp8lVHCNw==", "dev": true }, "elliptic": { @@ -3807,16 +3743,10 @@ "@types/node": "*" } }, - "@types/is-url": { - "version": "1.2.28", - "resolved": "https://registry.npmjs.org/@types/is-url/-/is-url-1.2.28.tgz", - "integrity": "sha1-kU2r1QVG2bAUKAbkLHK8fCt+B4c=", - "dev": true - }, "@types/long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.0.tgz", - "integrity": "sha512-1w52Nyx4Gq47uuu0EVcsHBxZFJgurQ+rTKS3qMHxR1GY2T8c2AJYd6vZoZ9q1rupaDjU0yT+Jc2XTyXkjeMA+Q==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==", "dev": true }, "@types/node": { @@ -3834,12 +3764,66 @@ "@types/node": "*" } }, + "@types/prettier": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-1.19.0.tgz", + "integrity": "sha512-gDE8JJEygpay7IjA/u3JiIURvwZW08f0cZSZLAzFoX/ZmeqvS0Sqv+97aKuHpNsalAMMhwPe+iAS6fQbfmbt7A==", + "dev": true + }, + "@types/resolve": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz", + "integrity": "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/semver": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-5.5.0.tgz", "integrity": "sha512-41qEJgBH/TWgo5NFSvBCJ1qkoi3Q6ONSF2avrHq1LVEZfYpdHmj0y9SuTK+u9ZhG1sYQKBL1AWXKyLWP4RaUoQ==", "dev": true }, + "@web3-js/scrypt-shim": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@web3-js/scrypt-shim/-/scrypt-shim-0.1.0.tgz", + "integrity": "sha512-ZtZeWCc/s0nMcdx/+rZwY1EcuRdemOK9ag21ty9UsHkFxsNb/AaoucUz0iPuyGe0Ku+PFuRmWZG7Z7462p9xPw==", + "dev": true, + "requires": { + "scryptsy": "^2.1.0", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@web3-js/websocket": { + "version": "1.0.30", + "resolved": "https://registry.npmjs.org/@web3-js/websocket/-/websocket-1.0.30.tgz", + "integrity": "sha512-fDwrD47MiDrzcJdSeTLF75aCcxVVt8B1N74rA+vh2XCAvFy4tEWJjtnUtj2QG7/zlQ6g9cQ88bZFBxwd9/FmtA==", + "dev": true, + "requires": { + "debug": "^2.2.0", + "es5-ext": "^0.10.50", + "nan": "^2.14.0", + "typedarray-to-buffer": "^3.1.5", + "yaeti": "^0.0.6" + }, + "dependencies": { + "nan": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", + "dev": true + } + } + }, "abi-decoder": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/abi-decoder/-/abi-decoder-2.2.2.tgz", @@ -4005,6 +3989,15 @@ "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", "dev": true }, + "array-back": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-2.0.0.tgz", + "integrity": "sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==", + "dev": true, + "requires": { + "typical": "^2.6.1" + } + }, "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -4225,6 +4218,12 @@ "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", "dev": true }, + "ast-parents": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/ast-parents/-/ast-parents-0.0.1.tgz", + "integrity": "sha1-UI/Q8F0MSHddnszaLhdEIyYejdM=", + "dev": true + }, "astral-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", @@ -4833,16 +4832,23 @@ "dev": true, "requires": { "callsites": "^2.0.0" - }, - "dependencies": { - "callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", - "dev": true - } } }, + "caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "dev": true, + "requires": { + "caller-callsite": "^2.0.0" + } + }, + "callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "dev": true + }, "camelcase": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", @@ -5138,6 +5144,17 @@ "integrity": "sha512-PM54PkseWbiiD/mMsbvW351/u+dafwTJ0ye2qB60G1aGQP9j3xK2gmMDc+R34L3nDtx4qMCitXT75mkbkGJDLw==", "dev": true }, + "command-line-args": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-4.0.7.tgz", + "integrity": "sha512-aUdPvQRAyBvQd2n7jXcsMDz68ckBJELXNzBybCHOibUWEg0mWTnaYCSRU8h9R+aNRSvDihJtssSRCiDRpLaezA==", + "dev": true, + "requires": { + "array-back": "^2.0.0", + "find-replace": "^1.0.3", + "typical": "^2.6.1" + } + }, "commander": { "version": "2.20.1", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.1.tgz", @@ -5313,6 +5330,27 @@ } } }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, "crypto-browserify": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", @@ -6362,9 +6400,9 @@ } }, "eslint-visitor-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", "dev": true }, "espree": { @@ -7224,6 +7262,27 @@ "unpipe": "~1.0.0" } }, + "find-replace": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-1.0.3.tgz", + "integrity": "sha1-uI5zZNLZyVlVnziMZmcNYTBEH6A=", + "dev": true, + "requires": { + "array-back": "^1.0.4", + "test-value": "^2.1.0" + }, + "dependencies": { + "array-back": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-1.0.4.tgz", + "integrity": "sha1-ZEun8JX3/898Q7Xw3DnTwfA8Bjs=", + "dev": true, + "requires": { + "typical": "^2.6.0" + } + } + } + }, "find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -28311,9 +28370,9 @@ }, "dependencies": { "readable-stream": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", - "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.5.0.tgz", + "integrity": "sha512-gSz026xs2LfxBPudDuI41V1lka8cxg64E66SGe78zJlsUofOg/yqwezdIcdfwik6B4h8LFmWPA9ef9X3FiNFLA==", "dev": true, "requires": { "inherits": "^2.0.3", @@ -28446,15 +28505,6 @@ "resolve-from": "^3.0.0" }, "dependencies": { - "caller-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", - "dev": true, - "requires": { - "caller-callsite": "^2.0.0" - } - }, "resolve-from": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", @@ -30230,6 +30280,12 @@ "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=", "dev": true }, + "lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", + "dev": true + }, "lodash.startcase": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz", @@ -30291,6 +30347,12 @@ "integrity": "sha1-PNRXSgC2e643OpS3SHcmQFB7eqw=", "dev": true }, + "lodash.zipwith": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.zipwith/-/lodash.zipwith-4.2.0.tgz", + "integrity": "sha1-r6zwP9LzhK8p4mPDxr2juA4/Uf0=", + "dev": true + }, "log-symbols": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", @@ -31545,12 +31607,6 @@ "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", "dev": true }, - "path-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.0.tgz", - "integrity": "sha512-Hkavx/nY4/plImrZPHRk2CL9vpOymZLgEbMNX1U0bjcBL7QN9wODxyx0yaMZURSQaUtSEvDrfAvxa9oPb0at9g==", - "dev": true - }, "path-dirname": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", @@ -31756,11 +31812,10 @@ "dev": true }, "prettier": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.18.2.tgz", - "integrity": "sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==", - "dev": true, - "optional": true + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", + "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", + "dev": true }, "process": { "version": "0.5.2", @@ -31808,9 +31863,9 @@ }, "dependencies": { "@types/node": { - "version": "10.17.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.6.tgz", - "integrity": "sha512-0a2X6cgN3RdPBL2MIlR6Lt0KlM7fOFsutuXcdglcOq6WvLnYXgPQSh0Mx6tO1KCAE8MxbHSOSTWDoUxRq+l3DA==", + "version": "10.17.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.14.tgz", + "integrity": "sha512-G0UmX5uKEmW+ZAhmZ6PLTQ5eu/VPaT+d/tdLd5IFsKRPcbe6lPxocBtcYBFSaLaCW8O60AX90e91Nsp8lVHCNw==", "dev": true } } @@ -31886,12 +31941,6 @@ "strict-uri-encode": "^1.0.0" } }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", - "dev": true - }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -32635,9 +32684,9 @@ } }, "simple-git": { - "version": "1.126.0", - "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-1.126.0.tgz", - "integrity": "sha512-47mqHxgZnN8XRa9HbpWprzUv3Ooqz9RY/LSZgvA7jCkW8jcwLahMz7LKugY91KZehfG0sCVPtgXiU72hd6b1Bw==", + "version": "1.131.0", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-1.131.0.tgz", + "integrity": "sha512-z/art7YYtmPnnLItT/j+nKwJt6ap6nHZ4D8sYo9PdCKK/ug56SN6m/evfxJk7uDV3e9JuCa8qIyDU2P3cxmiNQ==", "dev": true, "requires": { "debug": "^4.0.1" @@ -32900,13 +32949,15 @@ } }, "solhint": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/solhint/-/solhint-2.3.0.tgz", - "integrity": "sha512-2yiELLp+MsDtuOTrjc14lgsYmlMchp++SicvqCBu01VXsi9Mk2uynhyN3nBfbGzYq1YfmOEBpUqJfFYXVAR/Ig==", + "version": "3.0.0-rc.2", + "resolved": "https://registry.npmjs.org/solhint/-/solhint-3.0.0-rc.2.tgz", + "integrity": "sha512-0IDui3ik4WU8TcSXC+aRisfup8E6BVD1RwCYB/pvs404Rnj2HkhgrtmWKdct+tlSRjAo3XCMXbajC4vfG6mOBw==", "dev": true, "requires": { + "@fvictorio/solidity-parser": "^0.4.15", "ajv": "^6.6.1", "antlr4": "4.7.1", + "ast-parents": "0.0.1", "chalk": "^2.4.2", "commander": "2.18.0", "cosmiconfig": "^5.0.7", @@ -32921,65 +32972,27 @@ }, "dependencies": { "acorn": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz", - "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==", - "dev": true - }, - "acorn-jsx": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.2.tgz", - "integrity": "sha512-tiNTrP1MP0QrChmD2DdupCr6HWSFeKVw5d/dHTu4Y7rkAkRhU/Dt7dphAfIUyxtHpl/eBVip5uTNSpQJHylpAw==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.0.tgz", + "integrity": "sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw==", "dev": true }, "ajv": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", - "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.11.0.tgz", + "integrity": "sha512-nCprB/0syFYy9fVYU1ox1l2KN8S9I+tziH8D4zdZuLT3N6RMlGSGt5FSTpAiHB/Whv8Qs1cWHma1aMKZyaHRKA==", "dev": true, "requires": { - "fast-deep-equal": "^2.0.1", + "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true - }, "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, "commander": { @@ -32988,27 +33001,6 @@ "integrity": "sha512-6CYPa+JP2ftfRU2qkDK+UTVeQYosOg/2GbcjIcKPHfinyOLPVGXu/ovN86RP49Re5ndJK1N0kuiidFFuepc4ZQ==", "dev": true }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, "debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", @@ -33018,15 +33010,6 @@ "ms": "^2.1.1" } }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, "eslint": { "version": "5.16.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz", @@ -33100,47 +33083,16 @@ "eslint-visitor-keys": "^1.0.0" } }, - "external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - } - }, "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", + "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==", "dev": true }, - "file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", - "dev": true, - "requires": { - "flat-cache": "^2.0.1" - } - }, - "flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", - "dev": true, - "requires": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" - } - }, "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -33151,63 +33103,16 @@ "path-is-absolute": "^1.0.0" } }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - }, "import-fresh": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz", - "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", "dev": true, "requires": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, - "inquirer": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", - "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", - "dev": true, - "requires": { - "ansi-escapes": "^3.2.0", - "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.3", - "figures": "^2.0.0", - "lodash": "^4.17.12", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^6.4.0", - "string-width": "^2.1.0", - "strip-ansi": "^5.1.0", - "through": "^2.3.6" - }, - "dependencies": { - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -33220,44 +33125,12 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", - "dev": true - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true }, - "slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" - } - }, "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", @@ -33265,66 +33138,6 @@ "dev": true, "requires": { "ansi-regex": "^3.0.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 - } - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", - "dev": true, - "requires": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" - }, - "dependencies": { - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", - "dev": true, - "requires": { - "mkdirp": "^0.5.1" } } } @@ -34223,6 +34036,27 @@ "xtend": "^4.0.0" } }, + "test-value": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/test-value/-/test-value-2.1.0.tgz", + "integrity": "sha1-Edpv9nDzRxpztiXKTz/c97t0gpE=", + "dev": true, + "requires": { + "array-back": "^1.0.3", + "typical": "^2.6.0" + }, + "dependencies": { + "array-back": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-1.0.4.tgz", + "integrity": "sha1-ZEun8JX3/898Q7Xw3DnTwfA8Bjs=", + "dev": true, + "requires": { + "typical": "^2.6.0" + } + } + } + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -34309,6 +34143,12 @@ "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", "dev": true }, + "toposort": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", + "integrity": "sha1-riF2gXXRVZ1IvvNUILL0li8JwzA=", + "dev": true + }, "tough-cookie": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", @@ -34476,6 +34316,45 @@ "integrity": "sha1-NEiaLKwMCcHMEO2RugEVlNQzO+I=", "dev": true }, + "ts-essentials": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-1.0.4.tgz", + "integrity": "sha512-q3N1xS4vZpRouhYHDPwO0bDW3EZ6SK9CrrDHxi/D6BPReSjpVgWIOpLS2o0gSBZm+7q/wyKp6RVM1AeeW7uyfQ==", + "dev": true + }, + "ts-generator": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ts-generator/-/ts-generator-0.0.8.tgz", + "integrity": "sha512-Gi+aZCELpVL7Mqb+GuMgM+n8JZ/arZZib1iD/R9Ok8JDjOCOCrqS9b1lr72ku7J45WeDCFZxyJoRsiQvhokCnw==", + "dev": true, + "requires": { + "@types/prettier": "^1.13.2", + "@types/resolve": "^0.0.8", + "chalk": "^2.4.1", + "glob": "^7.1.2", + "mkdirp": "^0.5.1", + "prettier": "^1.14.2", + "resolve": "^1.8.1", + "ts-essentials": "^1.0.0" + }, + "dependencies": { + "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.15.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.0.tgz", + "integrity": "sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + } + } + }, "tslib": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", @@ -34558,6 +34437,487 @@ } } }, + "typechain": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typechain/-/typechain-1.0.4.tgz", + "integrity": "sha512-jZoxGWTlGXf9n95lIb9R0i3SzHP2jMxJDpVgePMQq93FaLYa8pHKe8DRmCmVkWXP2SGZpo4/jUPYMc0+vf/4XA==", + "dev": true, + "requires": { + "command-line-args": "^4.0.7", + "debug": "^3.0.1", + "fs-extra": "^7.0.0", + "js-sha3": "^0.8.0", + "lodash": "^4.17.15", + "ts-generator": "^0.0.8" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", + "dev": true + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "typechain-target-truffle": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typechain-target-truffle/-/typechain-target-truffle-1.0.2.tgz", + "integrity": "sha512-XF3Iq2IzR+Pqvx6fcKIKGXNEk3lEcY24vYv9VqoVPfPB6vUM09PRLJCeLm1/ag6Pr2PICKUA0f4Es+YTR3ESKA==", + "dev": true, + "requires": { + "lodash": "^4.17.15" + }, + "dependencies": { + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + } + } + }, + "typechain-target-web3-v1": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typechain-target-web3-v1/-/typechain-target-web3-v1-1.0.4.tgz", + "integrity": "sha512-jQ6eCfY7QorBq6kQDjSy5LMuImZGkp6IXR6FXZp7/ulITIxAfb6Dxh+yvh0NN/zboLnMPvvSJi6tHWCqlwfSDA==", + "dev": true, + "requires": { + "lodash": "^4.17.15", + "web3": "^1.2.4" + }, + "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, + "requires": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "xhr-request-promise": "^0.1.2" + } + }, + "ethereumjs-tx": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ethereumjs-tx/-/ethereumjs-tx-2.1.2.tgz", + "integrity": "sha512-zZEK1onCeiORb0wyCXUvg94Ve5It/K6GD1K+26KfFKodiBiS6d9lfCXlUKGBBdQ+bv7Day+JK0tj1K+BeNFRAw==", + "dev": true, + "requires": { + "ethereumjs-common": "^1.5.0", + "ethereumjs-util": "^6.0.0" + }, + "dependencies": { + "ethereumjs-common": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/ethereumjs-common/-/ethereumjs-common-1.5.0.tgz", + "integrity": "sha512-SZOjgK1356hIY7MRj3/ma5qtfr/4B5BL+G4rP/XSMYr2z1H5el4RX5GReYCKmQmYI/nSBmRnwrZ17IfHuG0viQ==", + "dev": true + } + } + }, + "ethers": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.0-beta.3.tgz", + "integrity": "sha512-YYPogooSknTwvHg3+Mv71gM/3Wcrx+ZpCzarBj3mqs9njjRkrOo2/eufzhHloOCo3JSoNI4TQJJ6yU5ABm3Uog==", + "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.3", + "setimmediate": "1.0.4", + "uuid": "2.0.1", + "xmlhttprequest": "1.8.0" + }, + "dependencies": { + "@types/node": { + "version": "10.17.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.14.tgz", + "integrity": "sha512-G0UmX5uKEmW+ZAhmZ6PLTQ5eu/VPaT+d/tdLd5IFsKRPcbe6lPxocBtcYBFSaLaCW8O60AX90e91Nsp8lVHCNw==", + "dev": true + }, + "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" + } + } + } + }, + "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 + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "scrypt-js": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.3.tgz", + "integrity": "sha1-uwBAvgMEPamgEqLOqfyfhSz8h9Q=", + "dev": true + }, + "uuid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", + "integrity": "sha1-wqMN7bPlNdcsz4LjQ5QaULqFM6w=", + "dev": true + }, + "web3": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.2.6.tgz", + "integrity": "sha512-tpu9fLIComgxGrFsD8LUtA4s4aCZk7px8UfcdEy6kS2uDi/ZfR07KJqpXZMij7Jvlq+cQrTAhsPSiBVvoMaivA==", + "dev": true, + "requires": { + "@types/node": "^12.6.1", + "web3-bzz": "1.2.6", + "web3-core": "1.2.6", + "web3-eth": "1.2.6", + "web3-eth-personal": "1.2.6", + "web3-net": "1.2.6", + "web3-shh": "1.2.6", + "web3-utils": "1.2.6" + } + }, + "web3-bzz": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.2.6.tgz", + "integrity": "sha512-9NiHLlxdI1XeFtbPJAmi2jnnIHVF+GNy517wvOS72P7ZfuJTPwZaSNXfT01vWgPPE9R96/uAHDWHOg+T4WaDQQ==", + "dev": true, + "requires": { + "@types/node": "^10.12.18", + "got": "9.6.0", + "swarm-js": "0.1.39", + "underscore": "1.9.1" + }, + "dependencies": { + "@types/node": { + "version": "10.17.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.14.tgz", + "integrity": "sha512-G0UmX5uKEmW+ZAhmZ6PLTQ5eu/VPaT+d/tdLd5IFsKRPcbe6lPxocBtcYBFSaLaCW8O60AX90e91Nsp8lVHCNw==", + "dev": true + } + } + }, + "web3-core": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.2.6.tgz", + "integrity": "sha512-y/QNBFtr5cIR8vxebnotbjWJpOnO8LDYEAzZjeRRUJh2ijmhjoYk7dSNx9ExgC0UCfNFRoNCa9dGRu/GAxwRlw==", + "dev": true, + "requires": { + "@types/bn.js": "^4.11.4", + "@types/node": "^12.6.1", + "web3-core-helpers": "1.2.6", + "web3-core-method": "1.2.6", + "web3-core-requestmanager": "1.2.6", + "web3-utils": "1.2.6" + } + }, + "web3-core-helpers": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.6.tgz", + "integrity": "sha512-gYKWmC2HmO7RcDzpo4L1K8EIoy5L8iubNDuTC6q69UxczwqKF/Io0kbK/1Z10Av++NlzOSiuyGp2gc4t4UOsDw==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-eth-iban": "1.2.6", + "web3-utils": "1.2.6" + } + }, + "web3-core-method": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.2.6.tgz", + "integrity": "sha512-r2dzyPEonqkBg7Mugq5dknhV5PGaZTHBZlS/C+aMxNyQs3T3eaAsCTqlQDitwNUh/sUcYPEGF0Vo7ahYK4k91g==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-core-helpers": "1.2.6", + "web3-core-promievent": "1.2.6", + "web3-core-subscriptions": "1.2.6", + "web3-utils": "1.2.6" + } + }, + "web3-core-promievent": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.2.6.tgz", + "integrity": "sha512-km72kJef/qtQNiSjDJJVHIZvoVOm6ytW3FCYnOcCs7RIkviAb5JYlPiye0o4pJOLzCXYID7DK7Q9bhY8qWb1lw==", + "dev": true, + "requires": { + "any-promise": "1.3.0", + "eventemitter3": "3.1.2" + } + }, + "web3-core-requestmanager": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.2.6.tgz", + "integrity": "sha512-QU2cbsj9Dm0r6om40oSwk8Oqbp3wTa08tXuMpSmeOTkGZ3EMHJ1/4LiJ8shwg1AvPMrKVU0Nri6+uBNCdReZ+g==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-core-helpers": "1.2.6", + "web3-providers-http": "1.2.6", + "web3-providers-ipc": "1.2.6", + "web3-providers-ws": "1.2.6" + } + }, + "web3-core-subscriptions": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.2.6.tgz", + "integrity": "sha512-M0PzRrP2Ct13x3wPulFtc5kENH4UtnPxO9YxkfQlX2WRKENWjt4Rfq+BCVGYEk3rTutDfWrjfzjmqMRvXqEY5Q==", + "dev": true, + "requires": { + "eventemitter3": "3.1.2", + "underscore": "1.9.1", + "web3-core-helpers": "1.2.6" + } + }, + "web3-eth": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.2.6.tgz", + "integrity": "sha512-ROWlDPzh4QX6tlGGGlAK6X4kA2n0/cNj/4kb0nNVWkRouGmYO0R8k6s47YxYHvGiXt0s0++FUUv5vAbWovtUQw==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-core": "1.2.6", + "web3-core-helpers": "1.2.6", + "web3-core-method": "1.2.6", + "web3-core-subscriptions": "1.2.6", + "web3-eth-abi": "1.2.6", + "web3-eth-accounts": "1.2.6", + "web3-eth-contract": "1.2.6", + "web3-eth-ens": "1.2.6", + "web3-eth-iban": "1.2.6", + "web3-eth-personal": "1.2.6", + "web3-net": "1.2.6", + "web3-utils": "1.2.6" + } + }, + "web3-eth-abi": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.2.6.tgz", + "integrity": "sha512-w9GAyyikn8nSifSDZxAvU9fxtQSX+W2xQWMmrtTXmBGCaE4/ywKOSPAO78gq8AoU4Wq5yqVGKZLLbfpt7/sHlA==", + "dev": true, + "requires": { + "ethers": "4.0.0-beta.3", + "underscore": "1.9.1", + "web3-utils": "1.2.6" + } + }, + "web3-eth-accounts": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.2.6.tgz", + "integrity": "sha512-cDVtonHRgzqi/ZHOOf8kfCQWFEipcfQNAMzXIaKZwc0UUD9mgSI5oJrN45a89Ze+E6Lz9m77cDG5Ax9zscSkcw==", + "dev": true, + "requires": { + "@web3-js/scrypt-shim": "^0.1.0", + "any-promise": "1.3.0", + "crypto-browserify": "3.12.0", + "eth-lib": "^0.2.8", + "ethereumjs-common": "^1.3.2", + "ethereumjs-tx": "^2.1.1", + "underscore": "1.9.1", + "uuid": "3.3.2", + "web3-core": "1.2.6", + "web3-core-helpers": "1.2.6", + "web3-core-method": "1.2.6", + "web3-utils": "1.2.6" + }, + "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.2.6", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.2.6.tgz", + "integrity": "sha512-ak4xbHIhWgsbdPCkSN+HnQc1SH4c856y7Ly+S57J/DQVzhFZemK5HvWdpwadJrQTcHET3ZeId1vq3kmW7UYodw==", + "dev": true, + "requires": { + "@types/bn.js": "^4.11.4", + "underscore": "1.9.1", + "web3-core": "1.2.6", + "web3-core-helpers": "1.2.6", + "web3-core-method": "1.2.6", + "web3-core-promievent": "1.2.6", + "web3-core-subscriptions": "1.2.6", + "web3-eth-abi": "1.2.6", + "web3-utils": "1.2.6" + } + }, + "web3-eth-ens": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.2.6.tgz", + "integrity": "sha512-8UEqt6fqR/dji/jBGPFAyBs16OJjwi0t2dPWXPyGXmty/fH+osnXwWXE4HRUyj4xuafiM5P1YkXMsPhKEadjiw==", + "dev": true, + "requires": { + "eth-ens-namehash": "2.0.8", + "underscore": "1.9.1", + "web3-core": "1.2.6", + "web3-core-helpers": "1.2.6", + "web3-core-promievent": "1.2.6", + "web3-eth-abi": "1.2.6", + "web3-eth-contract": "1.2.6", + "web3-utils": "1.2.6" + } + }, + "web3-eth-iban": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.2.6.tgz", + "integrity": "sha512-TPMc3BW9Iso7H+9w+ytbqHK9wgOmtocyCD3PaAe5Eie50KQ/j7ThA60dGJnxItVo6yyRv5pZAYxPVob9x/fJlg==", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "web3-utils": "1.2.6" + } + }, + "web3-eth-personal": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.2.6.tgz", + "integrity": "sha512-T2NUkh1plY8d7wePXSoHnaiKOd8dLNFaQfgBl9JHU6S7IJrG9jnYD9bVxLEgRUfHs9gKf9tQpDf7AcPFdq/A8g==", + "dev": true, + "requires": { + "@types/node": "^12.6.1", + "web3-core": "1.2.6", + "web3-core-helpers": "1.2.6", + "web3-core-method": "1.2.6", + "web3-net": "1.2.6", + "web3-utils": "1.2.6" + } + }, + "web3-net": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.2.6.tgz", + "integrity": "sha512-hsNHAPddrhgjWLmbESW0KxJi2GnthPcow0Sqpnf4oB6+/+ZnQHU9OsIyHb83bnC1OmunrK2vf9Ye2mLPdFIu3A==", + "dev": true, + "requires": { + "web3-core": "1.2.6", + "web3-core-method": "1.2.6", + "web3-utils": "1.2.6" + } + }, + "web3-providers-http": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.2.6.tgz", + "integrity": "sha512-2+SaFCspb5f82QKuHB3nEPQOF9iSWxRf7c18fHtmnLNVkfG9SwLN1zh67bYn3tZGUdOI3gj8aX4Uhfpwx9Ezpw==", + "dev": true, + "requires": { + "web3-core-helpers": "1.2.6", + "xhr2-cookies": "1.1.0" + } + }, + "web3-providers-ipc": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.2.6.tgz", + "integrity": "sha512-b0Es+/GTZyk5FG3SgUDW+2/mBwJAXWt5LuppODptiOas8bB2khLjG6+Gm1K4uwOb+1NJGPt5mZZ8Wi7vibtQ+A==", + "dev": true, + "requires": { + "oboe": "2.1.4", + "underscore": "1.9.1", + "web3-core-helpers": "1.2.6" + } + }, + "web3-providers-ws": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.2.6.tgz", + "integrity": "sha512-20waSYX+gb5M5yKhug5FIwxBBvkKzlJH7sK6XEgdOx6BZ9YYamLmvg9wcRVtnSZO8hV/3cWenO/tRtTrHVvIgQ==", + "dev": true, + "requires": { + "@web3-js/websocket": "^1.0.29", + "underscore": "1.9.1", + "web3-core-helpers": "1.2.6" + } + }, + "web3-shh": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.2.6.tgz", + "integrity": "sha512-rouWyOOM6YMbLQd65grpj8BBezQfgNeRRX+cGyW4xsn6Xgu+B73Zvr6OtA/ftJwwa9bqHGpnLrrLMeWyy4YLUw==", + "dev": true, + "requires": { + "web3-core": "1.2.6", + "web3-core-method": "1.2.6", + "web3-core-subscriptions": "1.2.6", + "web3-net": "1.2.6" + } + }, + "web3-utils": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.2.6.tgz", + "integrity": "sha512-8/HnqG/l7dGmKMgEL9JeKPTtjScxOePTzopv5aaKFExPfaBrYRkgoMqhoowCiAl/s16QaTn4DoIF1QC4YsT7Mg==", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "eth-lib": "0.2.7", + "ethereum-bloom-filters": "^1.0.6", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "underscore": "1.9.1", + "utf8": "3.0.0" + } + } + } + }, "typedarray-to-buffer": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", @@ -34567,6 +34927,12 @@ "is-typedarray": "^1.0.0" } }, + "typical": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/typical/-/typical-2.6.1.tgz", + "integrity": "sha1-XAgOXWYcu+OCWdLnCjxyU+hziB0=", + "dev": true + }, "uglify-js": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz", @@ -34717,24 +35083,6 @@ "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", "dev": true }, - "url": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", - "dev": true, - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - }, - "dependencies": { - "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", - "dev": true - } - } - }, "url-parse-lax": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", diff --git a/package.json b/package.json index 0b86966f4..30d866339 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ }, "homepage": "https://openzeppelin.com/contracts/", "devDependencies": { - "@openzeppelin/cli": "^2.5.3", + "@openzeppelin/cli": "^2.7.0-rc.2", "@openzeppelin/gsn-helpers": "^0.2.3", "@openzeppelin/gsn-provider": "^0.1.9", "@openzeppelin/test-environment": "^0.1.2", @@ -63,7 +63,7 @@ "micromatch": "^4.0.2", "mocha": "^7.0.1", "openzeppelin-docs-utils": "github:OpenZeppelin/docs-utils", - "solhint": "2.3.0", + "solhint": "^3.0.0-rc.2", "solidity-coverage": "github:rotcivegaf/solidity-coverage#5875f5b7bc74d447f3312c9c0e9fc7814b482477", "solidity-docgen": "^0.3.14" }, diff --git a/test/access/roles/CapperRole.test.js b/test/access/roles/CapperRole.test.js deleted file mode 100644 index ecd538b1f..000000000 --- a/test/access/roles/CapperRole.test.js +++ /dev/null @@ -1,15 +0,0 @@ -const { accounts, contract } = require('@openzeppelin/test-environment'); - -const { shouldBehaveLikePublicRole } = require('../../behaviors/access/roles/PublicRole.behavior'); -const CapperRoleMock = contract.fromArtifact('CapperRoleMock'); - -describe('CapperRole', function () { - const [ capper, otherCapper, ...otherAccounts ] = accounts; - - beforeEach(async function () { - this.contract = await CapperRoleMock.new({ from: capper }); - await this.contract.addCapper(otherCapper, { from: capper }); - }); - - shouldBehaveLikePublicRole(capper, otherCapper, otherAccounts, 'capper'); -}); diff --git a/test/access/roles/MinterRole.test.js b/test/access/roles/MinterRole.test.js deleted file mode 100644 index 968577504..000000000 --- a/test/access/roles/MinterRole.test.js +++ /dev/null @@ -1,15 +0,0 @@ -const { accounts, contract } = require('@openzeppelin/test-environment'); - -const { shouldBehaveLikePublicRole } = require('../../behaviors/access/roles/PublicRole.behavior'); -const MinterRoleMock = contract.fromArtifact('MinterRoleMock'); - -describe('MinterRole', function () { - const [ minter, otherMinter, ...otherAccounts ] = accounts; - - beforeEach(async function () { - this.contract = await MinterRoleMock.new({ from: minter }); - await this.contract.addMinter(otherMinter, { from: minter }); - }); - - shouldBehaveLikePublicRole(minter, otherMinter, otherAccounts, 'minter'); -}); diff --git a/test/access/roles/PauserRole.test.js b/test/access/roles/PauserRole.test.js deleted file mode 100644 index b527fe946..000000000 --- a/test/access/roles/PauserRole.test.js +++ /dev/null @@ -1,15 +0,0 @@ -const { accounts, contract } = require('@openzeppelin/test-environment'); - -const { shouldBehaveLikePublicRole } = require('../../behaviors/access/roles/PublicRole.behavior'); -const PauserRoleMock = contract.fromArtifact('PauserRoleMock'); - -describe('PauserRole', function () { - const [ pauser, otherPauser, ...otherAccounts ] = accounts; - - beforeEach(async function () { - this.contract = await PauserRoleMock.new({ from: pauser }); - await this.contract.addPauser(otherPauser, { from: pauser }); - }); - - shouldBehaveLikePublicRole(pauser, otherPauser, otherAccounts, 'pauser'); -}); diff --git a/test/access/roles/SignerRole.test.js b/test/access/roles/SignerRole.test.js deleted file mode 100644 index 8887f96df..000000000 --- a/test/access/roles/SignerRole.test.js +++ /dev/null @@ -1,15 +0,0 @@ -const { accounts, contract } = require('@openzeppelin/test-environment'); - -const { shouldBehaveLikePublicRole } = require('../../behaviors/access/roles/PublicRole.behavior'); -const SignerRoleMock = contract.fromArtifact('SignerRoleMock'); - -describe('SignerRole', function () { - const [ signer, otherSigner, ...otherAccounts ] = accounts; - - beforeEach(async function () { - this.contract = await SignerRoleMock.new({ from: signer }); - await this.contract.addSigner(otherSigner, { from: signer }); - }); - - shouldBehaveLikePublicRole(signer, otherSigner, otherAccounts, 'signer'); -}); diff --git a/test/access/roles/WhitelistAdminRole.test.js b/test/access/roles/WhitelistAdminRole.test.js deleted file mode 100644 index 1d6333c26..000000000 --- a/test/access/roles/WhitelistAdminRole.test.js +++ /dev/null @@ -1,15 +0,0 @@ -const { accounts, contract } = require('@openzeppelin/test-environment'); - -const { shouldBehaveLikePublicRole } = require('../../behaviors/access/roles/PublicRole.behavior'); -const WhitelistAdminRoleMock = contract.fromArtifact('WhitelistAdminRoleMock'); - -describe('WhitelistAdminRole', function () { - const [ whitelistAdmin, otherWhitelistAdmin, ...otherAccounts ] = accounts; - - beforeEach(async function () { - this.contract = await WhitelistAdminRoleMock.new({ from: whitelistAdmin }); - await this.contract.addWhitelistAdmin(otherWhitelistAdmin, { from: whitelistAdmin }); - }); - - shouldBehaveLikePublicRole(whitelistAdmin, otherWhitelistAdmin, otherAccounts, 'whitelistAdmin'); -}); diff --git a/test/access/roles/WhitelistedRole.test.js b/test/access/roles/WhitelistedRole.test.js deleted file mode 100644 index 853223f2f..000000000 --- a/test/access/roles/WhitelistedRole.test.js +++ /dev/null @@ -1,16 +0,0 @@ -const { accounts, contract } = require('@openzeppelin/test-environment'); - -const { shouldBehaveLikePublicRole } = require('../../behaviors/access/roles/PublicRole.behavior'); -const WhitelistedRoleMock = contract.fromArtifact('WhitelistedRoleMock'); - -describe('WhitelistedRole', function () { - const [ whitelisted, otherWhitelisted, whitelistAdmin, ...otherAccounts ] = accounts; - - beforeEach(async function () { - this.contract = await WhitelistedRoleMock.new({ from: whitelistAdmin }); - await this.contract.addWhitelisted(whitelisted, { from: whitelistAdmin }); - await this.contract.addWhitelisted(otherWhitelisted, { from: whitelistAdmin }); - }); - - shouldBehaveLikePublicRole(whitelisted, otherWhitelisted, otherAccounts, 'whitelisted', whitelistAdmin); -}); diff --git a/test/crowdsale/AllowanceCrowdsale.test.js b/test/crowdsale/AllowanceCrowdsale.test.js deleted file mode 100644 index fa50d538a..000000000 --- a/test/crowdsale/AllowanceCrowdsale.test.js +++ /dev/null @@ -1,89 +0,0 @@ -const { accounts, contract } = require('@openzeppelin/test-environment'); - -const { balance, BN, constants, ether, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); -const { ZERO_ADDRESS } = constants; - -const { expect } = require('chai'); - -const AllowanceCrowdsaleImpl = contract.fromArtifact('AllowanceCrowdsaleImpl'); -const SimpleToken = contract.fromArtifact('SimpleToken'); - -describe('AllowanceCrowdsale', function () { - const [ investor, wallet, purchaser, tokenWallet ] = accounts; - - const rate = new BN('1'); - const value = ether('0.42'); - const expectedTokenAmount = rate.mul(value); - const tokenAllowance = new BN('10').pow(new BN('22')); - - beforeEach(async function () { - this.token = await SimpleToken.new({ from: tokenWallet }); - this.crowdsale = await AllowanceCrowdsaleImpl.new(rate, wallet, this.token.address, tokenWallet); - await this.token.approve(this.crowdsale.address, tokenAllowance, { from: tokenWallet }); - }); - - describe('accepting payments', function () { - it('should have token wallet', async function () { - expect(await this.crowdsale.tokenWallet()).to.equal(tokenWallet); - }); - - it('should accept sends', async function () { - await this.crowdsale.send(value); - }); - - it('should accept payments', async function () { - await this.crowdsale.buyTokens(investor, { value: value, from: purchaser }); - }); - }); - - describe('high-level purchase', function () { - it('should log purchase', async function () { - const { logs } = await this.crowdsale.sendTransaction({ value: value, from: investor }); - expectEvent.inLogs(logs, 'TokensPurchased', { - purchaser: investor, - beneficiary: investor, - value: value, - amount: expectedTokenAmount, - }); - }); - - it('should assign tokens to sender', async function () { - await this.crowdsale.sendTransaction({ value: value, from: investor }); - expect(await this.token.balanceOf(investor)).to.be.bignumber.equal(expectedTokenAmount); - }); - - it('should forward funds to wallet', async function () { - const balanceTracker = await balance.tracker(wallet); - await this.crowdsale.sendTransaction({ value, from: investor }); - expect(await balanceTracker.delta()).to.be.bignumber.equal(value); - }); - }); - - describe('check remaining allowance', function () { - it('should report correct allowance left', async function () { - const remainingAllowance = tokenAllowance.sub(expectedTokenAmount); - await this.crowdsale.buyTokens(investor, { value: value, from: purchaser }); - expect(await this.crowdsale.remainingTokens()).to.be.bignumber.equal(remainingAllowance); - }); - - context('when the allowance is larger than the token amount', function () { - beforeEach(async function () { - const amount = await this.token.balanceOf(tokenWallet); - await this.token.approve(this.crowdsale.address, amount.addn(1), { from: tokenWallet }); - }); - - it('should report the amount instead of the allowance', async function () { - expect(await this.crowdsale.remainingTokens()).to.be.bignumber.equal(await this.token.balanceOf(tokenWallet)); - }); - }); - }); - - describe('when token wallet is the zero address', function () { - it('creation reverts', async function () { - this.token = await SimpleToken.new({ from: tokenWallet }); - await expectRevert(AllowanceCrowdsaleImpl.new(rate, wallet, this.token.address, ZERO_ADDRESS), - 'AllowanceCrowdsale: token wallet is the zero address' - ); - }); - }); -}); diff --git a/test/crowdsale/CappedCrowdsale.test.js b/test/crowdsale/CappedCrowdsale.test.js deleted file mode 100644 index 9d193cbe8..000000000 --- a/test/crowdsale/CappedCrowdsale.test.js +++ /dev/null @@ -1,67 +0,0 @@ -const { accounts, contract } = require('@openzeppelin/test-environment'); - -const { BN, ether, expectRevert } = require('@openzeppelin/test-helpers'); - -const { expect } = require('chai'); - -const CappedCrowdsaleImpl = contract.fromArtifact('CappedCrowdsaleImpl'); -const SimpleToken = contract.fromArtifact('SimpleToken'); - -describe('CappedCrowdsale', function () { - const [ wallet ] = accounts; - - const rate = new BN('1'); - const cap = ether('100'); - const lessThanCap = ether('60'); - const tokenSupply = new BN('10').pow(new BN('22')); - - beforeEach(async function () { - this.token = await SimpleToken.new(); - }); - - it('rejects a cap of zero', async function () { - await expectRevert(CappedCrowdsaleImpl.new(rate, wallet, this.token.address, 0), - 'CappedCrowdsale: cap is 0' - ); - }); - - context('with crowdsale', function () { - beforeEach(async function () { - this.crowdsale = await CappedCrowdsaleImpl.new(rate, wallet, this.token.address, cap); - await this.token.transfer(this.crowdsale.address, tokenSupply); - }); - - describe('accepting payments', function () { - it('should accept payments within cap', async function () { - await this.crowdsale.send(cap.sub(lessThanCap)); - await this.crowdsale.send(lessThanCap); - }); - - it('should reject payments outside cap', async function () { - await this.crowdsale.send(cap); - await expectRevert(this.crowdsale.send(1), 'CappedCrowdsale: cap exceeded'); - }); - - it('should reject payments that exceed cap', async function () { - await expectRevert(this.crowdsale.send(cap.addn(1)), 'CappedCrowdsale: cap exceeded'); - }); - }); - - describe('ending', function () { - it('should not reach cap if sent under cap', async function () { - await this.crowdsale.send(lessThanCap); - expect(await this.crowdsale.capReached()).to.equal(false); - }); - - it('should not reach cap if sent just under cap', async function () { - await this.crowdsale.send(cap.subn(1)); - expect(await this.crowdsale.capReached()).to.equal(false); - }); - - it('should reach cap if cap sent', async function () { - await this.crowdsale.send(cap); - expect(await this.crowdsale.capReached()).to.equal(true); - }); - }); - }); -}); diff --git a/test/crowdsale/Crowdsale.test.js b/test/crowdsale/Crowdsale.test.js deleted file mode 100644 index 869cdacf4..000000000 --- a/test/crowdsale/Crowdsale.test.js +++ /dev/null @@ -1,129 +0,0 @@ -const { accounts, contract } = require('@openzeppelin/test-environment'); - -const { balance, BN, constants, ether, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); -const { ZERO_ADDRESS } = constants; - -const { expect } = require('chai'); - -const Crowdsale = contract.fromArtifact('CrowdsaleMock'); -const SimpleToken = contract.fromArtifact('SimpleToken'); - -describe('Crowdsale', function () { - const [ investor, wallet, purchaser ] = accounts; - - const rate = new BN(1); - const value = ether('42'); - const tokenSupply = new BN('10').pow(new BN('22')); - const expectedTokenAmount = rate.mul(value); - - it('requires a non-null token', async function () { - await expectRevert( - Crowdsale.new(rate, wallet, ZERO_ADDRESS), - 'Crowdsale: token is the zero address' - ); - }); - - context('with token', async function () { - beforeEach(async function () { - this.token = await SimpleToken.new(); - }); - - it('requires a non-zero rate', async function () { - await expectRevert( - Crowdsale.new(0, wallet, this.token.address), 'Crowdsale: rate is 0' - ); - }); - - it('requires a non-null wallet', async function () { - await expectRevert( - Crowdsale.new(rate, ZERO_ADDRESS, this.token.address), 'Crowdsale: wallet is the zero address' - ); - }); - - context('once deployed', async function () { - beforeEach(async function () { - this.crowdsale = await Crowdsale.new(rate, wallet, this.token.address); - await this.token.transfer(this.crowdsale.address, tokenSupply); - }); - - describe('accepting payments', function () { - describe('bare payments', function () { - it('should accept payments', async function () { - await this.crowdsale.send(value, { from: purchaser }); - }); - - it('reverts on zero-valued payments', async function () { - await expectRevert( - this.crowdsale.send(0, { from: purchaser }), 'Crowdsale: weiAmount is 0' - ); - }); - }); - - describe('buyTokens', function () { - it('should accept payments', async function () { - await this.crowdsale.buyTokens(investor, { value: value, from: purchaser }); - }); - - it('reverts on zero-valued payments', async function () { - await expectRevert( - this.crowdsale.buyTokens(investor, { value: 0, from: purchaser }), 'Crowdsale: weiAmount is 0' - ); - }); - - it('requires a non-null beneficiary', async function () { - await expectRevert( - this.crowdsale.buyTokens(ZERO_ADDRESS, { value: value, from: purchaser }), - 'Crowdsale: beneficiary is the zero address' - ); - }); - }); - }); - - describe('high-level purchase', function () { - it('should log purchase', async function () { - const { logs } = await this.crowdsale.sendTransaction({ value: value, from: investor }); - expectEvent.inLogs(logs, 'TokensPurchased', { - purchaser: investor, - beneficiary: investor, - value: value, - amount: expectedTokenAmount, - }); - }); - - it('should assign tokens to sender', async function () { - await this.crowdsale.sendTransaction({ value: value, from: investor }); - expect(await this.token.balanceOf(investor)).to.be.bignumber.equal(expectedTokenAmount); - }); - - it('should forward funds to wallet', async function () { - const balanceTracker = await balance.tracker(wallet); - await this.crowdsale.sendTransaction({ value, from: investor }); - expect(await balanceTracker.delta()).to.be.bignumber.equal(value); - }); - }); - - describe('low-level purchase', function () { - it('should log purchase', async function () { - const { logs } = await this.crowdsale.buyTokens(investor, { value: value, from: purchaser }); - expectEvent.inLogs(logs, 'TokensPurchased', { - purchaser: purchaser, - beneficiary: investor, - value: value, - amount: expectedTokenAmount, - }); - }); - - it('should assign tokens to beneficiary', async function () { - await this.crowdsale.buyTokens(investor, { value, from: purchaser }); - expect(await this.token.balanceOf(investor)).to.be.bignumber.equal(expectedTokenAmount); - }); - - it('should forward funds to wallet', async function () { - const balanceTracker = await balance.tracker(wallet); - await this.crowdsale.buyTokens(investor, { value, from: purchaser }); - expect(await balanceTracker.delta()).to.be.bignumber.equal(value); - }); - }); - }); - }); -}); diff --git a/test/crowdsale/FinalizableCrowdsale.test.js b/test/crowdsale/FinalizableCrowdsale.test.js deleted file mode 100644 index a59c621a1..000000000 --- a/test/crowdsale/FinalizableCrowdsale.test.js +++ /dev/null @@ -1,53 +0,0 @@ -const { accounts, contract } = require('@openzeppelin/test-environment'); - -const { BN, expectEvent, expectRevert, time } = require('@openzeppelin/test-helpers'); - -const FinalizableCrowdsaleImpl = contract.fromArtifact('FinalizableCrowdsaleImpl'); -const ERC20 = contract.fromArtifact('ERC20'); - -describe('FinalizableCrowdsale', function () { - const [ wallet, other ] = accounts; - - const rate = new BN('1000'); - - before(async function () { - // Advance to the next block to correctly read time in the solidity "now" function interpreted by ganache - await time.advanceBlock(); - }); - - beforeEach(async function () { - this.openingTime = (await time.latest()).add(time.duration.weeks(1)); - this.closingTime = this.openingTime.add(time.duration.weeks(1)); - this.afterClosingTime = this.closingTime.add(time.duration.seconds(1)); - - this.token = await ERC20.new(); - this.crowdsale = await FinalizableCrowdsaleImpl.new( - this.openingTime, this.closingTime, rate, wallet, this.token.address - ); - }); - - it('cannot be finalized before ending', async function () { - await expectRevert(this.crowdsale.finalize({ from: other }), - 'FinalizableCrowdsale: not closed' - ); - }); - - it('can be finalized by anyone after ending', async function () { - await time.increaseTo(this.afterClosingTime); - await this.crowdsale.finalize({ from: other }); - }); - - it('cannot be finalized twice', async function () { - await time.increaseTo(this.afterClosingTime); - await this.crowdsale.finalize({ from: other }); - await expectRevert(this.crowdsale.finalize({ from: other }), - 'FinalizableCrowdsale: already finalized' - ); - }); - - it('logs finalized', async function () { - await time.increaseTo(this.afterClosingTime); - const { logs } = await this.crowdsale.finalize({ from: other }); - expectEvent.inLogs(logs, 'CrowdsaleFinalized'); - }); -}); diff --git a/test/crowdsale/IncreasingPriceCrowdsale.test.js b/test/crowdsale/IncreasingPriceCrowdsale.test.js deleted file mode 100644 index 02103baf0..000000000 --- a/test/crowdsale/IncreasingPriceCrowdsale.test.js +++ /dev/null @@ -1,123 +0,0 @@ -const { accounts, contract } = require('@openzeppelin/test-environment'); - -const { BN, ether, expectRevert, time } = require('@openzeppelin/test-helpers'); - -const { expect } = require('chai'); - -const IncreasingPriceCrowdsaleImpl = contract.fromArtifact('IncreasingPriceCrowdsaleImpl'); -const SimpleToken = contract.fromArtifact('SimpleToken'); - -describe('IncreasingPriceCrowdsale', function () { - const [ investor, wallet, purchaser ] = accounts; - - const value = ether('1'); - const tokenSupply = new BN('10').pow(new BN('22')); - - describe('rate during crowdsale should change at a fixed step every block', async function () { - const initialRate = new BN('9166'); - const finalRate = new BN('5500'); - const rateAtTime150 = new BN('9166'); - const rateAtTime300 = new BN('9165'); - const rateAtTime1500 = new BN('9157'); - const rateAtTime30 = new BN('9166'); - const rateAtTime150000 = new BN('8257'); - const rateAtTime450000 = new BN('6439'); - - beforeEach(async function () { - await time.advanceBlock(); - this.startTime = (await time.latest()).add(time.duration.weeks(1)); - this.closingTime = this.startTime.add(time.duration.weeks(1)); - this.afterClosingTime = this.closingTime.add(time.duration.seconds(1)); - this.token = await SimpleToken.new(); - }); - - it('reverts with a final rate larger than the initial rate', async function () { - await expectRevert(IncreasingPriceCrowdsaleImpl.new( - this.startTime, this.closingTime, wallet, this.token.address, initialRate, initialRate.addn(1) - ), 'IncreasingPriceCrowdsale: initial rate is not greater than final rate'); - }); - - it('reverts with a final rate equal to the initial rate', async function () { - await expectRevert(IncreasingPriceCrowdsaleImpl.new( - this.startTime, this.closingTime, wallet, this.token.address, initialRate, initialRate - ), 'IncreasingPriceCrowdsale: initial rate is not greater than final rate'); - }); - - it('reverts with a final rate of zero', async function () { - await expectRevert(IncreasingPriceCrowdsaleImpl.new( - this.startTime, this.closingTime, wallet, this.token.address, initialRate, 0 - ), 'IncreasingPriceCrowdsale: final rate is 0'); - }); - - context('with crowdsale', function () { - beforeEach(async function () { - this.crowdsale = await IncreasingPriceCrowdsaleImpl.new( - this.startTime, this.closingTime, wallet, this.token.address, initialRate, finalRate - ); - await this.token.transfer(this.crowdsale.address, tokenSupply); - }); - - it('should have initial and final rate', async function () { - expect(await this.crowdsale.initialRate()).to.be.bignumber.equal(initialRate); - expect(await this.crowdsale.finalRate()).to.be.bignumber.equal(finalRate); - }); - - it('reverts when the base Crowdsale\'s rate function is called', async function () { - await expectRevert(this.crowdsale.rate(), - 'IncreasingPriceCrowdsale: rate() called' - ); - }); - - it('returns a rate of 0 before the crowdsale starts', async function () { - expect(await this.crowdsale.getCurrentRate()).to.be.bignumber.equal('0'); - }); - - it('returns a rate of 0 after the crowdsale ends', async function () { - await time.increaseTo(this.afterClosingTime); - expect(await this.crowdsale.getCurrentRate()).to.be.bignumber.equal('0'); - }); - - it('at start', async function () { - await time.increaseTo(this.startTime); - await this.crowdsale.buyTokens(investor, { value, from: purchaser }); - expect(await this.token.balanceOf(investor)).to.be.bignumber.equal(value.mul(initialRate)); - }); - - it('at time 150', async function () { - await time.increaseTo(this.startTime.addn(150)); - await this.crowdsale.buyTokens(investor, { value, from: purchaser }); - expect(await this.token.balanceOf(investor)).to.be.bignumber.equal(value.mul(rateAtTime150)); - }); - - it('at time 300', async function () { - await time.increaseTo(this.startTime.addn(300)); - await this.crowdsale.buyTokens(investor, { value, from: purchaser }); - expect(await this.token.balanceOf(investor)).to.be.bignumber.equal(value.mul(rateAtTime300)); - }); - - it('at time 1500', async function () { - await time.increaseTo(this.startTime.addn(1500)); - await this.crowdsale.buyTokens(investor, { value, from: purchaser }); - expect(await this.token.balanceOf(investor)).to.be.bignumber.equal(value.mul(rateAtTime1500)); - }); - - it('at time 30', async function () { - await time.increaseTo(this.startTime.addn(30)); - await this.crowdsale.buyTokens(investor, { value, from: purchaser }); - expect(await this.token.balanceOf(investor)).to.be.bignumber.equal(value.mul(rateAtTime30)); - }); - - it('at time 150000', async function () { - await time.increaseTo(this.startTime.addn(150000)); - await this.crowdsale.buyTokens(investor, { value, from: purchaser }); - expect(await this.token.balanceOf(investor)).to.be.bignumber.equal(value.mul(rateAtTime150000)); - }); - - it('at time 450000', async function () { - await time.increaseTo(this.startTime.addn(450000)); - await this.crowdsale.buyTokens(investor, { value, from: purchaser }); - expect(await this.token.balanceOf(investor)).to.be.bignumber.equal(value.mul(rateAtTime450000)); - }); - }); - }); -}); diff --git a/test/crowdsale/IndividuallyCappedCrowdsale.test.js b/test/crowdsale/IndividuallyCappedCrowdsale.test.js deleted file mode 100644 index f5214bd6e..000000000 --- a/test/crowdsale/IndividuallyCappedCrowdsale.test.js +++ /dev/null @@ -1,102 +0,0 @@ -const { accounts, contract } = require('@openzeppelin/test-environment'); - -const { BN, ether, expectRevert } = require('@openzeppelin/test-helpers'); - -const { expect } = require('chai'); - -const IndividuallyCappedCrowdsaleImpl = contract.fromArtifact('IndividuallyCappedCrowdsaleImpl'); -const SimpleToken = contract.fromArtifact('SimpleToken'); -const { shouldBehaveLikePublicRole } = require('../behaviors/access/roles/PublicRole.behavior'); - -describe('IndividuallyCappedCrowdsale', function () { - const [ capper, otherCapper, wallet, alice, bob, charlie, other, ...otherAccounts ] = accounts; - - const rate = new BN(1); - const capAlice = ether('10'); - const capBob = ether('2'); - const lessThanCapAlice = ether('6'); - const lessThanCapBoth = ether('1'); - const tokenSupply = new BN('10').pow(new BN('22')); - - beforeEach(async function () { - this.token = await SimpleToken.new(); - this.crowdsale = await IndividuallyCappedCrowdsaleImpl.new(rate, wallet, this.token.address, { from: capper }); - }); - - describe('capper role', function () { - beforeEach(async function () { - this.contract = this.crowdsale; - await this.contract.addCapper(otherCapper, { from: capper }); - }); - - shouldBehaveLikePublicRole(capper, otherCapper, otherAccounts, 'capper'); - }); - - describe('individual caps', function () { - it('sets a cap when the sender is a capper', async function () { - await this.crowdsale.setCap(alice, capAlice, { from: capper }); - expect(await this.crowdsale.getCap(alice)).to.be.bignumber.equal(capAlice); - }); - - it('reverts when a non-capper sets a cap', async function () { - await expectRevert(this.crowdsale.setCap(alice, capAlice, { from: other }), - 'CapperRole: caller does not have the Capper role' - ); - }); - - context('with individual caps', function () { - beforeEach(async function () { - await this.crowdsale.setCap(alice, capAlice, { from: capper }); - await this.crowdsale.setCap(bob, capBob, { from: capper }); - await this.token.transfer(this.crowdsale.address, tokenSupply); - }); - - describe('accepting payments', function () { - it('should accept payments within cap', async function () { - await this.crowdsale.buyTokens(alice, { value: lessThanCapAlice }); - await this.crowdsale.buyTokens(bob, { value: lessThanCapBoth }); - }); - - it('should reject payments outside cap', async function () { - await this.crowdsale.buyTokens(alice, { value: capAlice }); - await expectRevert(this.crowdsale.buyTokens(alice, { value: 1 }), - 'IndividuallyCappedCrowdsale: beneficiary\'s cap exceeded' - ); - }); - - it('should reject payments that exceed cap', async function () { - await expectRevert(this.crowdsale.buyTokens(alice, { value: capAlice.addn(1) }), - 'IndividuallyCappedCrowdsale: beneficiary\'s cap exceeded' - ); - await expectRevert(this.crowdsale.buyTokens(bob, { value: capBob.addn(1) }), - 'IndividuallyCappedCrowdsale: beneficiary\'s cap exceeded' - ); - }); - - it('should manage independent caps', async function () { - await this.crowdsale.buyTokens(alice, { value: lessThanCapAlice }); - await expectRevert(this.crowdsale.buyTokens(bob, { value: lessThanCapAlice }), - 'IndividuallyCappedCrowdsale: beneficiary\'s cap exceeded' - ); - }); - - it('should default to a cap of zero', async function () { - await expectRevert(this.crowdsale.buyTokens(charlie, { value: lessThanCapBoth }), - 'IndividuallyCappedCrowdsale: beneficiary\'s cap exceeded' - ); - }); - }); - - describe('reporting state', function () { - it('should report correct cap', async function () { - expect(await this.crowdsale.getCap(alice)).to.be.bignumber.equal(capAlice); - }); - - it('should report actual contribution', async function () { - await this.crowdsale.buyTokens(alice, { value: lessThanCapAlice }); - expect(await this.crowdsale.getContribution(alice)).to.be.bignumber.equal(lessThanCapAlice); - }); - }); - }); - }); -}); diff --git a/test/crowdsale/MintedCrowdsale.behavior.js b/test/crowdsale/MintedCrowdsale.behavior.js deleted file mode 100644 index 49aa3bcd5..000000000 --- a/test/crowdsale/MintedCrowdsale.behavior.js +++ /dev/null @@ -1,43 +0,0 @@ -const { balance, expectEvent } = require('@openzeppelin/test-helpers'); - -const { expect } = require('chai'); - -function shouldBehaveLikeMintedCrowdsale ([ investor, wallet, purchaser ], rate, value) { - const expectedTokenAmount = rate.mul(value); - - describe('as a minted crowdsale', function () { - describe('accepting payments', function () { - it('should accept payments', async function () { - await this.crowdsale.send(value); - await this.crowdsale.buyTokens(investor, { value: value, from: purchaser }); - }); - }); - - describe('high-level purchase', function () { - it('should log purchase', async function () { - const { logs } = await this.crowdsale.sendTransaction({ value: value, from: investor }); - expectEvent.inLogs(logs, 'TokensPurchased', { - purchaser: investor, - beneficiary: investor, - value: value, - amount: expectedTokenAmount, - }); - }); - - it('should assign tokens to sender', async function () { - await this.crowdsale.sendTransaction({ value: value, from: investor }); - expect(await this.token.balanceOf(investor)).to.be.bignumber.equal(expectedTokenAmount); - }); - - it('should forward funds to wallet', async function () { - const balanceTracker = await balance.tracker(wallet); - await this.crowdsale.sendTransaction({ value, from: investor }); - expect(await balanceTracker.delta()).to.be.bignumber.equal(value); - }); - }); - }); -} - -module.exports = { - shouldBehaveLikeMintedCrowdsale, -}; diff --git a/test/crowdsale/MintedCrowdsale.test.js b/test/crowdsale/MintedCrowdsale.test.js deleted file mode 100644 index 6a7343b56..000000000 --- a/test/crowdsale/MintedCrowdsale.test.js +++ /dev/null @@ -1,48 +0,0 @@ -const { accounts, contract } = require('@openzeppelin/test-environment'); - -const { BN, ether, expectRevert } = require('@openzeppelin/test-helpers'); -const { shouldBehaveLikeMintedCrowdsale } = require('./MintedCrowdsale.behavior'); - -const { expect } = require('chai'); - -const MintedCrowdsaleImpl = contract.fromArtifact('MintedCrowdsaleImpl'); -const ERC20Mintable = contract.fromArtifact('ERC20Mintable'); -const ERC20 = contract.fromArtifact('ERC20'); - -describe('MintedCrowdsale', function () { - const [ deployer, investor, wallet, purchaser ] = accounts; - - const rate = new BN('1000'); - const value = ether('5'); - - describe('using ERC20Mintable', function () { - beforeEach(async function () { - this.token = await ERC20Mintable.new({ from: deployer }); - this.crowdsale = await MintedCrowdsaleImpl.new(rate, wallet, this.token.address); - - await this.token.addMinter(this.crowdsale.address, { from: deployer }); - await this.token.renounceMinter({ from: deployer }); - }); - - it('crowdsale should be minter', async function () { - expect(await this.token.isMinter(this.crowdsale.address)).to.equal(true); - }); - - shouldBehaveLikeMintedCrowdsale([investor, wallet, purchaser], rate, value); - }); - - describe('using non-mintable token', function () { - beforeEach(async function () { - this.token = await ERC20.new(); - this.crowdsale = await MintedCrowdsaleImpl.new(rate, wallet, this.token.address); - }); - - it('rejects bare payments', async function () { - await expectRevert.unspecified(this.crowdsale.send(value)); - }); - - it('rejects token purchases', async function () { - await expectRevert.unspecified(this.crowdsale.buyTokens(investor, { value: value, from: purchaser })); - }); - }); -}); diff --git a/test/crowdsale/PausableCrowdsale.test.js b/test/crowdsale/PausableCrowdsale.test.js deleted file mode 100644 index ee87e976f..000000000 --- a/test/crowdsale/PausableCrowdsale.test.js +++ /dev/null @@ -1,52 +0,0 @@ -const { accounts, contract } = require('@openzeppelin/test-environment'); - -const { BN, expectRevert } = require('@openzeppelin/test-helpers'); - -const PausableCrowdsale = contract.fromArtifact('PausableCrowdsaleImpl'); -const SimpleToken = contract.fromArtifact('SimpleToken'); - -describe('PausableCrowdsale', function () { - const [ pauser, wallet, other ] = accounts; - - const rate = new BN(1); - const value = new BN(1); - - beforeEach(async function () { - const from = pauser; - - this.token = await SimpleToken.new({ from }); - this.crowdsale = await PausableCrowdsale.new(rate, wallet, this.token.address, { from }); - await this.token.transfer(this.crowdsale.address, value.muln(2), { from }); - }); - - it('purchases work', async function () { - await this.crowdsale.sendTransaction({ from: other, value }); - await this.crowdsale.buyTokens(other, { from: other, value }); - }); - - context('after pause', function () { - beforeEach(async function () { - await this.crowdsale.pause({ from: pauser }); - }); - - it('purchases do not work', async function () { - await expectRevert(this.crowdsale.sendTransaction({ from: other, value }), - 'Pausable: paused' - ); - await expectRevert(this.crowdsale.buyTokens(other, { from: other, value }), - 'Pausable: paused' - ); - }); - - context('after unpause', function () { - beforeEach(async function () { - await this.crowdsale.unpause({ from: pauser }); - }); - - it('purchases work', async function () { - await this.crowdsale.sendTransaction({ from: other, value }); - await this.crowdsale.buyTokens(other, { from: other, value }); - }); - }); - }); -}); diff --git a/test/crowdsale/PostDeliveryCrowdsale.test.js b/test/crowdsale/PostDeliveryCrowdsale.test.js deleted file mode 100644 index f05d59623..000000000 --- a/test/crowdsale/PostDeliveryCrowdsale.test.js +++ /dev/null @@ -1,75 +0,0 @@ -const { accounts, contract } = require('@openzeppelin/test-environment'); - -const { BN, ether, expectRevert, time } = require('@openzeppelin/test-helpers'); - -const { expect } = require('chai'); - -const PostDeliveryCrowdsaleImpl = contract.fromArtifact('PostDeliveryCrowdsaleImpl'); -const SimpleToken = contract.fromArtifact('SimpleToken'); - -describe('PostDeliveryCrowdsale', function () { - const [ investor, wallet, purchaser ] = accounts; - - const rate = new BN(1); - const tokenSupply = new BN('10').pow(new BN('22')); - - before(async function () { - // Advance to the next block to correctly read time in the solidity "now" function interpreted by ganache - await time.advanceBlock(); - }); - - beforeEach(async function () { - this.openingTime = (await time.latest()).add(time.duration.weeks(1)); - this.closingTime = this.openingTime.add(time.duration.weeks(1)); - this.afterClosingTime = this.closingTime.add(time.duration.seconds(1)); - this.token = await SimpleToken.new(); - this.crowdsale = await PostDeliveryCrowdsaleImpl.new( - this.openingTime, this.closingTime, rate, wallet, this.token.address - ); - await this.token.transfer(this.crowdsale.address, tokenSupply); - }); - - context('after opening time', function () { - beforeEach(async function () { - await time.increaseTo(this.openingTime); - }); - - context('with bought tokens', function () { - const value = ether('42'); - - beforeEach(async function () { - await this.crowdsale.buyTokens(investor, { value: value, from: purchaser }); - }); - - it('does not immediately assign tokens to beneficiaries', async function () { - expect(await this.crowdsale.balanceOf(investor)).to.be.bignumber.equal(value); - expect(await this.token.balanceOf(investor)).to.be.bignumber.equal('0'); - }); - - it('does not allow beneficiaries to withdraw tokens before crowdsale ends', async function () { - await expectRevert(this.crowdsale.withdrawTokens(investor), - 'PostDeliveryCrowdsale: not closed' - ); - }); - - context('after closing time', function () { - beforeEach(async function () { - await time.increaseTo(this.afterClosingTime); - }); - - it('allows beneficiaries to withdraw tokens', async function () { - await this.crowdsale.withdrawTokens(investor); - expect(await this.crowdsale.balanceOf(investor)).to.be.bignumber.equal('0'); - expect(await this.token.balanceOf(investor)).to.be.bignumber.equal(value); - }); - - it('rejects multiple withdrawals', async function () { - await this.crowdsale.withdrawTokens(investor); - await expectRevert(this.crowdsale.withdrawTokens(investor), - 'PostDeliveryCrowdsale: beneficiary is not due any tokens' - ); - }); - }); - }); - }); -}); diff --git a/test/crowdsale/RefundableCrowdsale.test.js b/test/crowdsale/RefundableCrowdsale.test.js deleted file mode 100644 index 2b088134c..000000000 --- a/test/crowdsale/RefundableCrowdsale.test.js +++ /dev/null @@ -1,111 +0,0 @@ -const { accounts, contract } = require('@openzeppelin/test-environment'); - -const { balance, BN, ether, expectRevert, time } = require('@openzeppelin/test-helpers'); - -const { expect } = require('chai'); - -const RefundableCrowdsaleImpl = contract.fromArtifact('RefundableCrowdsaleImpl'); -const SimpleToken = contract.fromArtifact('SimpleToken'); - -describe('RefundableCrowdsale', function () { - const [ wallet, investor, other ] = accounts; - - const rate = new BN(1); - const goal = ether('50'); - const lessThanGoal = ether('45'); - const tokenSupply = new BN('10').pow(new BN('22')); - - before(async function () { - // Advance to the next block to correctly read time in the solidity "now" function interpreted by ganache - await time.advanceBlock(); - }); - - beforeEach(async function () { - this.openingTime = (await time.latest()).add(time.duration.weeks(1)); - this.closingTime = this.openingTime.add(time.duration.weeks(1)); - this.afterClosingTime = this.closingTime.add(time.duration.seconds(1)); - this.preWalletBalance = await balance.current(wallet); - - this.token = await SimpleToken.new(); - }); - - it('rejects a goal of zero', async function () { - await expectRevert( - RefundableCrowdsaleImpl.new(this.openingTime, this.closingTime, rate, wallet, this.token.address, 0), - 'RefundableCrowdsale: goal is 0' - ); - }); - - context('with crowdsale', function () { - beforeEach(async function () { - this.crowdsale = await RefundableCrowdsaleImpl.new( - this.openingTime, this.closingTime, rate, wallet, this.token.address, goal - ); - - await this.token.transfer(this.crowdsale.address, tokenSupply); - }); - - context('before opening time', function () { - it('denies refunds', async function () { - await expectRevert(this.crowdsale.claimRefund(investor), - 'RefundableCrowdsale: not finalized' - ); - }); - }); - - context('after opening time', function () { - beforeEach(async function () { - await time.increaseTo(this.openingTime); - }); - - it('denies refunds', async function () { - await expectRevert(this.crowdsale.claimRefund(investor), - 'RefundableCrowdsale: not finalized' - ); - }); - - context('with unreached goal', function () { - beforeEach(async function () { - await this.crowdsale.sendTransaction({ value: lessThanGoal, from: investor }); - }); - - context('after closing time and finalization', function () { - beforeEach(async function () { - await time.increaseTo(this.afterClosingTime); - await this.crowdsale.finalize({ from: other }); - }); - - it('refunds', async function () { - const balanceTracker = await balance.tracker(investor); - await this.crowdsale.claimRefund(investor, { gasPrice: 0 }); - expect(await balanceTracker.delta()).to.be.bignumber.equal(lessThanGoal); - }); - }); - }); - - context('with reached goal', function () { - beforeEach(async function () { - await this.crowdsale.sendTransaction({ value: goal, from: investor }); - }); - - context('after closing time and finalization', function () { - beforeEach(async function () { - await time.increaseTo(this.afterClosingTime); - await this.crowdsale.finalize({ from: other }); - }); - - it('denies refunds', async function () { - await expectRevert(this.crowdsale.claimRefund(investor), - 'RefundableCrowdsale: goal reached' - ); - }); - - it('forwards funds to wallet', async function () { - const postWalletBalance = await balance.current(wallet); - expect(postWalletBalance.sub(this.preWalletBalance)).to.be.bignumber.equal(goal); - }); - }); - }); - }); - }); -}); diff --git a/test/crowdsale/RefundablePostDeliveryCrowdsale.test.js b/test/crowdsale/RefundablePostDeliveryCrowdsale.test.js deleted file mode 100644 index 3f52c8077..000000000 --- a/test/crowdsale/RefundablePostDeliveryCrowdsale.test.js +++ /dev/null @@ -1,109 +0,0 @@ -const { accounts, contract } = require('@openzeppelin/test-environment'); - -const { BN, ether, expectRevert, time } = require('@openzeppelin/test-helpers'); - -const { expect } = require('chai'); - -const RefundablePostDeliveryCrowdsaleImpl = contract.fromArtifact('RefundablePostDeliveryCrowdsaleImpl'); -const SimpleToken = contract.fromArtifact('SimpleToken'); - -describe('RefundablePostDeliveryCrowdsale', function () { - const [ investor, wallet, purchaser ] = accounts; - - const rate = new BN(1); - const tokenSupply = new BN('10').pow(new BN('22')); - const goal = ether('100'); - - before(async function () { - // Advance to the next block to correctly read time in the solidity "now" function interpreted by ganache - await time.advanceBlock(); - }); - - beforeEach(async function () { - this.openingTime = (await time.latest()).add(time.duration.weeks(1)); - this.closingTime = this.openingTime.add(time.duration.weeks(1)); - this.afterClosingTime = this.closingTime.add(time.duration.seconds(1)); - this.token = await SimpleToken.new(); - this.crowdsale = await RefundablePostDeliveryCrowdsaleImpl.new( - this.openingTime, this.closingTime, rate, wallet, this.token.address, goal - ); - await this.token.transfer(this.crowdsale.address, tokenSupply); - }); - - context('after opening time', function () { - beforeEach(async function () { - await time.increaseTo(this.openingTime); - }); - - context('with bought tokens below the goal', function () { - const value = goal.subn(1); - - beforeEach(async function () { - await this.crowdsale.buyTokens(investor, { value: value, from: purchaser }); - }); - - it('does not immediately deliver tokens to beneficiaries', async function () { - expect(await this.crowdsale.balanceOf(investor)).to.be.bignumber.equal(value); - expect(await this.token.balanceOf(investor)).to.be.bignumber.equal('0'); - }); - - it('does not allow beneficiaries to withdraw tokens before crowdsale ends', async function () { - await expectRevert(this.crowdsale.withdrawTokens(investor), - 'RefundablePostDeliveryCrowdsale: not finalized' - ); - }); - - context('after closing time and finalization', function () { - beforeEach(async function () { - await time.increaseTo(this.afterClosingTime); - await this.crowdsale.finalize(); - }); - - it('rejects token withdrawals', async function () { - await expectRevert(this.crowdsale.withdrawTokens(investor), - 'RefundablePostDeliveryCrowdsale: goal not reached' - ); - }); - }); - }); - - context('with bought tokens matching the goal', function () { - const value = goal; - - beforeEach(async function () { - await this.crowdsale.buyTokens(investor, { value: value, from: purchaser }); - }); - - it('does not immediately deliver tokens to beneficiaries', async function () { - expect(await this.crowdsale.balanceOf(investor)).to.be.bignumber.equal(value); - expect(await this.token.balanceOf(investor)).to.be.bignumber.equal('0'); - }); - - it('does not allow beneficiaries to withdraw tokens before crowdsale ends', async function () { - await expectRevert(this.crowdsale.withdrawTokens(investor), - 'RefundablePostDeliveryCrowdsale: not finalized' - ); - }); - - context('after closing time and finalization', function () { - beforeEach(async function () { - await time.increaseTo(this.afterClosingTime); - await this.crowdsale.finalize(); - }); - - it('allows beneficiaries to withdraw tokens', async function () { - await this.crowdsale.withdrawTokens(investor); - expect(await this.crowdsale.balanceOf(investor)).to.be.bignumber.equal('0'); - expect(await this.token.balanceOf(investor)).to.be.bignumber.equal(value); - }); - - it('rejects multiple withdrawals', async function () { - await this.crowdsale.withdrawTokens(investor); - await expectRevert(this.crowdsale.withdrawTokens(investor), - 'PostDeliveryCrowdsale: beneficiary is not due any tokens' - ); - }); - }); - }); - }); -}); diff --git a/test/crowdsale/TimedCrowdsale.test.js b/test/crowdsale/TimedCrowdsale.test.js deleted file mode 100644 index 0d98d71d5..000000000 --- a/test/crowdsale/TimedCrowdsale.test.js +++ /dev/null @@ -1,150 +0,0 @@ -const { accounts, contract } = require('@openzeppelin/test-environment'); - -const { BN, ether, expectEvent, expectRevert, time } = require('@openzeppelin/test-helpers'); - -const { expect } = require('chai'); - -const TimedCrowdsaleImpl = contract.fromArtifact('TimedCrowdsaleImpl'); -const SimpleToken = contract.fromArtifact('SimpleToken'); - -describe('TimedCrowdsale', function () { - const [ investor, wallet, purchaser ] = accounts; - - const rate = new BN(1); - const value = ether('42'); - const tokenSupply = new BN('10').pow(new BN('22')); - - before(async function () { - // Advance to the next block to correctly read time in the solidity "now" function interpreted by ganache - await time.advanceBlock(); - }); - - beforeEach(async function () { - this.openingTime = (await time.latest()).add(time.duration.weeks(1)); - this.closingTime = this.openingTime.add(time.duration.weeks(1)); - this.afterClosingTime = this.closingTime.add(time.duration.seconds(1)); - this.token = await SimpleToken.new(); - }); - - it('reverts if the opening time is in the past', async function () { - await expectRevert(TimedCrowdsaleImpl.new( - (await time.latest()).sub(time.duration.days(1)), this.closingTime, rate, wallet, this.token.address - ), 'TimedCrowdsale: opening time is before current time'); - }); - - it('reverts if the closing time is before the opening time', async function () { - await expectRevert(TimedCrowdsaleImpl.new( - this.openingTime, this.openingTime.sub(time.duration.seconds(1)), rate, wallet, this.token.address - ), 'TimedCrowdsale: opening time is not before closing time'); - }); - - it('reverts if the closing time equals the opening time', async function () { - await expectRevert(TimedCrowdsaleImpl.new( - this.openingTime, this.openingTime, rate, wallet, this.token.address - ), 'TimedCrowdsale: opening time is not before closing time'); - }); - - context('with crowdsale', function () { - beforeEach(async function () { - this.crowdsale = await TimedCrowdsaleImpl.new( - this.openingTime, this.closingTime, rate, wallet, this.token.address - ); - await this.token.transfer(this.crowdsale.address, tokenSupply); - }); - - it('should be ended only after end', async function () { - expect(await this.crowdsale.hasClosed()).to.equal(false); - await time.increaseTo(this.afterClosingTime); - expect(await this.crowdsale.isOpen()).to.equal(false); - expect(await this.crowdsale.hasClosed()).to.equal(true); - }); - - describe('accepting payments', function () { - it('should reject payments before start', async function () { - expect(await this.crowdsale.isOpen()).to.equal(false); - await expectRevert(this.crowdsale.send(value), 'TimedCrowdsale: not open'); - await expectRevert(this.crowdsale.buyTokens(investor, { from: purchaser, value: value }), - 'TimedCrowdsale: not open' - ); - }); - - it('should accept payments after start', async function () { - await time.increaseTo(this.openingTime); - expect(await this.crowdsale.isOpen()).to.equal(true); - await this.crowdsale.send(value); - await this.crowdsale.buyTokens(investor, { value: value, from: purchaser }); - }); - - it('should reject payments after end', async function () { - await time.increaseTo(this.afterClosingTime); - await expectRevert(this.crowdsale.send(value), 'TimedCrowdsale: not open'); - await expectRevert(this.crowdsale.buyTokens(investor, { value: value, from: purchaser }), - 'TimedCrowdsale: not open' - ); - }); - }); - - describe('extending closing time', function () { - it('should not reduce duration', async function () { - // Same date - await expectRevert(this.crowdsale.extendTime(this.closingTime), - 'TimedCrowdsale: new closing time is before current closing time' - ); - - // Prescending date - const newClosingTime = this.closingTime.sub(time.duration.seconds(1)); - await expectRevert(this.crowdsale.extendTime(newClosingTime), - 'TimedCrowdsale: new closing time is before current closing time' - ); - }); - - context('before crowdsale start', function () { - beforeEach(async function () { - expect(await this.crowdsale.isOpen()).to.equal(false); - await expectRevert(this.crowdsale.send(value), 'TimedCrowdsale: not open'); - }); - - it('it extends end time', async function () { - const newClosingTime = this.closingTime.add(time.duration.days(1)); - const { logs } = await this.crowdsale.extendTime(newClosingTime); - expectEvent.inLogs(logs, 'TimedCrowdsaleExtended', { - prevClosingTime: this.closingTime, - newClosingTime: newClosingTime, - }); - expect(await this.crowdsale.closingTime()).to.be.bignumber.equal(newClosingTime); - }); - }); - - context('after crowdsale start', function () { - beforeEach(async function () { - await time.increaseTo(this.openingTime); - expect(await this.crowdsale.isOpen()).to.equal(true); - await this.crowdsale.send(value); - }); - - it('it extends end time', async function () { - const newClosingTime = this.closingTime.add(time.duration.days(1)); - const { logs } = await this.crowdsale.extendTime(newClosingTime); - expectEvent.inLogs(logs, 'TimedCrowdsaleExtended', { - prevClosingTime: this.closingTime, - newClosingTime: newClosingTime, - }); - expect(await this.crowdsale.closingTime()).to.be.bignumber.equal(newClosingTime); - }); - }); - - context('after crowdsale end', function () { - beforeEach(async function () { - await time.increaseTo(this.afterClosingTime); - }); - - it('it reverts', async function () { - const newClosingTime = await time.latest(); - await expectRevert(this.crowdsale.extendTime(newClosingTime), - 'TimedCrowdsale: already closed' - ); - }); - }); - }); - }); -}); diff --git a/test/crowdsale/WhitelistCrowdsale.test.js b/test/crowdsale/WhitelistCrowdsale.test.js deleted file mode 100644 index bcd8a8c13..000000000 --- a/test/crowdsale/WhitelistCrowdsale.test.js +++ /dev/null @@ -1,61 +0,0 @@ -const { accounts, contract } = require('@openzeppelin/test-environment'); - -const { BN, ether, expectRevert } = require('@openzeppelin/test-helpers'); - -const WhitelistCrowdsale = contract.fromArtifact('WhitelistCrowdsaleImpl'); -const SimpleToken = contract.fromArtifact('SimpleToken'); - -describe('WhitelistCrowdsale', function () { - const [ wallet, whitelister, whitelisted, otherWhitelisted, other ] = accounts; - - const rate = new BN(1); - const value = ether('42'); - const tokenSupply = new BN('10').pow(new BN('22')); - - beforeEach(async function () { - this.token = await SimpleToken.new({ from: whitelister }); - this.crowdsale = await WhitelistCrowdsale.new(rate, wallet, this.token.address, { from: whitelister }); - await this.token.transfer(this.crowdsale.address, tokenSupply, { from: whitelister }); - }); - - async function purchaseShouldSucceed (crowdsale, beneficiary, value) { - await crowdsale.buyTokens(beneficiary, { from: beneficiary, value }); - await crowdsale.sendTransaction({ from: beneficiary, value }); - } - - async function purchaseExpectRevert (crowdsale, beneficiary, value) { - await expectRevert(crowdsale.buyTokens(beneficiary, { from: beneficiary, value }), - 'WhitelistCrowdsale: beneficiary doesn\'t have the Whitelisted role' - ); - await expectRevert(crowdsale.sendTransaction({ from: beneficiary, value }), - 'WhitelistCrowdsale: beneficiary doesn\'t have the Whitelisted role' - ); - } - - context('with no whitelisted addresses', function () { - it('rejects all purchases', async function () { - await purchaseExpectRevert(this.crowdsale, other, value); - await purchaseExpectRevert(this.crowdsale, whitelisted, value); - }); - }); - - context('with whitelisted addresses', function () { - beforeEach(async function () { - await this.crowdsale.addWhitelisted(whitelisted, { from: whitelister }); - await this.crowdsale.addWhitelisted(otherWhitelisted, { from: whitelister }); - }); - - it('accepts purchases with whitelisted beneficiaries', async function () { - await purchaseShouldSucceed(this.crowdsale, whitelisted, value); - await purchaseShouldSucceed(this.crowdsale, otherWhitelisted, value); - }); - - it('rejects purchases from whitelisted addresses with non-whitelisted beneficiaries', async function () { - await expectRevert.unspecified(this.crowdsale.buyTokens(other, { from: whitelisted, value })); - }); - - it('rejects purchases with non-whitelisted beneficiaries', async function () { - await purchaseExpectRevert(this.crowdsale, other, value); - }); - }); -}); diff --git a/test/drafts/ERC20Migrator.test.js b/test/drafts/ERC20Migrator.test.js deleted file mode 100644 index 07df5fcbf..000000000 --- a/test/drafts/ERC20Migrator.test.js +++ /dev/null @@ -1,203 +0,0 @@ -const { accounts, contract } = require('@openzeppelin/test-environment'); - -const { BN, constants, expectRevert } = require('@openzeppelin/test-helpers'); -const { ZERO_ADDRESS } = constants; - -const { expect } = require('chai'); - -const ERC20Mock = contract.fromArtifact('ERC20Mock'); -const ERC20Mintable = contract.fromArtifact('ERC20Mintable'); -const ERC20Migrator = contract.fromArtifact('ERC20Migrator'); - -describe('ERC20Migrator', function () { - const [ owner ] = accounts; - - const totalSupply = new BN('200'); - - it('reverts with a null legacy token address', async function () { - await expectRevert(ERC20Migrator.new(ZERO_ADDRESS), - 'ERC20Migrator: legacy token is the zero address' - ); - }); - - describe('with tokens and migrator', function () { - beforeEach('deploying tokens and migrator', async function () { - this.legacyToken = await ERC20Mock.new(owner, totalSupply); - this.migrator = await ERC20Migrator.new(this.legacyToken.address); - this.newToken = await ERC20Mintable.new(); - }); - - it('returns legacy token', async function () { - expect(await this.migrator.legacyToken()).to.equal(this.legacyToken.address); - }); - - describe('beginMigration', function () { - it('reverts with a null new token address', async function () { - await expectRevert(this.migrator.beginMigration(ZERO_ADDRESS), - 'ERC20Migrator: new token is the zero address' - ); - }); - - it('reverts if not a minter of the token', async function () { - await expectRevert(this.migrator.beginMigration(this.newToken.address), - 'ERC20Migrator: not a minter for new token' - ); - }); - - it('succeeds if it is a minter of the token', async function () { - await this.newToken.addMinter(this.migrator.address); - await this.migrator.beginMigration(this.newToken.address); - }); - - it('reverts the second time it is called', async function () { - await this.newToken.addMinter(this.migrator.address); - await this.migrator.beginMigration(this.newToken.address); - await expectRevert(this.migrator.beginMigration(this.newToken.address), - 'ERC20Migrator: migration already started' - ); - }); - }); - - context('before starting the migration', function () { - it('returns the zero address for the new token', async function () { - expect(await this.migrator.newToken()).to.equal(ZERO_ADDRESS); - }); - - describe('migrateAll', function () { - const amount = totalSupply; - - describe('when the approved balance is equal to the owned balance', function () { - beforeEach('approving the whole balance to the new contract', async function () { - await this.legacyToken.approve(this.migrator.address, amount, { from: owner }); - }); - - it('reverts', async function () { - await expectRevert(this.migrator.migrateAll(owner), - 'ERC20Migrator: migration not started' - ); - }); - }); - }); - - describe('migrate', function () { - const amount = new BN(50); - - describe('when the amount is equal to the approved value', function () { - beforeEach('approving tokens to the new contract', async function () { - await this.legacyToken.approve(this.migrator.address, amount, { from: owner }); - }); - - it('reverts', async function () { - await expectRevert(this.migrator.migrate(owner, amount), - 'ERC20Migrator: migration not started' - ); - }); - }); - }); - }); - - describe('once migration began', function () { - beforeEach('beginning migration', async function () { - await this.newToken.addMinter(this.migrator.address); - await this.migrator.beginMigration(this.newToken.address); - }); - - it('returns new token', async function () { - expect(await this.migrator.newToken()).to.equal(this.newToken.address); - }); - - describe('migrateAll', function () { - const baseAmount = totalSupply; - - describe('when the approved balance is equal to the owned balance', function () { - const amount = baseAmount; - - beforeEach('approving the whole balance to the new contract', async function () { - await this.legacyToken.approve(this.migrator.address, amount, { from: owner }); - }); - - beforeEach('migrating token', async function () { - const tx = await this.migrator.migrateAll(owner); - this.logs = tx.receipt.logs; - }); - - it('mints the same balance of the new token', async function () { - const currentBalance = await this.newToken.balanceOf(owner); - expect(currentBalance).to.be.bignumber.equal(amount); - }); - - it('burns a given amount of old tokens', async function () { - const currentBurnedBalance = await this.legacyToken.balanceOf(this.migrator.address); - expect(currentBurnedBalance).to.be.bignumber.equal(amount); - - const currentLegacyTokenBalance = await this.legacyToken.balanceOf(owner); - expect(currentLegacyTokenBalance).to.be.bignumber.equal('0'); - }); - - it('updates the total supply', async function () { - const currentSupply = await this.newToken.totalSupply(); - expect(currentSupply).to.be.bignumber.equal(amount); - }); - }); - - describe('when the approved balance is lower than the owned balance', function () { - const amount = baseAmount.subn(1); - - beforeEach('approving part of the balance to the new contract', async function () { - await this.legacyToken.approve(this.migrator.address, amount, { from: owner }); - await this.migrator.migrateAll(owner); - }); - - it('migrates only approved amount', async function () { - const currentBalance = await this.newToken.balanceOf(owner); - expect(currentBalance).to.be.bignumber.equal(amount); - }); - }); - }); - - describe('migrate', function () { - const baseAmount = new BN(50); - - beforeEach('approving tokens to the new contract', async function () { - await this.legacyToken.approve(this.migrator.address, baseAmount, { from: owner }); - }); - - describe('when the amount is equal to the one approved', function () { - const amount = baseAmount; - - beforeEach('migrate token', async function () { - ({ logs: this.logs } = await this.migrator.migrate(owner, amount)); - }); - - it('mints that amount of the new token', async function () { - const currentBalance = await this.newToken.balanceOf(owner); - expect(currentBalance).to.be.bignumber.equal(amount); - }); - - it('burns a given amount of old tokens', async function () { - const currentBurnedBalance = await this.legacyToken.balanceOf(this.migrator.address); - expect(currentBurnedBalance).to.be.bignumber.equal(amount); - - const currentLegacyTokenBalance = await this.legacyToken.balanceOf(owner); - expect(currentLegacyTokenBalance).to.be.bignumber.equal(totalSupply.sub(amount)); - }); - - it('updates the total supply', async function () { - const currentSupply = await this.newToken.totalSupply(); - expect(currentSupply).to.be.bignumber.equal(amount); - }); - }); - - describe('when the given amount is higher than the one approved', function () { - const amount = baseAmount.addn(1); - - it('reverts', async function () { - await expectRevert(this.migrator.migrate(owner, amount), - 'SafeERC20: low-level call failed' - ); - }); - }); - }); - }); - }); -}); diff --git a/test/drafts/TokenVesting.test.js b/test/drafts/TokenVesting.test.js index b085d31c1..3eb2d7c51 100644 --- a/test/drafts/TokenVesting.test.js +++ b/test/drafts/TokenVesting.test.js @@ -5,7 +5,7 @@ const { ZERO_ADDRESS } = constants; const { expect } = require('chai'); -const ERC20Mintable = contract.fromArtifact('ERC20Mintable'); +const ERC20Mock = contract.fromArtifact('ERC20Mock'); const TokenVesting = contract.fromArtifact('TokenVesting'); describe('TokenVesting', function () { @@ -61,8 +61,7 @@ describe('TokenVesting', function () { this.vesting = await TokenVesting.new( beneficiary, this.start, this.cliffDuration, this.duration, true, { from: owner }); - this.token = await ERC20Mintable.new({ from: owner }); - await this.token.mint(this.vesting.address, amount, { from: owner }); + this.token = await ERC20Mock.new(this.vesting.address, amount); }); it('can get state', async function () { diff --git a/test/examples/SampleCrowdsale.test.js b/test/examples/SampleCrowdsale.test.js deleted file mode 100644 index 555500c60..000000000 --- a/test/examples/SampleCrowdsale.test.js +++ /dev/null @@ -1,111 +0,0 @@ -const { accounts, contract } = require('@openzeppelin/test-environment'); - -const { BN, balance, ether, expectRevert, time } = require('@openzeppelin/test-helpers'); - -const { expect } = require('chai'); - -const SampleCrowdsale = contract.fromArtifact('SampleCrowdsale'); -const SampleCrowdsaleToken = contract.fromArtifact('SampleCrowdsaleToken'); - -describe('SampleCrowdsale', function () { - const [ deployer, owner, wallet, investor ] = accounts; - - const RATE = new BN(10); - const GOAL = ether('10'); - const CAP = ether('20'); - - before(async function () { - // Advance to the next block to correctly read time in the solidity "now" function interpreted by ganache - await time.advanceBlock(); - }); - - beforeEach(async function () { - this.openingTime = (await time.latest()).add(time.duration.weeks(1)); - this.closingTime = this.openingTime.add(time.duration.weeks(1)); - this.afterClosingTime = this.closingTime.add(time.duration.seconds(1)); - - this.token = await SampleCrowdsaleToken.new({ from: deployer }); - this.crowdsale = await SampleCrowdsale.new( - this.openingTime, this.closingTime, RATE, wallet, CAP, this.token.address, GOAL, - { from: owner } - ); - - await this.token.addMinter(this.crowdsale.address, { from: deployer }); - await this.token.renounceMinter({ from: deployer }); - }); - - it('should create crowdsale with correct parameters', async function () { - expect(await this.crowdsale.openingTime()).to.be.bignumber.equal(this.openingTime); - expect(await this.crowdsale.closingTime()).to.be.bignumber.equal(this.closingTime); - expect(await this.crowdsale.rate()).to.be.bignumber.equal(RATE); - expect(await this.crowdsale.wallet()).to.equal(wallet); - expect(await this.crowdsale.goal()).to.be.bignumber.equal(GOAL); - expect(await this.crowdsale.cap()).to.be.bignumber.equal(CAP); - }); - - it('should not accept payments before start', async function () { - await expectRevert(this.crowdsale.send(ether('1')), 'TimedCrowdsale: not open'); - await expectRevert(this.crowdsale.buyTokens(investor, { from: investor, value: ether('1') }), - 'TimedCrowdsale: not open' - ); - }); - - it('should accept payments during the sale', async function () { - const investmentAmount = ether('1'); - const expectedTokenAmount = RATE.mul(investmentAmount); - - await time.increaseTo(this.openingTime); - await this.crowdsale.buyTokens(investor, { value: investmentAmount, from: investor }); - - expect(await this.token.balanceOf(investor)).to.be.bignumber.equal(expectedTokenAmount); - expect(await this.token.totalSupply()).to.be.bignumber.equal(expectedTokenAmount); - }); - - it('should reject payments after end', async function () { - await time.increaseTo(this.afterClosingTime); - await expectRevert(this.crowdsale.send(ether('1')), 'TimedCrowdsale: not open'); - await expectRevert(this.crowdsale.buyTokens(investor, { value: ether('1'), from: investor }), - 'TimedCrowdsale: not open' - ); - }); - - it('should reject payments over cap', async function () { - await time.increaseTo(this.openingTime); - await this.crowdsale.send(CAP); - await expectRevert(this.crowdsale.send(1), 'CappedCrowdsale: cap exceeded'); - }); - - it('should allow finalization and transfer funds to wallet if the goal is reached', async function () { - await time.increaseTo(this.openingTime); - await this.crowdsale.send(GOAL); - - const balanceTracker = await balance.tracker(wallet); - await time.increaseTo(this.afterClosingTime); - await this.crowdsale.finalize({ from: owner }); - expect(await balanceTracker.delta()).to.be.bignumber.equal(GOAL); - }); - - it('should allow refunds if the goal is not reached', async function () { - const balanceTracker = await balance.tracker(investor); - - await time.increaseTo(this.openingTime); - await this.crowdsale.sendTransaction({ value: ether('1'), from: investor, gasPrice: 0 }); - await time.increaseTo(this.afterClosingTime); - - await this.crowdsale.finalize({ from: owner }); - await this.crowdsale.claimRefund(investor, { gasPrice: 0 }); - - expect(await balanceTracker.delta()).to.be.bignumber.equal('0'); - }); - - describe('when goal > cap', function () { - // goal > cap - const HIGH_GOAL = ether('30'); - - it('creation reverts', async function () { - await expectRevert(SampleCrowdsale.new( - this.openingTime, this.closingTime, RATE, wallet, CAP, this.token.address, HIGH_GOAL - ), 'SampleCrowdSale: goal is greater than cap'); - }); - }); -}); diff --git a/test/examples/SimpleToken.test.js b/test/examples/SimpleToken.test.js deleted file mode 100644 index 52deb77b9..000000000 --- a/test/examples/SimpleToken.test.js +++ /dev/null @@ -1,41 +0,0 @@ -const { accounts, contract } = require('@openzeppelin/test-environment'); - -const { constants, expectEvent } = require('@openzeppelin/test-helpers'); -const { ZERO_ADDRESS } = constants; - -const { expect } = require('chai'); - -const SimpleToken = contract.fromArtifact('SimpleToken'); - -describe('SimpleToken', function () { - const [ creator ] = accounts; - - beforeEach(async function () { - this.token = await SimpleToken.new({ from: creator }); - }); - - it('has a name', async function () { - expect(await this.token.name()).to.equal('SimpleToken'); - }); - - it('has a symbol', async function () { - expect(await this.token.symbol()).to.equal('SIM'); - }); - - it('has 18 decimals', async function () { - expect(await this.token.decimals()).to.be.bignumber.equal('18'); - }); - - it('assigns the initial total supply to the creator', async function () { - const totalSupply = await this.token.totalSupply(); - const creatorBalance = await this.token.balanceOf(creator); - - expect(creatorBalance).to.be.bignumber.equal(totalSupply); - - await expectEvent.inConstruction(this.token, 'Transfer', { - from: ZERO_ADDRESS, - to: creator, - value: totalSupply, - }); - }); -}); diff --git a/test/lifecycle/Pausable.test.js b/test/lifecycle/Pausable.test.js index c024e4263..0af218563 100644 --- a/test/lifecycle/Pausable.test.js +++ b/test/lifecycle/Pausable.test.js @@ -1,26 +1,16 @@ const { accounts, contract } = require('@openzeppelin/test-environment'); const { expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); -const { shouldBehaveLikePublicRole } = require('../behaviors/access/roles/PublicRole.behavior'); const { expect } = require('chai'); const PausableMock = contract.fromArtifact('PausableMock'); describe('Pausable', function () { - const [ pauser, otherPauser, other, ...otherAccounts ] = accounts; + const [ pauser ] = accounts; beforeEach(async function () { - this.pausable = await PausableMock.new({ from: pauser }); - }); - - describe('pauser role', function () { - beforeEach(async function () { - this.contract = this.pausable; - await this.contract.addPauser(otherPauser, { from: pauser }); - }); - - shouldBehaveLikePublicRole(pauser, otherPauser, otherAccounts, 'pauser'); + this.pausable = await PausableMock.new(); }); context('when unpaused', function () { @@ -31,87 +21,68 @@ describe('Pausable', function () { it('can perform normal process in non-pause', async function () { expect(await this.pausable.count()).to.be.bignumber.equal('0'); - await this.pausable.normalProcess({ from: other }); + await this.pausable.normalProcess(); expect(await this.pausable.count()).to.be.bignumber.equal('1'); }); it('cannot take drastic measure in non-pause', async function () { - await expectRevert(this.pausable.drasticMeasure({ from: other }), + await expectRevert(this.pausable.drasticMeasure(), 'Pausable: not paused' ); expect(await this.pausable.drasticMeasureTaken()).to.equal(false); }); - describe('pausing', function () { - it('is pausable by the pauser', async function () { - await this.pausable.pause({ from: pauser }); - expect(await this.pausable.paused()).to.equal(true); + context('when paused', function () { + beforeEach(async function () { + ({ logs: this.logs } = await this.pausable.pause({ from: pauser })); }); - it('reverts when pausing from non-pauser', async function () { - await expectRevert(this.pausable.pause({ from: other }), - 'PauserRole: caller does not have the Pauser role' - ); + it('emits a Paused event', function () { + expectEvent.inLogs(this.logs, 'Paused', { account: pauser }); }); - context('when paused', function () { - beforeEach(async function () { - ({ logs: this.logs } = await this.pausable.pause({ from: pauser })); + it('cannot perform normal process in pause', async function () { + await expectRevert(this.pausable.normalProcess(), 'Pausable: paused'); + }); + + it('can take a drastic measure in a pause', async function () { + await this.pausable.drasticMeasure(); + expect(await this.pausable.drasticMeasureTaken()).to.equal(true); + }); + + it('reverts when re-pausing', async function () { + await expectRevert(this.pausable.pause(), 'Pausable: paused'); + }); + + describe('unpausing', function () { + it('is unpausable by the pauser', async function () { + await this.pausable.unpause(); + expect(await this.pausable.paused()).to.equal(false); }); - it('emits a Paused event', function () { - expectEvent.inLogs(this.logs, 'Paused', { account: pauser }); - }); - - it('cannot perform normal process in pause', async function () { - await expectRevert(this.pausable.normalProcess({ from: other }), 'Pausable: paused'); - }); - - it('can take a drastic measure in a pause', async function () { - await this.pausable.drasticMeasure({ from: other }); - expect(await this.pausable.drasticMeasureTaken()).to.equal(true); - }); - - it('reverts when re-pausing', async function () { - await expectRevert(this.pausable.pause({ from: pauser }), 'Pausable: paused'); - }); - - describe('unpausing', function () { - it('is unpausable by the pauser', async function () { - await this.pausable.unpause({ from: pauser }); - expect(await this.pausable.paused()).to.equal(false); + context('when unpaused', function () { + beforeEach(async function () { + ({ logs: this.logs } = await this.pausable.unpause({ from: pauser })); }); - it('reverts when unpausing from non-pauser', async function () { - await expectRevert(this.pausable.unpause({ from: other }), - 'PauserRole: caller does not have the Pauser role' + it('emits an Unpaused event', function () { + expectEvent.inLogs(this.logs, 'Unpaused', { account: pauser }); + }); + + it('should resume allowing normal process', async function () { + expect(await this.pausable.count()).to.be.bignumber.equal('0'); + await this.pausable.normalProcess(); + expect(await this.pausable.count()).to.be.bignumber.equal('1'); + }); + + it('should prevent drastic measure', async function () { + await expectRevert(this.pausable.drasticMeasure(), + 'Pausable: not paused' ); }); - context('when unpaused', function () { - beforeEach(async function () { - ({ logs: this.logs } = await this.pausable.unpause({ from: pauser })); - }); - - it('emits an Unpaused event', function () { - expectEvent.inLogs(this.logs, 'Unpaused', { account: pauser }); - }); - - it('should resume allowing normal process', async function () { - expect(await this.pausable.count()).to.be.bignumber.equal('0'); - await this.pausable.normalProcess({ from: other }); - expect(await this.pausable.count()).to.be.bignumber.equal('1'); - }); - - it('should prevent drastic measure', async function () { - await expectRevert(this.pausable.drasticMeasure({ from: other }), - 'Pausable: not paused' - ); - }); - - it('reverts when re-unpausing', async function () { - await expectRevert(this.pausable.unpause({ from: pauser }), 'Pausable: not paused'); - }); + it('reverts when re-unpausing', async function () { + await expectRevert(this.pausable.unpause(), 'Pausable: not paused'); }); }); }); diff --git a/test/token/ERC20/ERC20Capped.test.js b/test/token/ERC20/ERC20Capped.test.js index d44ba2d62..5978e952e 100644 --- a/test/token/ERC20/ERC20Capped.test.js +++ b/test/token/ERC20/ERC20Capped.test.js @@ -1,10 +1,9 @@ const { accounts, contract } = require('@openzeppelin/test-environment'); const { BN, ether, expectRevert } = require('@openzeppelin/test-helpers'); -const { shouldBehaveLikeERC20Mintable } = require('./behaviors/ERC20Mintable.behavior'); const { shouldBehaveLikeERC20Capped } = require('./behaviors/ERC20Capped.behavior'); -const ERC20Capped = contract.fromArtifact('ERC20Capped'); +const ERC20Capped = contract.fromArtifact('ERC20CappedMock'); describe('ERC20Capped', function () { const [ minter, ...otherAccounts ] = accounts; @@ -23,6 +22,5 @@ describe('ERC20Capped', function () { }); shouldBehaveLikeERC20Capped(minter, otherAccounts, cap); - shouldBehaveLikeERC20Mintable(minter, otherAccounts); }); }); diff --git a/test/token/ERC20/ERC20Mintable.test.js b/test/token/ERC20/ERC20Mintable.test.js deleted file mode 100644 index d69f9533a..000000000 --- a/test/token/ERC20/ERC20Mintable.test.js +++ /dev/null @@ -1,24 +0,0 @@ -const { accounts, contract } = require('@openzeppelin/test-environment'); - -const { shouldBehaveLikeERC20Mintable } = require('./behaviors/ERC20Mintable.behavior'); -const ERC20MintableMock = contract.fromArtifact('ERC20MintableMock'); -const { shouldBehaveLikePublicRole } = require('../../behaviors/access/roles/PublicRole.behavior'); - -describe('ERC20Mintable', function () { - const [ minter, otherMinter, ...otherAccounts ] = accounts; - - beforeEach(async function () { - this.token = await ERC20MintableMock.new({ from: minter }); - }); - - describe('minter role', function () { - beforeEach(async function () { - this.contract = this.token; - await this.contract.addMinter(otherMinter, { from: minter }); - }); - - shouldBehaveLikePublicRole(minter, otherMinter, otherAccounts, 'minter'); - }); - - shouldBehaveLikeERC20Mintable(minter, otherAccounts); -}); diff --git a/test/token/ERC20/ERC20Pausable.test.js b/test/token/ERC20/ERC20Pausable.test.js index 6f81cddf9..9b57b6633 100644 --- a/test/token/ERC20/ERC20Pausable.test.js +++ b/test/token/ERC20/ERC20Pausable.test.js @@ -1,178 +1,44 @@ const { accounts, contract } = require('@openzeppelin/test-environment'); -const { BN, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { BN, expectRevert } = require('@openzeppelin/test-helpers'); const { expect } = require('chai'); const ERC20PausableMock = contract.fromArtifact('ERC20PausableMock'); -const { shouldBehaveLikePublicRole } = require('../../behaviors/access/roles/PublicRole.behavior'); describe('ERC20Pausable', function () { - const [ pauser, otherPauser, recipient, anotherAccount, ...otherAccounts ] = accounts; + const [ holder, recipient, anotherAccount ] = accounts; const initialSupply = new BN(100); beforeEach(async function () { - this.token = await ERC20PausableMock.new(pauser, initialSupply, { from: pauser }); - }); - - describe('pauser role', function () { - beforeEach(async function () { - this.contract = this.token; - await this.contract.addPauser(otherPauser, { from: pauser }); - }); - - shouldBehaveLikePublicRole(pauser, otherPauser, otherAccounts, 'pauser'); - }); - - describe('pause', function () { - describe('when the sender is the token pauser', function () { - const from = pauser; - - describe('when the token is unpaused', function () { - it('pauses the token', async function () { - await this.token.pause({ from }); - expect(await this.token.paused()).to.equal(true); - }); - - it('emits a Pause event', async function () { - const { logs } = await this.token.pause({ from }); - - expectEvent.inLogs(logs, 'Paused'); - }); - }); - - describe('when the token is paused', function () { - beforeEach(async function () { - await this.token.pause({ from }); - }); - - it('reverts', async function () { - await expectRevert(this.token.pause({ from }), 'Pausable: paused'); - }); - }); - }); - - describe('when the sender is not the token pauser', function () { - const from = anotherAccount; - - it('reverts', async function () { - await expectRevert(this.token.pause({ from }), - 'PauserRole: caller does not have the Pauser role' - ); - }); - }); - }); - - describe('unpause', function () { - describe('when the sender is the token pauser', function () { - const from = pauser; - - describe('when the token is paused', function () { - beforeEach(async function () { - await this.token.pause({ from }); - }); - - it('unpauses the token', async function () { - await this.token.unpause({ from }); - expect(await this.token.paused()).to.equal(false); - }); - - it('emits an Unpause event', async function () { - const { logs } = await this.token.unpause({ from }); - - expectEvent.inLogs(logs, 'Unpaused'); - }); - }); - - describe('when the token is unpaused', function () { - it('reverts', async function () { - await expectRevert(this.token.unpause({ from }), 'Pausable: not paused'); - }); - }); - }); - - describe('when the sender is not the token pauser', function () { - const from = anotherAccount; - - it('reverts', async function () { - await expectRevert(this.token.unpause({ from }), - 'PauserRole: caller does not have the Pauser role' - ); - }); - }); + this.token = await ERC20PausableMock.new(holder, initialSupply); }); describe('pausable token', function () { - const from = pauser; - - describe('paused', function () { - it('is not paused by default', async function () { - expect(await this.token.paused({ from })).to.equal(false); - }); - - it('is paused after being paused', async function () { - await this.token.pause({ from }); - expect(await this.token.paused({ from })).to.equal(true); - }); - - it('is not paused after being paused and then unpaused', async function () { - await this.token.pause({ from }); - await this.token.unpause({ from }); - expect(await this.token.paused()).to.equal(false); - }); - }); - describe('transfer', function () { it('allows to transfer when unpaused', async function () { - await this.token.transfer(recipient, initialSupply, { from: pauser }); + await this.token.transfer(recipient, initialSupply, { from: holder }); - expect(await this.token.balanceOf(pauser)).to.be.bignumber.equal('0'); + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal('0'); expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(initialSupply); }); it('allows to transfer when paused and then unpaused', async function () { - await this.token.pause({ from: pauser }); - await this.token.unpause({ from: pauser }); + await this.token.pause(); + await this.token.unpause(); - await this.token.transfer(recipient, initialSupply, { from: pauser }); + await this.token.transfer(recipient, initialSupply, { from: holder }); - expect(await this.token.balanceOf(pauser)).to.be.bignumber.equal('0'); + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal('0'); expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(initialSupply); }); it('reverts when trying to transfer when paused', async function () { - await this.token.pause({ from: pauser }); + await this.token.pause(); - await expectRevert(this.token.transfer(recipient, initialSupply, { from: pauser }), - 'Pausable: paused' - ); - }); - }); - - describe('approve', function () { - const allowance = new BN(40); - - it('allows to approve when unpaused', async function () { - await this.token.approve(anotherAccount, allowance, { from: pauser }); - - expect(await this.token.allowance(pauser, anotherAccount)).to.be.bignumber.equal(allowance); - }); - - it('allows to approve when paused and then unpaused', async function () { - await this.token.pause({ from: pauser }); - await this.token.unpause({ from: pauser }); - - await this.token.approve(anotherAccount, allowance, { from: pauser }); - - expect(await this.token.allowance(pauser, anotherAccount)).to.be.bignumber.equal(allowance); - }); - - it('reverts when trying to approve when paused', async function () { - await this.token.pause({ from: pauser }); - - await expectRevert(this.token.approve(anotherAccount, allowance, { from: pauser }), - 'Pausable: paused' + await expectRevert(this.token.transfer(recipient, initialSupply, { from: holder }), + 'ERC20Pausable: token transfer while paused' ); }); }); @@ -181,95 +47,31 @@ describe('ERC20Pausable', function () { const allowance = new BN(40); beforeEach(async function () { - await this.token.approve(anotherAccount, allowance, { from: pauser }); + await this.token.approve(anotherAccount, allowance, { from: holder }); }); it('allows to transfer from when unpaused', async function () { - await this.token.transferFrom(pauser, recipient, allowance, { from: anotherAccount }); + await this.token.transferFrom(holder, recipient, allowance, { from: anotherAccount }); expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(allowance); - expect(await this.token.balanceOf(pauser)).to.be.bignumber.equal(initialSupply.sub(allowance)); + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal(initialSupply.sub(allowance)); }); it('allows to transfer when paused and then unpaused', async function () { - await this.token.pause({ from: pauser }); - await this.token.unpause({ from: pauser }); + await this.token.pause(); + await this.token.unpause(); - await this.token.transferFrom(pauser, recipient, allowance, { from: anotherAccount }); + await this.token.transferFrom(holder, recipient, allowance, { from: anotherAccount }); expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(allowance); - expect(await this.token.balanceOf(pauser)).to.be.bignumber.equal(initialSupply.sub(allowance)); + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal(initialSupply.sub(allowance)); }); it('reverts when trying to transfer from when paused', async function () { - await this.token.pause({ from: pauser }); + await this.token.pause(); await expectRevert(this.token.transferFrom( - pauser, recipient, allowance, { from: anotherAccount }), 'Pausable: paused' - ); - }); - }); - - describe('decrease approval', function () { - const allowance = new BN(40); - const decrement = new BN(10); - - beforeEach(async function () { - await this.token.approve(anotherAccount, allowance, { from: pauser }); - }); - - it('allows to decrease approval when unpaused', async function () { - await this.token.decreaseAllowance(anotherAccount, decrement, { from: pauser }); - - expect(await this.token.allowance(pauser, anotherAccount)).to.be.bignumber.equal(allowance.sub(decrement)); - }); - - it('allows to decrease approval when paused and then unpaused', async function () { - await this.token.pause({ from: pauser }); - await this.token.unpause({ from: pauser }); - - await this.token.decreaseAllowance(anotherAccount, decrement, { from: pauser }); - - expect(await this.token.allowance(pauser, anotherAccount)).to.be.bignumber.equal(allowance.sub(decrement)); - }); - - it('reverts when trying to transfer when paused', async function () { - await this.token.pause({ from: pauser }); - - await expectRevert(this.token.decreaseAllowance( - anotherAccount, decrement, { from: pauser }), 'Pausable: paused' - ); - }); - }); - - describe('increase approval', function () { - const allowance = new BN(40); - const increment = new BN(30); - - beforeEach(async function () { - await this.token.approve(anotherAccount, allowance, { from: pauser }); - }); - - it('allows to increase approval when unpaused', async function () { - await this.token.increaseAllowance(anotherAccount, increment, { from: pauser }); - - expect(await this.token.allowance(pauser, anotherAccount)).to.be.bignumber.equal(allowance.add(increment)); - }); - - it('allows to increase approval when paused and then unpaused', async function () { - await this.token.pause({ from: pauser }); - await this.token.unpause({ from: pauser }); - - await this.token.increaseAllowance(anotherAccount, increment, { from: pauser }); - - expect(await this.token.allowance(pauser, anotherAccount)).to.be.bignumber.equal(allowance.add(increment)); - }); - - it('reverts when trying to increase approval when paused', async function () { - await this.token.pause({ from: pauser }); - - await expectRevert(this.token.increaseAllowance( - anotherAccount, increment, { from: pauser }), 'Pausable: paused' + holder, recipient, allowance, { from: anotherAccount }), 'ERC20Pausable: token transfer while paused' ); }); }); diff --git a/test/token/ERC20/TokenTimelock.test.js b/test/token/ERC20/TokenTimelock.test.js index 91c666e47..751916ae4 100644 --- a/test/token/ERC20/TokenTimelock.test.js +++ b/test/token/ERC20/TokenTimelock.test.js @@ -4,17 +4,17 @@ const { BN, expectRevert, time } = require('@openzeppelin/test-helpers'); const { expect } = require('chai'); -const ERC20Mintable = contract.fromArtifact('ERC20Mintable'); +const ERC20Mock = contract.fromArtifact('ERC20Mock'); const TokenTimelock = contract.fromArtifact('TokenTimelock'); describe('TokenTimelock', function () { - const [ minter, beneficiary ] = accounts; + const [ beneficiary ] = accounts; const amount = new BN(100); context('with token', function () { beforeEach(async function () { - this.token = await ERC20Mintable.new({ from: minter }); + this.token = await ERC20Mock.new(beneficiary, 0); // We're not using the preminted tokens }); it('rejects a release time in the past', async function () { @@ -29,7 +29,7 @@ describe('TokenTimelock', function () { beforeEach(async function () { this.releaseTime = (await time.latest()).add(time.duration.years(1)); this.timelock = await TokenTimelock.new(this.token.address, beneficiary, this.releaseTime); - await this.token.mint(this.timelock.address, amount, { from: minter }); + await this.token.mint(this.timelock.address, amount); }); it('can get state', async function () { diff --git a/test/token/ERC20/behaviors/ERC20Mintable.behavior.js b/test/token/ERC20/behaviors/ERC20Mintable.behavior.js deleted file mode 100644 index c9bc2e8fd..000000000 --- a/test/token/ERC20/behaviors/ERC20Mintable.behavior.js +++ /dev/null @@ -1,56 +0,0 @@ -const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); -const { ZERO_ADDRESS } = constants; - -const { expect } = require('chai'); - -function shouldBehaveLikeERC20Mintable (minter, [other]) { - describe('as a mintable token', function () { - describe('mint', function () { - const amount = new BN(100); - - context('when the sender has minting permission', function () { - const from = minter; - - context('for a zero amount', function () { - shouldMint(new BN(0)); - }); - - context('for a non-zero amount', function () { - shouldMint(amount); - }); - - function shouldMint (amount) { - beforeEach(async function () { - ({ logs: this.logs } = await this.token.mint(other, amount, { from })); - }); - - it('mints the requested amount', async function () { - expect(await this.token.balanceOf(other)).to.be.bignumber.equal(amount); - }); - - it('emits a mint and a transfer event', async function () { - expectEvent.inLogs(this.logs, 'Transfer', { - from: ZERO_ADDRESS, - to: other, - value: amount, - }); - }); - } - }); - - context('when the sender doesn\'t have minting permission', function () { - const from = other; - - it('reverts', async function () { - await expectRevert(this.token.mint(other, amount, { from }), - 'MinterRole: caller does not have the Minter role' - ); - }); - }); - }); - }); -} - -module.exports = { - shouldBehaveLikeERC20Mintable, -}; diff --git a/test/token/ERC721/ERC721.behavior.js b/test/token/ERC721/ERC721.behavior.js index bca0fc924..e6ef75f44 100644 --- a/test/token/ERC721/ERC721.behavior.js +++ b/test/token/ERC721/ERC721.behavior.js @@ -8,8 +8,6 @@ const ERC721Mock = contract.fromArtifact('ERC721Mock'); const ERC721ReceiverMock = contract.fromArtifact('ERC721ReceiverMock'); function shouldBehaveLikeERC721 ( - creator, - minter, [owner, approved, anotherApproved, operator, other] ) { const firstTokenId = new BN(1); @@ -19,8 +17,8 @@ function shouldBehaveLikeERC721 ( describe('like an ERC721', function () { beforeEach(async function () { - await this.token.mint(owner, firstTokenId, { from: minter }); - await this.token.mint(owner, secondTokenId, { from: minter }); + await this.token.mint(owner, firstTokenId); + await this.token.mint(owner, secondTokenId); this.toWhom = other; // default to anyone for toWhom in context-dependent tests }); @@ -593,7 +591,7 @@ function shouldBehaveLikeERC721 ( context('when token is not minted', async function () { it('reverts', async function () { await expectRevert( - this.token.getApproved(unknownTokenId, { from: minter }), + this.token.getApproved(unknownTokenId), 'ERC721: approved query for nonexistent token' ); }); diff --git a/test/token/ERC721/ERC721.test.js b/test/token/ERC721/ERC721.test.js index fd22e3d3e..b9709fd5a 100644 --- a/test/token/ERC721/ERC721.test.js +++ b/test/token/ERC721/ERC721.test.js @@ -9,13 +9,13 @@ const { shouldBehaveLikeERC721 } = require('./ERC721.behavior'); const ERC721Mock = contract.fromArtifact('ERC721Mock'); describe('ERC721', function () { - const [ creator, owner, other, ...otherAccounts ] = accounts; + const [ owner, other ] = accounts; beforeEach(async function () { - this.token = await ERC721Mock.new({ from: creator }); + this.token = await ERC721Mock.new(); }); - shouldBehaveLikeERC721(creator, creator, otherAccounts); + shouldBehaveLikeERC721(accounts); describe('internal functions', function () { const tokenId = new BN('5042'); diff --git a/test/token/ERC721/ERC721Burnable.test.js b/test/token/ERC721/ERC721Burnable.test.js index a1ff2e814..456d41715 100644 --- a/test/token/ERC721/ERC721Burnable.test.js +++ b/test/token/ERC721/ERC721Burnable.test.js @@ -1,22 +1,79 @@ const { accounts, contract } = require('@openzeppelin/test-environment'); -require('@openzeppelin/test-helpers'); +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; -const { shouldBehaveLikeERC721 } = require('./ERC721.behavior'); -const { - shouldBehaveLikeMintAndBurnERC721, -} = require('./ERC721MintBurn.behavior'); +const { expect } = require('chai'); -const ERC721BurnableImpl = contract.fromArtifact('ERC721MintableBurnableImpl'); +const ERC721BurnableMock = contract.fromArtifact('ERC721BurnableMock'); describe('ERC721Burnable', function () { - const [ creator, ...otherAccounts ] = accounts; - const minter = creator; + const [owner, approved] = accounts; + + const firstTokenId = new BN(1); + const secondTokenId = new BN(2); + const unknownTokenId = new BN(3); beforeEach(async function () { - this.token = await ERC721BurnableImpl.new({ from: creator }); + this.token = await ERC721BurnableMock.new(); }); - shouldBehaveLikeERC721(creator, minter, otherAccounts); - shouldBehaveLikeMintAndBurnERC721(creator, minter, otherAccounts); + describe('like a burnable ERC721', function () { + beforeEach(async function () { + await this.token.mint(owner, firstTokenId); + await this.token.mint(owner, secondTokenId); + }); + + describe('burn', function () { + const tokenId = firstTokenId; + let logs = null; + + describe('when successful', function () { + beforeEach(async function () { + const result = await this.token.burn(tokenId, { from: owner }); + logs = result.logs; + }); + + it('burns the given token ID and adjusts the balance of the owner', async function () { + await expectRevert( + this.token.ownerOf(tokenId), + 'ERC721: owner query for nonexistent token' + ); + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal('1'); + }); + + it('emits a burn event', async function () { + expectEvent.inLogs(logs, 'Transfer', { + from: owner, + to: ZERO_ADDRESS, + tokenId: tokenId, + }); + }); + }); + + describe('when there is a previous approval burned', function () { + beforeEach(async function () { + await this.token.approve(approved, tokenId, { from: owner }); + const result = await this.token.burn(tokenId, { from: owner }); + logs = result.logs; + }); + + context('getApproved', function () { + it('reverts', async function () { + await expectRevert( + this.token.getApproved(tokenId), 'ERC721: approved query for nonexistent token' + ); + }); + }); + }); + + describe('when the given token ID was not tracked by this contract', function () { + it('reverts', async function () { + await expectRevert( + this.token.burn(unknownTokenId, { from: owner }), 'ERC721: operator query for nonexistent token' + ); + }); + }); + }); + }); }); diff --git a/test/token/ERC721/ERC721Full.test.js b/test/token/ERC721/ERC721Full.test.js index 93a23bf13..e7473d020 100644 --- a/test/token/ERC721/ERC721Full.test.js +++ b/test/token/ERC721/ERC721Full.test.js @@ -9,14 +9,7 @@ const { shouldSupportInterfaces } = require('../../introspection/SupportsInterfa const ERC721FullMock = contract.fromArtifact('ERC721FullMock'); describe('ERC721Full', function () { - const [ creator, ...otherAccounts ] = accounts; - const minter = creator; - - const [ - owner, - newOwner, - other, - ] = otherAccounts; + const [owner, newOwner, other ] = accounts; const name = 'Non Fungible Token'; const symbol = 'NFT'; @@ -26,18 +19,18 @@ describe('ERC721Full', function () { const nonExistentTokenId = new BN(999); beforeEach(async function () { - this.token = await ERC721FullMock.new(name, symbol, { from: creator }); + this.token = await ERC721FullMock.new(name, symbol); }); describe('like a full ERC721', function () { beforeEach(async function () { - await this.token.mint(owner, firstTokenId, { from: minter }); - await this.token.mint(owner, secondTokenId, { from: minter }); + await this.token.mint(owner, firstTokenId); + await this.token.mint(owner, secondTokenId); }); describe('mint', function () { beforeEach(async function () { - await this.token.mint(newOwner, thirdTokenId, { from: minter }); + await this.token.mint(newOwner, thirdTokenId); }); it('adjusts owner tokens by index', async function () { @@ -228,8 +221,8 @@ describe('ERC721Full', function () { const anotherNewTokenId = new BN(400); await this.token.burn(tokenId, { from: owner }); - await this.token.mint(newOwner, newTokenId, { from: minter }); - await this.token.mint(newOwner, anotherNewTokenId, { from: minter }); + await this.token.mint(newOwner, newTokenId); + await this.token.mint(newOwner, anotherNewTokenId); expect(await this.token.totalSupply()).to.be.bignumber.equal('3'); @@ -245,7 +238,7 @@ describe('ERC721Full', function () { }); }); - shouldBehaveLikeERC721(creator, minter, otherAccounts); + shouldBehaveLikeERC721(accounts); shouldSupportInterfaces([ 'ERC165', diff --git a/test/token/ERC721/ERC721Holder.test.js b/test/token/ERC721/ERC721Holder.test.js index faeee3c6d..b2d1017c5 100644 --- a/test/token/ERC721/ERC721Holder.test.js +++ b/test/token/ERC721/ERC721Holder.test.js @@ -5,18 +5,18 @@ const { BN } = require('@openzeppelin/test-helpers'); const { expect } = require('chai'); const ERC721Holder = contract.fromArtifact('ERC721Holder'); -const ERC721Mintable = contract.fromArtifact('ERC721MintableBurnableImpl'); +const ERC721Mock = contract.fromArtifact('ERC721Mock'); describe('ERC721Holder', function () { - const [ creator ] = accounts; + const [ owner ] = accounts; it('receives an ERC721 token', async function () { - const token = await ERC721Mintable.new({ from: creator }); + const token = await ERC721Mock.new(); const tokenId = new BN(1); - await token.mint(creator, tokenId, { from: creator }); + await token.mint(owner, tokenId); const receiver = await ERC721Holder.new(); - await token.safeTransferFrom(creator, receiver.address, tokenId, { from: creator }); + await token.safeTransferFrom(owner, receiver.address, tokenId, { from: owner }); expect(await token.ownerOf(tokenId)).to.be.equal(receiver.address); }); diff --git a/test/token/ERC721/ERC721MintBurn.behavior.js b/test/token/ERC721/ERC721MintBurn.behavior.js deleted file mode 100644 index 87898d676..000000000 --- a/test/token/ERC721/ERC721MintBurn.behavior.js +++ /dev/null @@ -1,144 +0,0 @@ -const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); -const { ZERO_ADDRESS } = constants; - -const { expect } = require('chai'); - -function shouldBehaveLikeMintAndBurnERC721 ( - creator, - minter, - [owner, newOwner, approved] -) { - const firstTokenId = new BN(1); - const secondTokenId = new BN(2); - const thirdTokenId = new BN(3); - const unknownTokenId = new BN(4); - const MOCK_URI = 'https://example.com'; - const data = '0x42'; - - describe('like a mintable and burnable ERC721', function () { - beforeEach(async function () { - await this.token.mint(owner, firstTokenId, { from: minter }); - await this.token.mint(owner, secondTokenId, { from: minter }); - }); - - describe('mint', function () { - let logs = null; - - describe('when successful', function () { - beforeEach(async function () { - const result = await this.token.mint(newOwner, thirdTokenId, { from: minter }); - logs = result.logs; - }); - - it('assigns the token to the new owner', async function () { - expect(await this.token.ownerOf(thirdTokenId)).to.equal(newOwner); - }); - - it('increases the balance of its owner', async function () { - expect(await this.token.balanceOf(newOwner)).to.be.bignumber.equal('1'); - }); - - it('emits a transfer and minted event', async function () { - expectEvent.inLogs(logs, 'Transfer', { - from: ZERO_ADDRESS, - to: newOwner, - tokenId: thirdTokenId, - }); - }); - }); - - describe('when the given owner address is the zero address', function () { - it('reverts', async function () { - await expectRevert( - this.token.mint(ZERO_ADDRESS, thirdTokenId, { from: minter }), - 'ERC721: mint to the zero address' - ); - }); - }); - - describe('when the given token ID was already tracked by this contract', function () { - it('reverts', async function () { - await expectRevert(this.token.mint(owner, firstTokenId, { from: minter }), - 'ERC721: token already minted.' - ); - }); - }); - }); - - describe('mintWithTokenURI', function () { - it('can mint with a tokenUri', async function () { - await this.token.mintWithTokenURI(newOwner, thirdTokenId, MOCK_URI, { - from: minter, - }); - }); - }); - - describe('safeMint', function () { - it('it can safely mint with data', async function () { - await this.token.methods['safeMint(address,uint256,bytes)'](...[newOwner, thirdTokenId, data], - { from: minter }); - }); - - it('it can safely mint without data', async function () { - await this.token.methods['safeMint(address,uint256)'](...[newOwner, thirdTokenId], - { from: minter }); - }); - }); - - describe('burn', function () { - const tokenId = firstTokenId; - let logs = null; - - describe('when successful', function () { - beforeEach(async function () { - const result = await this.token.burn(tokenId, { from: owner }); - logs = result.logs; - }); - - it('burns the given token ID and adjusts the balance of the owner', async function () { - await expectRevert( - this.token.ownerOf(tokenId), - 'ERC721: owner query for nonexistent token' - ); - expect(await this.token.balanceOf(owner)).to.be.bignumber.equal('1'); - }); - - it('emits a burn event', async function () { - expectEvent.inLogs(logs, 'Transfer', { - from: owner, - to: ZERO_ADDRESS, - tokenId: tokenId, - }); - }); - }); - - describe('when there is a previous approval burned', function () { - beforeEach(async function () { - await this.token.approve(approved, tokenId, { from: owner }); - const result = await this.token.burn(tokenId, { from: owner }); - logs = result.logs; - }); - - context('getApproved', function () { - it('reverts', async function () { - await expectRevert( - this.token.getApproved(tokenId), 'ERC721: approved query for nonexistent token' - ); - }); - }); - }); - - describe('when the given token ID was not tracked by this contract', function () { - it('reverts', async function () { - await expectRevert( - this.token.burn(unknownTokenId, { from: creator }), 'ERC721: operator query for nonexistent token' - ); - }); - }); - }); - }); -} - -module.exports = { - shouldBehaveLikeMintAndBurnERC721, -}; diff --git a/test/token/ERC721/ERC721Mintable.test.js b/test/token/ERC721/ERC721Mintable.test.js deleted file mode 100644 index 9f10b5d34..000000000 --- a/test/token/ERC721/ERC721Mintable.test.js +++ /dev/null @@ -1,21 +0,0 @@ -const { accounts, contract } = require('@openzeppelin/test-environment'); - -require('@openzeppelin/test-helpers'); -const { shouldBehaveLikeERC721 } = require('./ERC721.behavior'); -const { shouldBehaveLikeMintAndBurnERC721 } = require('./ERC721MintBurn.behavior'); - -const ERC721MintableImpl = contract.fromArtifact('ERC721MintableBurnableImpl'); - -describe('ERC721Mintable', function () { - const [ creator, ...otherAccounts ] = accounts; - const minter = creator; - - beforeEach(async function () { - this.token = await ERC721MintableImpl.new({ - from: creator, - }); - }); - - shouldBehaveLikeERC721(creator, minter, otherAccounts); - shouldBehaveLikeMintAndBurnERC721(creator, minter, otherAccounts); -}); diff --git a/test/token/ERC721/ERC721Pausable.test.js b/test/token/ERC721/ERC721Pausable.test.js index 0b8c7bbea..16f5b8421 100644 --- a/test/token/ERC721/ERC721Pausable.test.js +++ b/test/token/ERC721/ERC721Pausable.test.js @@ -1,46 +1,88 @@ const { accounts, contract } = require('@openzeppelin/test-environment'); -require('@openzeppelin/test-helpers'); -const { shouldBehaveLikeERC721PausedToken } = require('./ERC721PausedToken.behavior'); +const { BN, constants, expectRevert } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; + +const { expect } = require('chai'); + const { shouldBehaveLikeERC721 } = require('./ERC721.behavior'); -const { shouldBehaveLikePublicRole } = require('../../behaviors/access/roles/PublicRole.behavior'); const ERC721PausableMock = contract.fromArtifact('ERC721PausableMock'); describe('ERC721Pausable', function () { - const [ creator, otherPauser, ...otherAccounts ] = accounts; + const [ owner, receiver, operator ] = accounts; beforeEach(async function () { - this.token = await ERC721PausableMock.new({ from: creator }); - }); - - describe('pauser role', function () { - beforeEach(async function () { - this.contract = this.token; - await this.contract.addPauser(otherPauser, { from: creator }); - }); - - shouldBehaveLikePublicRole(creator, otherPauser, otherAccounts, 'pauser'); - }); - - context('when token is paused', function () { - beforeEach(async function () { - await this.token.pause({ from: creator }); - }); - - shouldBehaveLikeERC721PausedToken(creator, otherAccounts); + this.token = await ERC721PausableMock.new(); }); context('when token is not paused yet', function () { - shouldBehaveLikeERC721(creator, creator, otherAccounts); + shouldBehaveLikeERC721(accounts); }); - context('when token is paused and then unpaused', function () { + context('when token is paused', function () { + const firstTokenId = new BN(1); + const mintedTokens = new BN(1); + const mockData = '0x42'; + beforeEach(async function () { - await this.token.pause({ from: creator }); - await this.token.unpause({ from: creator }); + await this.token.mint(owner, firstTokenId, { from: owner }); + await this.token.pause(); }); - shouldBehaveLikeERC721(creator, creator, otherAccounts); + it('reverts when trying to transferFrom', async function () { + await expectRevert( + this.token.transferFrom(owner, receiver, firstTokenId, { from: owner }), + 'ERC721Pausable: token transfer while paused' + ); + }); + + it('reverts when trying to safeTransferFrom', async function () { + await expectRevert( + this.token.safeTransferFrom(owner, receiver, firstTokenId, { from: owner }), + 'ERC721Pausable: token transfer while paused' + ); + }); + + it('reverts when trying to safeTransferFrom with data', async function () { + await expectRevert( + this.token.methods['safeTransferFrom(address,address,uint256,bytes)']( + owner, receiver, firstTokenId, mockData, { from: owner } + ), 'ERC721Pausable: token transfer while paused' + ); + }); + + describe('getApproved', function () { + it('returns approved address', async function () { + const approvedAccount = await this.token.getApproved(firstTokenId); + expect(approvedAccount).to.equal(ZERO_ADDRESS); + }); + }); + + describe('balanceOf', function () { + it('returns the amount of tokens owned by the given address', async function () { + const balance = await this.token.balanceOf(owner); + expect(balance).to.be.bignumber.equal(mintedTokens); + }); + }); + + describe('ownerOf', function () { + it('returns the amount of tokens owned by the given address', async function () { + const ownerOfToken = await this.token.ownerOf(firstTokenId); + expect(ownerOfToken).to.equal(owner); + }); + }); + + describe('exists', function () { + it('should return token existence', async function () { + expect(await this.token.exists(firstTokenId)).to.equal(true); + }); + }); + + describe('isApprovedForAll', function () { + it('returns the approval of the operator', async function () { + expect(await this.token.isApprovedForAll(owner, operator)).to.equal(false); + }); + }); }); }); diff --git a/test/token/ERC721/ERC721PausedToken.behavior.js b/test/token/ERC721/ERC721PausedToken.behavior.js deleted file mode 100644 index e15a26dc1..000000000 --- a/test/token/ERC721/ERC721PausedToken.behavior.js +++ /dev/null @@ -1,85 +0,0 @@ -const { BN, constants, expectRevert } = require('@openzeppelin/test-helpers'); -const { ZERO_ADDRESS } = constants; - -const { expect } = require('chai'); - -function shouldBehaveLikeERC721PausedToken (owner, [receiver, operator]) { - const firstTokenId = new BN(1); - const mintedTokens = new BN(1); - const mockData = '0x42'; - - describe('like a paused ERC721', function () { - beforeEach(async function () { - await this.token.mint(owner, firstTokenId, { from: owner }); - }); - - it('reverts when trying to approve', async function () { - await expectRevert( - this.token.approve(receiver, firstTokenId, { from: owner }), 'Pausable: paused' - ); - }); - - it('reverts when trying to setApprovalForAll', async function () { - await expectRevert( - this.token.setApprovalForAll(operator, true, { from: owner }), 'Pausable: paused' - ); - }); - - it('reverts when trying to transferFrom', async function () { - await expectRevert( - this.token.transferFrom(owner, receiver, firstTokenId, { from: owner }), 'Pausable: paused' - ); - }); - - it('reverts when trying to safeTransferFrom', async function () { - await expectRevert( - this.token.safeTransferFrom(owner, receiver, firstTokenId, { from: owner }), 'Pausable: paused' - ); - }); - - it('reverts when trying to safeTransferFrom with data', async function () { - await expectRevert( - this.token.methods['safeTransferFrom(address,address,uint256,bytes)']( - owner, receiver, firstTokenId, mockData, { from: owner } - ), 'Pausable: paused' - ); - }); - - describe('getApproved', function () { - it('returns approved address', async function () { - const approvedAccount = await this.token.getApproved(firstTokenId); - expect(approvedAccount).to.equal(ZERO_ADDRESS); - }); - }); - - describe('balanceOf', function () { - it('returns the amount of tokens owned by the given address', async function () { - const balance = await this.token.balanceOf(owner); - expect(balance).to.be.bignumber.equal(mintedTokens); - }); - }); - - describe('ownerOf', function () { - it('returns the amount of tokens owned by the given address', async function () { - const ownerOfToken = await this.token.ownerOf(firstTokenId); - expect(ownerOfToken).to.equal(owner); - }); - }); - - describe('exists', function () { - it('should return token existence', async function () { - expect(await this.token.exists(firstTokenId)).to.equal(true); - }); - }); - - describe('isApprovedForAll', function () { - it('returns the approval of the operator', async function () { - expect(await this.token.isApprovedForAll(owner, operator)).to.equal(false); - }); - }); - }); -} - -module.exports = { - shouldBehaveLikeERC721PausedToken, -}; diff --git a/test/utils/Address.test.js b/test/utils/Address.test.js index a86c3a77e..3fa6440c9 100644 --- a/test/utils/Address.test.js +++ b/test/utils/Address.test.js @@ -4,7 +4,6 @@ const { balance, constants, ether, expectRevert, send } = require('@openzeppelin const { expect } = require('chai'); const AddressImpl = contract.fromArtifact('AddressImpl'); -const SimpleToken = contract.fromArtifact('SimpleToken'); const EtherReceiver = contract.fromArtifact('EtherReceiverMock'); describe('Address', function () { @@ -22,7 +21,7 @@ describe('Address', function () { }); it('should return true for contract address', async function () { - const contract = await SimpleToken.new(); + const contract = await AddressImpl.new(); expect(await this.mock.isContract(contract.address)).to.equal(true); }); });