diff --git a/contracts/access/Roles.sol b/contracts/access/Roles.sol index 62d2216dc29..25da77e2812 100644 --- a/contracts/access/Roles.sol +++ b/contracts/access/Roles.sol @@ -13,8 +13,7 @@ library Roles { * @dev Give an account access to this role. */ function add(Role storage role, address account) internal { - require(!has(role, account)); - + require(!has(role, account), "Roles: account already has role"); role.bearer[account] = true; } @@ -22,8 +21,7 @@ library Roles { * @dev Remove an account's access to this role. */ function remove(Role storage role, address account) internal { - require(has(role, account)); - + require(has(role, account), "Roles: account does not have role"); role.bearer[account] = false; } @@ -32,7 +30,7 @@ library Roles { * @return bool */ function has(Role storage role, address account) internal view returns (bool) { - require(account != address(0)); + require(account != address(0), "Roles: account is the zero address"); return role.bearer[account]; } } diff --git a/contracts/access/roles/CapperRole.sol b/contracts/access/roles/CapperRole.sol index c817624fa55..527097d8b96 100644 --- a/contracts/access/roles/CapperRole.sol +++ b/contracts/access/roles/CapperRole.sol @@ -15,7 +15,7 @@ contract CapperRole { } modifier onlyCapper() { - require(isCapper(msg.sender)); + require(isCapper(msg.sender), "CapperRole: caller does not have the Capper role"); _; } diff --git a/contracts/access/roles/MinterRole.sol b/contracts/access/roles/MinterRole.sol index 803d96e7c81..fd44a7fb7bf 100644 --- a/contracts/access/roles/MinterRole.sol +++ b/contracts/access/roles/MinterRole.sol @@ -15,7 +15,7 @@ contract MinterRole { } modifier onlyMinter() { - require(isMinter(msg.sender)); + require(isMinter(msg.sender), "MinterRole: caller does not have the Minter role"); _; } diff --git a/contracts/access/roles/PauserRole.sol b/contracts/access/roles/PauserRole.sol index 47ae84698a5..1f94c390813 100644 --- a/contracts/access/roles/PauserRole.sol +++ b/contracts/access/roles/PauserRole.sol @@ -15,7 +15,7 @@ contract PauserRole { } modifier onlyPauser() { - require(isPauser(msg.sender)); + require(isPauser(msg.sender), "PauserRole: caller does not have the Pauser role"); _; } diff --git a/contracts/access/roles/SignerRole.sol b/contracts/access/roles/SignerRole.sol index 2892ca9501a..0e5e4425d6b 100644 --- a/contracts/access/roles/SignerRole.sol +++ b/contracts/access/roles/SignerRole.sol @@ -15,7 +15,7 @@ contract SignerRole { } modifier onlySigner() { - require(isSigner(msg.sender)); + require(isSigner(msg.sender), "SignerRole: caller does not have the Signer role"); _; } diff --git a/contracts/access/roles/WhitelistAdminRole.sol b/contracts/access/roles/WhitelistAdminRole.sol index 7d66388dcce..d7283cbc0ba 100644 --- a/contracts/access/roles/WhitelistAdminRole.sol +++ b/contracts/access/roles/WhitelistAdminRole.sol @@ -19,7 +19,7 @@ contract WhitelistAdminRole { } modifier onlyWhitelistAdmin() { - require(isWhitelistAdmin(msg.sender)); + require(isWhitelistAdmin(msg.sender), "WhitelistAdminRole: caller does not have the WhitelistAdmin role"); _; } diff --git a/contracts/access/roles/WhitelistedRole.sol b/contracts/access/roles/WhitelistedRole.sol index 55fd39c86d1..cca3137941a 100644 --- a/contracts/access/roles/WhitelistedRole.sol +++ b/contracts/access/roles/WhitelistedRole.sol @@ -18,7 +18,7 @@ contract WhitelistedRole is WhitelistAdminRole { Roles.Role private _whitelisteds; modifier onlyWhitelisted() { - require(isWhitelisted(msg.sender)); + require(isWhitelisted(msg.sender), "WhitelistedRole: caller does not have the Whitelisted role"); _; } diff --git a/contracts/crowdsale/Crowdsale.sol b/contracts/crowdsale/Crowdsale.sol index d6d3227c4ca..e9857ab5602 100644 --- a/contracts/crowdsale/Crowdsale.sol +++ b/contracts/crowdsale/Crowdsale.sol @@ -54,9 +54,9 @@ contract Crowdsale is ReentrancyGuard { * @param token Address of the token being sold */ constructor (uint256 rate, address payable wallet, IERC20 token) public { - require(rate > 0); - require(wallet != address(0)); - require(address(token) != address(0)); + 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; @@ -136,8 +136,8 @@ contract Crowdsale is ReentrancyGuard { * @param weiAmount Value in wei involved in the purchase */ function _preValidatePurchase(address beneficiary, uint256 weiAmount) internal view { - require(beneficiary != address(0)); - require(weiAmount != 0); + require(beneficiary != address(0), "Crowdsale: beneficiary is the zero address"); + require(weiAmount != 0, "Crowdsale: weiAmount is 0"); } /** diff --git a/contracts/crowdsale/distribution/FinalizableCrowdsale.sol b/contracts/crowdsale/distribution/FinalizableCrowdsale.sol index 3a391a35edf..a3c3fdd2a99 100644 --- a/contracts/crowdsale/distribution/FinalizableCrowdsale.sol +++ b/contracts/crowdsale/distribution/FinalizableCrowdsale.sol @@ -31,8 +31,8 @@ contract FinalizableCrowdsale is TimedCrowdsale { * work. Calls the contract's finalization function. */ function finalize() public { - require(!_finalized); - require(hasClosed()); + require(!_finalized, "FinalizableCrowdsale: already finalized"); + require(hasClosed(), "FinalizableCrowdsale: not closed"); _finalized = true; diff --git a/contracts/crowdsale/distribution/PostDeliveryCrowdsale.sol b/contracts/crowdsale/distribution/PostDeliveryCrowdsale.sol index c074ba4210a..c1067754546 100644 --- a/contracts/crowdsale/distribution/PostDeliveryCrowdsale.sol +++ b/contracts/crowdsale/distribution/PostDeliveryCrowdsale.sol @@ -24,9 +24,9 @@ contract PostDeliveryCrowdsale is TimedCrowdsale { * @param beneficiary Whose tokens will be withdrawn. */ function withdrawTokens(address beneficiary) public { - require(hasClosed()); + require(hasClosed(), "PostDeliveryCrowdsale: not closed"); uint256 amount = _balances[beneficiary]; - require(amount > 0); + require(amount > 0, "PostDeliveryCrowdsale: beneficiary is not due any tokens"); _balances[beneficiary] = 0; _vault.transfer(token(), beneficiary, amount); diff --git a/contracts/crowdsale/distribution/RefundableCrowdsale.sol b/contracts/crowdsale/distribution/RefundableCrowdsale.sol index f217aa7da5f..e6af3b69d4b 100644 --- a/contracts/crowdsale/distribution/RefundableCrowdsale.sol +++ b/contracts/crowdsale/distribution/RefundableCrowdsale.sol @@ -28,7 +28,7 @@ contract RefundableCrowdsale is FinalizableCrowdsale { * @param goal Funding goal */ constructor (uint256 goal) public { - require(goal > 0); + require(goal > 0, "RefundableCrowdsale: goal is 0"); _escrow = new RefundEscrow(wallet()); _goal = goal; } @@ -45,8 +45,8 @@ contract RefundableCrowdsale is FinalizableCrowdsale { * @param refundee Whose refund will be claimed. */ function claimRefund(address payable refundee) public { - require(finalized()); - require(!goalReached()); + require(finalized(), "RefundableCrowdsale: not finalized"); + require(!goalReached(), "RefundableCrowdsale: goal reached"); _escrow.withdraw(refundee); } diff --git a/contracts/crowdsale/distribution/RefundablePostDeliveryCrowdsale.sol b/contracts/crowdsale/distribution/RefundablePostDeliveryCrowdsale.sol index fd46a42b6be..7fcd6856503 100644 --- a/contracts/crowdsale/distribution/RefundablePostDeliveryCrowdsale.sol +++ b/contracts/crowdsale/distribution/RefundablePostDeliveryCrowdsale.sol @@ -12,8 +12,8 @@ import "./PostDeliveryCrowdsale.sol"; */ contract RefundablePostDeliveryCrowdsale is RefundableCrowdsale, PostDeliveryCrowdsale { function withdrawTokens(address beneficiary) public { - require(finalized()); - require(goalReached()); + 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 index 58ff0034c7c..cc9eaff68a4 100644 --- a/contracts/crowdsale/emission/AllowanceCrowdsale.sol +++ b/contracts/crowdsale/emission/AllowanceCrowdsale.sol @@ -21,7 +21,7 @@ contract AllowanceCrowdsale is Crowdsale { * @param tokenWallet Address holding the tokens, which has approved allowance to the crowdsale. */ constructor (address tokenWallet) public { - require(tokenWallet != address(0)); + require(tokenWallet != address(0), "AllowanceCrowdsale: token wallet is the zero address"); _tokenWallet = tokenWallet; } diff --git a/contracts/crowdsale/emission/MintedCrowdsale.sol b/contracts/crowdsale/emission/MintedCrowdsale.sol index 35d1f7167a5..fe456715442 100644 --- a/contracts/crowdsale/emission/MintedCrowdsale.sol +++ b/contracts/crowdsale/emission/MintedCrowdsale.sol @@ -16,6 +16,9 @@ contract MintedCrowdsale is Crowdsale { */ function _deliverTokens(address beneficiary, uint256 tokenAmount) internal { // Potentially dangerous assumption about the type of the token. - require(ERC20Mintable(address(token())).mint(beneficiary, tokenAmount)); + require( + ERC20Mintable(address(token())).mint(beneficiary, tokenAmount), + "MintedCrowdsale: minting failed" + ); } } diff --git a/contracts/crowdsale/price/IncreasingPriceCrowdsale.sol b/contracts/crowdsale/price/IncreasingPriceCrowdsale.sol index 36a9cdf7083..75834b7f1e6 100644 --- a/contracts/crowdsale/price/IncreasingPriceCrowdsale.sol +++ b/contracts/crowdsale/price/IncreasingPriceCrowdsale.sol @@ -21,8 +21,9 @@ contract IncreasingPriceCrowdsale is TimedCrowdsale { * @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); - require(initialRate > finalRate); + 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; } @@ -32,7 +33,7 @@ contract IncreasingPriceCrowdsale is TimedCrowdsale { * all calls to it are a mistake. */ function rate() public view returns (uint256) { - revert(); + revert("IncreasingPriceCrowdsale: rate() called"); } /** diff --git a/contracts/crowdsale/validation/CappedCrowdsale.sol b/contracts/crowdsale/validation/CappedCrowdsale.sol index 0af1fd07966..44293d48b49 100644 --- a/contracts/crowdsale/validation/CappedCrowdsale.sol +++ b/contracts/crowdsale/validation/CappedCrowdsale.sol @@ -17,7 +17,7 @@ contract CappedCrowdsale is Crowdsale { * @param cap Max amount of wei to be contributed */ constructor (uint256 cap) public { - require(cap > 0); + require(cap > 0, "CappedCrowdsale: cap is 0"); _cap = cap; } @@ -43,6 +43,6 @@ contract CappedCrowdsale is Crowdsale { */ function _preValidatePurchase(address beneficiary, uint256 weiAmount) internal view { super._preValidatePurchase(beneficiary, weiAmount); - require(weiRaised().add(weiAmount) <= _cap); + require(weiRaised().add(weiAmount) <= _cap, "CappedCrowdsale: cap exceeded"); } } diff --git a/contracts/crowdsale/validation/IndividuallyCappedCrowdsale.sol b/contracts/crowdsale/validation/IndividuallyCappedCrowdsale.sol index 7c64135b84f..8dbcd0ee4d3 100644 --- a/contracts/crowdsale/validation/IndividuallyCappedCrowdsale.sol +++ b/contracts/crowdsale/validation/IndividuallyCappedCrowdsale.sol @@ -48,7 +48,8 @@ contract IndividuallyCappedCrowdsale is Crowdsale, CapperRole { */ function _preValidatePurchase(address beneficiary, uint256 weiAmount) internal view { super._preValidatePurchase(beneficiary, weiAmount); - require(_contributions[beneficiary].add(weiAmount) <= _caps[beneficiary]); + // solhint-disable-next-line max-line-length + require(_contributions[beneficiary].add(weiAmount) <= _caps[beneficiary], "IndividuallyCappedCrowdsale: beneficiary's cap exceeded"); } /** diff --git a/contracts/crowdsale/validation/TimedCrowdsale.sol b/contracts/crowdsale/validation/TimedCrowdsale.sol index 690525bee48..a885486195a 100644 --- a/contracts/crowdsale/validation/TimedCrowdsale.sol +++ b/contracts/crowdsale/validation/TimedCrowdsale.sol @@ -24,7 +24,7 @@ contract TimedCrowdsale is Crowdsale { * @dev Reverts if not in crowdsale time range. */ modifier onlyWhileOpen { - require(isOpen()); + require(isOpen(), "TimedCrowdsale: not open"); _; } @@ -35,8 +35,9 @@ contract TimedCrowdsale is Crowdsale { */ constructor (uint256 openingTime, uint256 closingTime) public { // solhint-disable-next-line not-rely-on-time - require(openingTime >= block.timestamp); - require(closingTime > openingTime); + 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; @@ -87,8 +88,9 @@ contract TimedCrowdsale is Crowdsale { * @param newClosingTime Crowdsale closing time */ function _extendTime(uint256 newClosingTime) internal { - require(!hasClosed()); - require(newClosingTime > _closingTime); + 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 index 73aa1e599b8..8cdd478a4d2 100644 --- a/contracts/crowdsale/validation/WhitelistCrowdsale.sol +++ b/contracts/crowdsale/validation/WhitelistCrowdsale.sol @@ -15,7 +15,7 @@ contract WhitelistCrowdsale is WhitelistedRole, Crowdsale { * @param _weiAmount Amount of wei contributed */ function _preValidatePurchase(address _beneficiary, uint256 _weiAmount) internal view { - require(isWhitelisted(_beneficiary)); + require(isWhitelisted(_beneficiary), "WhitelistCrowdsale: beneficiary doesn't have the Whitelisted role"); super._preValidatePurchase(_beneficiary, _weiAmount); } } diff --git a/contracts/drafts/ERC20Migrator.sol b/contracts/drafts/ERC20Migrator.sol index bf00f87e4a2..f0daf90870c 100644 --- a/contracts/drafts/ERC20Migrator.sol +++ b/contracts/drafts/ERC20Migrator.sol @@ -44,7 +44,7 @@ contract ERC20Migrator { * @param legacyToken address of the old token contract */ constructor (IERC20 legacyToken) public { - require(address(legacyToken) != address(0)); + require(address(legacyToken) != address(0), "ERC20Migrator: legacy token is the zero address"); _legacyToken = legacyToken; } @@ -68,9 +68,10 @@ contract ERC20Migrator { * @param newToken_ the token that will be minted */ function beginMigration(ERC20Mintable newToken_) public { - require(address(_newToken) == address(0)); - require(address(newToken_) != address(0)); - require(newToken_.isMinter(address(this))); + 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_; } @@ -82,7 +83,7 @@ contract ERC20Migrator { * @param amount amount of tokens to be migrated */ function migrate(address account, uint256 amount) public { - require(address(_newToken) != address(0)); + require(address(_newToken) != address(0), "ERC20Migrator: migration not started"); _legacyToken.safeTransferFrom(account, address(this), amount); _newToken.mint(account, amount); } diff --git a/contracts/drafts/ERC20Snapshot.sol b/contracts/drafts/ERC20Snapshot.sol index be11e899edf..f226a203705 100644 --- a/contracts/drafts/ERC20Snapshot.sol +++ b/contracts/drafts/ERC20Snapshot.sol @@ -101,8 +101,9 @@ contract ERC20Snapshot is ERC20 { function _valueAt(uint256 snapshotId, Snapshots storage snapshots) private view returns (bool, uint256) { - require(snapshotId > 0); - require(snapshotId <= _currentSnapshotId.current()); + require(snapshotId > 0, "ERC20Snapshot: id is 0"); + // solhint-disable-next-line max-line-length + require(snapshotId <= _currentSnapshotId.current(), "ERC20Snapshot: nonexistent id"); uint256 index = snapshots.ids.findUpperBound(snapshotId); diff --git a/contracts/drafts/SignatureBouncer.sol b/contracts/drafts/SignatureBouncer.sol index 69f7c3758ad..5564e117beb 100644 --- a/contracts/drafts/SignatureBouncer.sol +++ b/contracts/drafts/SignatureBouncer.sol @@ -51,7 +51,7 @@ contract SignatureBouncer is SignerRole { * @dev Requires that a valid signature of a signer was provided. */ modifier onlyValidSignature(bytes memory signature) { - require(_isValidSignature(msg.sender, signature)); + require(_isValidSignature(msg.sender, signature), "SignatureBouncer: invalid signature for caller"); _; } @@ -59,7 +59,8 @@ contract SignatureBouncer is SignerRole { * @dev Requires that a valid signature with a specified method of a signer was provided. */ modifier onlyValidSignatureAndMethod(bytes memory signature) { - require(_isValidSignatureAndMethod(msg.sender, signature)); + // solhint-disable-next-line max-line-length + require(_isValidSignatureAndMethod(msg.sender, signature), "SignatureBouncer: invalid signature for caller and method"); _; } @@ -67,7 +68,8 @@ contract SignatureBouncer is SignerRole { * @dev Requires that a valid signature with a specified method and params of a signer was provided. */ modifier onlyValidSignatureAndData(bytes memory signature) { - require(_isValidSignatureAndData(msg.sender, signature)); + // solhint-disable-next-line max-line-length + require(_isValidSignatureAndData(msg.sender, signature), "SignatureBouncer: invalid signature for caller and data"); _; } @@ -97,7 +99,7 @@ contract SignatureBouncer is SignerRole { * @return bool */ function _isValidSignatureAndData(address account, bytes memory signature) internal view returns (bool) { - require(msg.data.length > _SIGNATURE_SIZE); + require(msg.data.length > _SIGNATURE_SIZE, "SignatureBouncer: data is too short"); bytes memory data = new bytes(msg.data.length - _SIGNATURE_SIZE); for (uint i = 0; i < data.length; i++) { diff --git a/contracts/drafts/SignedSafeMath.sol b/contracts/drafts/SignedSafeMath.sol index 7a18c799aba..808bd563efe 100644 --- a/contracts/drafts/SignedSafeMath.sol +++ b/contracts/drafts/SignedSafeMath.sol @@ -18,10 +18,10 @@ library SignedSafeMath { return 0; } - require(!(a == -1 && b == INT256_MIN)); // This is the only case of overflow not detected by the check below + require(!(a == -1 && b == INT256_MIN), "SignedSafeMath: multiplication overflow"); int256 c = a * b; - require(c / a == b); + require(c / a == b, "SignedSafeMath: multiplication overflow"); return c; } @@ -30,8 +30,8 @@ library SignedSafeMath { * @dev Integer division of two signed integers truncating the quotient, reverts on division by zero. */ function div(int256 a, int256 b) internal pure returns (int256) { - require(b != 0); // Solidity only automatically asserts when dividing by 0 - require(!(b == -1 && a == INT256_MIN)); // This is the only case of overflow + require(b != 0, "SignedSafeMath: division by zero"); + require(!(b == -1 && a == INT256_MIN), "SignedSafeMath: division overflow"); int256 c = a / b; @@ -43,7 +43,7 @@ library SignedSafeMath { */ function sub(int256 a, int256 b) internal pure returns (int256) { int256 c = a - b; - require((b >= 0 && c <= a) || (b < 0 && c > a)); + require((b >= 0 && c <= a) || (b < 0 && c > a), "SignedSafeMath: subtraction overflow"); return c; } @@ -53,7 +53,7 @@ library SignedSafeMath { */ function add(int256 a, int256 b) internal pure returns (int256) { int256 c = a + b; - require((b >= 0 && c >= a) || (b < 0 && c < a)); + require((b >= 0 && c >= a) || (b < 0 && c < a), "SignedSafeMath: addition overflow"); return c; } diff --git a/contracts/drafts/TokenVesting.sol b/contracts/drafts/TokenVesting.sol index a053dd089cf..951895d5ea5 100644 --- a/contracts/drafts/TokenVesting.sol +++ b/contracts/drafts/TokenVesting.sol @@ -47,10 +47,12 @@ contract TokenVesting is Ownable { * @param revocable whether the vesting is revocable or not */ constructor (address beneficiary, uint256 start, uint256 cliffDuration, uint256 duration, bool revocable) public { - require(beneficiary != address(0)); - require(cliffDuration <= duration); - require(duration > 0); - require(start.add(duration) > block.timestamp); + require(beneficiary != address(0), "TokenVesting: beneficiary is the zero address"); + // solhint-disable-next-line max-line-length + require(cliffDuration <= duration, "TokenVesting: cliff is longer than duration"); + require(duration > 0, "TokenVesting: duration is 0"); + // solhint-disable-next-line max-line-length + require(start.add(duration) > block.timestamp, "TokenVesting: final time is before current time"); _beneficiary = beneficiary; _revocable = revocable; @@ -115,7 +117,7 @@ contract TokenVesting is Ownable { function release(IERC20 token) public { uint256 unreleased = _releasableAmount(token); - require(unreleased > 0); + require(unreleased > 0, "TokenVesting: no tokens are due"); _released[address(token)] = _released[address(token)].add(unreleased); @@ -130,8 +132,8 @@ contract TokenVesting is Ownable { * @param token ERC20 token which is being vested */ function revoke(IERC20 token) public onlyOwner { - require(_revocable); - require(!_revoked[address(token)]); + require(_revocable, "TokenVesting: cannot revoke"); + require(!_revoked[address(token)], "TokenVesting: token already revoked"); uint256 balance = token.balanceOf(address(this)); diff --git a/contracts/examples/SampleCrowdsale.sol b/contracts/examples/SampleCrowdsale.sol index b77f6cad626..1d8d65ee515 100644 --- a/contracts/examples/SampleCrowdsale.sol +++ b/contracts/examples/SampleCrowdsale.sol @@ -48,6 +48,6 @@ contract SampleCrowdsale is CappedCrowdsale, RefundableCrowdsale, MintedCrowdsal { //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); + require(goal <= cap, "SampleCrowdSale: goal is greater than cap"); } } diff --git a/contracts/introspection/ERC165.sol b/contracts/introspection/ERC165.sol index 0f2c4cbd2f0..4765f83fa9b 100644 --- a/contracts/introspection/ERC165.sol +++ b/contracts/introspection/ERC165.sol @@ -37,7 +37,7 @@ contract ERC165 is IERC165 { * @dev Internal method for registering an interface. */ function _registerInterface(bytes4 interfaceId) internal { - require(interfaceId != 0xffffffff); + require(interfaceId != 0xffffffff, "ERC165: invalid interface id"); _supportedInterfaces[interfaceId] = true; } } diff --git a/contracts/lifecycle/Pausable.sol b/contracts/lifecycle/Pausable.sol index 04c803ce86a..8cbb3e8cda6 100644 --- a/contracts/lifecycle/Pausable.sol +++ b/contracts/lifecycle/Pausable.sol @@ -27,7 +27,7 @@ contract Pausable is PauserRole { * @dev Modifier to make a function callable only when the contract is not paused. */ modifier whenNotPaused() { - require(!_paused); + require(!_paused, "Pausable: paused"); _; } @@ -35,7 +35,7 @@ contract Pausable is PauserRole { * @dev Modifier to make a function callable only when the contract is paused. */ modifier whenPaused() { - require(_paused); + require(_paused, "Pausable: not paused"); _; } diff --git a/contracts/math/SafeMath.sol b/contracts/math/SafeMath.sol index a0dfe349de0..8e5d7bd6f4d 100644 --- a/contracts/math/SafeMath.sol +++ b/contracts/math/SafeMath.sol @@ -17,7 +17,7 @@ library SafeMath { } uint256 c = a * b; - require(c / a == b); + require(c / a == b, "SafeMath: multiplication overflow"); return c; } @@ -27,7 +27,7 @@ library SafeMath { */ function div(uint256 a, uint256 b) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 - require(b > 0); + require(b > 0, "SafeMath: division by zero"); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold @@ -38,7 +38,7 @@ library SafeMath { * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend). */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { - require(b <= a); + require(b <= a, "SafeMath: subtraction overflow"); uint256 c = a - b; return c; @@ -49,7 +49,7 @@ library SafeMath { */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; - require(c >= a); + require(c >= a, "SafeMath: addition overflow"); return c; } @@ -59,7 +59,7 @@ library SafeMath { * reverts when dividing by zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { - require(b != 0); + require(b != 0, "SafeMath: modulo by zero"); return a % b; } } diff --git a/contracts/mocks/ERC165/ERC165InterfacesSupported.sol b/contracts/mocks/ERC165/ERC165InterfacesSupported.sol index 40e3c5e82de..40c74b020a2 100644 --- a/contracts/mocks/ERC165/ERC165InterfacesSupported.sol +++ b/contracts/mocks/ERC165/ERC165InterfacesSupported.sol @@ -42,7 +42,7 @@ contract SupportsInterfaceWithLookupMock is IERC165 { * @dev Private method for registering an interface. */ function _registerInterface(bytes4 interfaceId) internal { - require(interfaceId != 0xffffffff); + require(interfaceId != 0xffffffff, "ERC165InterfacesSupported: invalid interface id"); _supportedInterfaces[interfaceId] = true; } } diff --git a/contracts/mocks/ERC721ReceiverMock.sol b/contracts/mocks/ERC721ReceiverMock.sol index 668fd99af9d..07f5d204bb5 100644 --- a/contracts/mocks/ERC721ReceiverMock.sol +++ b/contracts/mocks/ERC721ReceiverMock.sol @@ -16,7 +16,7 @@ contract ERC721ReceiverMock is IERC721Receiver { function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data) public returns (bytes4) { - require(!_reverts); + require(!_reverts, "ERC721ReceiverMock: reverting"); emit Received(operator, from, tokenId, data, gasleft()); return _retval; } diff --git a/contracts/mocks/ReentrancyAttack.sol b/contracts/mocks/ReentrancyAttack.sol index eb1262d2fc9..e9fbebecfbf 100644 --- a/contracts/mocks/ReentrancyAttack.sol +++ b/contracts/mocks/ReentrancyAttack.sol @@ -4,6 +4,6 @@ contract ReentrancyAttack { function callSender(bytes4 data) public { // solhint-disable-next-line avoid-low-level-calls (bool success,) = msg.sender.call(abi.encodeWithSelector(data)); - require(success); + require(success, "ReentrancyAttack: failed call"); } } diff --git a/contracts/mocks/ReentrancyMock.sol b/contracts/mocks/ReentrancyMock.sol index 6902b014cdf..20eaa873903 100644 --- a/contracts/mocks/ReentrancyMock.sol +++ b/contracts/mocks/ReentrancyMock.sol @@ -26,7 +26,7 @@ contract ReentrancyMock is ReentrancyGuard { count(); // solhint-disable-next-line avoid-low-level-calls (bool success,) = address(this).call(abi.encodeWithSignature("countThisRecursive(uint256)", n - 1)); - require(success); + require(success, "ReentrancyMock: failed call"); } } diff --git a/contracts/mocks/SafeERC20Helper.sol b/contracts/mocks/SafeERC20Helper.sol index edfd8ed17f3..6d77d80307c 100644 --- a/contracts/mocks/SafeERC20Helper.sol +++ b/contracts/mocks/SafeERC20Helper.sol @@ -26,7 +26,7 @@ contract ERC20ReturnFalseMock { } function allowance(address, address) public view returns (uint256) { - require(_dummy == 0); + require(_dummy == 0); // Duummy read from a state variable so that the function is view return 0; } } diff --git a/contracts/ownership/Ownable.sol b/contracts/ownership/Ownable.sol index 5db67f889cd..c03fa2c26b5 100644 --- a/contracts/ownership/Ownable.sol +++ b/contracts/ownership/Ownable.sol @@ -30,7 +30,7 @@ contract Ownable { * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { - require(isOwner()); + require(isOwner(), "Ownable: caller is not the owner"); _; } @@ -66,7 +66,7 @@ contract Ownable { * @param newOwner The address to transfer ownership to. */ function _transferOwnership(address newOwner) internal { - require(newOwner != address(0)); + 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 b3a17a23c53..49784989dd9 100644 --- a/contracts/ownership/Secondary.sol +++ b/contracts/ownership/Secondary.sol @@ -23,7 +23,7 @@ contract Secondary { * @dev Reverts if called from any account other than the primary. */ modifier onlyPrimary() { - require(msg.sender == _primary); + require(msg.sender == _primary, "Secondary: caller is not the primary account"); _; } @@ -39,7 +39,7 @@ contract Secondary { * @param recipient The address of new primary. */ function transferPrimary(address recipient) public onlyPrimary { - require(recipient != address(0)); + require(recipient != address(0), "Secondary: new primary is the zero address"); _primary = recipient; emit PrimaryTransferred(_primary); } diff --git a/contracts/payment/PaymentSplitter.sol b/contracts/payment/PaymentSplitter.sol index f281d9700b0..cbf142293a1 100644 --- a/contracts/payment/PaymentSplitter.sol +++ b/contracts/payment/PaymentSplitter.sol @@ -37,8 +37,9 @@ contract PaymentSplitter { * duplicates in `payees`. */ constructor (address[] memory payees, uint256[] memory shares) public payable { - require(payees.length == shares.length); - require(payees.length > 0); + // solhint-disable-next-line max-line-length + require(payees.length == shares.length, "PaymentSplitter: payees and shares length mismatch"); + require(payees.length > 0, "PaymentSplitter: no payees"); for (uint256 i = 0; i < payees.length; i++) { _addPayee(payees[i], shares[i]); @@ -98,12 +99,12 @@ contract PaymentSplitter { * total shares and their previous withdrawals. */ function release(address payable account) public { - require(_shares[account] > 0); + require(_shares[account] > 0, "PaymentSplitter: account has no shares"); uint256 totalReceived = address(this).balance.add(_totalReleased); uint256 payment = totalReceived.mul(_shares[account]).div(_totalShares).sub(_released[account]); - require(payment != 0); + require(payment != 0, "PaymentSplitter: account is not due payment"); _released[account] = _released[account].add(payment); _totalReleased = _totalReleased.add(payment); @@ -118,9 +119,9 @@ contract PaymentSplitter { * @param shares_ The number of shares owned by the payee. */ function _addPayee(address account, uint256 shares_) private { - require(account != address(0)); - require(shares_ > 0); - require(_shares[account] == 0); + require(account != address(0), "PaymentSplitter: account is the zero address"); + require(shares_ > 0, "PaymentSplitter: shares are 0"); + require(_shares[account] == 0, "PaymentSplitter: account already has shares"); _payees.push(account); _shares[account] = shares_; diff --git a/contracts/payment/escrow/ConditionalEscrow.sol b/contracts/payment/escrow/ConditionalEscrow.sol index bcc804ecfd9..96a2a01394d 100644 --- a/contracts/payment/escrow/ConditionalEscrow.sol +++ b/contracts/payment/escrow/ConditionalEscrow.sol @@ -16,7 +16,7 @@ contract ConditionalEscrow is Escrow { function withdrawalAllowed(address payee) public view returns (bool); function withdraw(address payable payee) public { - require(withdrawalAllowed(payee)); + require(withdrawalAllowed(payee), "ConditionalEscrow: payee is not allowed to withdraw"); super.withdraw(payee); } } diff --git a/contracts/payment/escrow/RefundEscrow.sol b/contracts/payment/escrow/RefundEscrow.sol index 2c5314d966e..95e43ba3ae8 100644 --- a/contracts/payment/escrow/RefundEscrow.sol +++ b/contracts/payment/escrow/RefundEscrow.sol @@ -27,7 +27,7 @@ contract RefundEscrow is ConditionalEscrow { * @param beneficiary The beneficiary of the deposits. */ constructor (address payable beneficiary) public { - require(beneficiary != address(0)); + require(beneficiary != address(0), "RefundEscrow: beneficiary is the zero address"); _beneficiary = beneficiary; _state = State.Active; } @@ -51,7 +51,7 @@ contract RefundEscrow is ConditionalEscrow { * @param refundee The address funds will be sent to if a refund occurs. */ function deposit(address refundee) public payable { - require(_state == State.Active); + require(_state == State.Active, "RefundEscrow: can only deposit while active"); super.deposit(refundee); } @@ -60,7 +60,7 @@ contract RefundEscrow is ConditionalEscrow { * further deposits. */ function close() public onlyPrimary { - require(_state == State.Active); + require(_state == State.Active, "RefundEscrow: can only close while active"); _state = State.Closed; emit RefundsClosed(); } @@ -69,7 +69,7 @@ contract RefundEscrow is ConditionalEscrow { * @dev Allows for refunds to take place, rejecting further deposits. */ function enableRefunds() public onlyPrimary { - require(_state == State.Active); + require(_state == State.Active, "RefundEscrow: can only enable refunds while active"); _state = State.Refunding; emit RefundsEnabled(); } @@ -78,7 +78,7 @@ contract RefundEscrow is ConditionalEscrow { * @dev Withdraws the beneficiary's funds. */ function beneficiaryWithdraw() public { - require(_state == State.Closed); + require(_state == State.Closed, "RefundEscrow: beneficiary can only withdraw while closed"); _beneficiary.transfer(address(this).balance); } diff --git a/contracts/token/ERC20/ERC20.sol b/contracts/token/ERC20/ERC20.sol index ba48ac2d6d4..c767898e070 100644 --- a/contracts/token/ERC20/ERC20.sol +++ b/contracts/token/ERC20/ERC20.sol @@ -125,7 +125,7 @@ contract ERC20 is IERC20 { * @param value The amount to be transferred. */ function _transfer(address from, address to, uint256 value) internal { - require(to != address(0)); + require(to != address(0), "ERC20: transfer to the zero address"); _balances[from] = _balances[from].sub(value); _balances[to] = _balances[to].add(value); @@ -140,7 +140,7 @@ contract ERC20 is IERC20 { * @param value The amount that will be created. */ function _mint(address account, uint256 value) internal { - require(account != address(0)); + require(account != address(0), "ERC20: mint to the zero address"); _totalSupply = _totalSupply.add(value); _balances[account] = _balances[account].add(value); @@ -154,7 +154,7 @@ contract ERC20 is IERC20 { * @param value The amount that will be burnt. */ function _burn(address account, uint256 value) internal { - require(account != address(0)); + require(account != address(0), "ERC20: burn from the zero address"); _totalSupply = _totalSupply.sub(value); _balances[account] = _balances[account].sub(value); @@ -168,8 +168,8 @@ contract ERC20 is IERC20 { * @param value The number of tokens that can be spent. */ function _approve(address owner, address spender, uint256 value) internal { - require(spender != address(0)); - require(owner != address(0)); + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); _allowed[owner][spender] = value; emit Approval(owner, spender, value); diff --git a/contracts/token/ERC20/ERC20Capped.sol b/contracts/token/ERC20/ERC20Capped.sol index c9146a5a05e..9d44cf73b59 100644 --- a/contracts/token/ERC20/ERC20Capped.sol +++ b/contracts/token/ERC20/ERC20Capped.sol @@ -10,7 +10,7 @@ contract ERC20Capped is ERC20Mintable { uint256 private _cap; constructor (uint256 cap) public { - require(cap > 0); + require(cap > 0, "ERC20Capped: cap is 0"); _cap = cap; } @@ -22,7 +22,7 @@ contract ERC20Capped is ERC20Mintable { } function _mint(address account, uint256 value) internal { - require(totalSupply().add(value) <= _cap); + require(totalSupply().add(value) <= _cap, "ERC20Capped: cap exceeded"); super._mint(account, value); } } diff --git a/contracts/token/ERC20/SafeERC20.sol b/contracts/token/ERC20/SafeERC20.sol index c6c6273bb9a..3c4e032a027 100644 --- a/contracts/token/ERC20/SafeERC20.sol +++ b/contracts/token/ERC20/SafeERC20.sol @@ -29,7 +29,10 @@ library SafeERC20 { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' - require((value == 0) || (token.allowance(address(this), spender) == 0)); + // solhint-disable-next-line max-line-length + require((value == 0) || (token.allowance(address(this), spender) == 0), + "SafeERC20: approve from non-zero to non-zero allowance" + ); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } @@ -57,15 +60,16 @@ library SafeERC20 { // 1. The target address is checked to verify it contains contract code // 2. The call itself is made, and success asserted // 3. The return value is decoded, which in turn checks the size of the returned data. - - require(address(token).isContract()); + // solhint-disable-next-line max-line-length + require(address(token).isContract(), "SafeERC20: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = address(token).call(data); - require(success); + require(success, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional - require(abi.decode(returndata, (bool))); + // solhint-disable-next-line max-line-length + require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } } diff --git a/contracts/token/ERC20/TokenTimelock.sol b/contracts/token/ERC20/TokenTimelock.sol index 4667285d571..a03b7503661 100644 --- a/contracts/token/ERC20/TokenTimelock.sol +++ b/contracts/token/ERC20/TokenTimelock.sol @@ -21,7 +21,7 @@ contract TokenTimelock { constructor (IERC20 token, address beneficiary, uint256 releaseTime) public { // solhint-disable-next-line not-rely-on-time - require(releaseTime > block.timestamp); + require(releaseTime > block.timestamp, "TokenTimelock: release time is before current time"); _token = token; _beneficiary = beneficiary; _releaseTime = releaseTime; @@ -53,10 +53,10 @@ contract TokenTimelock { */ function release() public { // solhint-disable-next-line not-rely-on-time - require(block.timestamp >= _releaseTime); + require(block.timestamp >= _releaseTime, "TokenTimelock: current time is before release time"); uint256 amount = _token.balanceOf(address(this)); - require(amount > 0); + require(amount > 0, "TokenTimelock: no tokens to release"); _token.safeTransfer(_beneficiary, amount); } diff --git a/contracts/token/ERC721/ERC721.sol b/contracts/token/ERC721/ERC721.sol index ed7862afe40..e71905c56ad 100644 --- a/contracts/token/ERC721/ERC721.sol +++ b/contracts/token/ERC721/ERC721.sol @@ -59,7 +59,8 @@ contract ERC721 is ERC165, IERC721 { * @return uint256 representing the amount owned by the passed address */ function balanceOf(address owner) public view returns (uint256) { - require(owner != address(0)); + require(owner != address(0), "ERC721: balance query for the zero address"); + return _ownedTokensCount[owner].current(); } @@ -70,7 +71,8 @@ contract ERC721 is ERC165, IERC721 { */ function ownerOf(uint256 tokenId) public view returns (address) { address owner = _tokenOwner[tokenId]; - require(owner != address(0)); + require(owner != address(0), "ERC721: owner query for nonexistent token"); + return owner; } @@ -84,8 +86,11 @@ contract ERC721 is ERC165, IERC721 { */ function approve(address to, uint256 tokenId) public { address owner = ownerOf(tokenId); - require(to != owner); - require(msg.sender == owner || isApprovedForAll(owner, msg.sender)); + require(to != owner, "ERC721: transfer to current owner"); + + require(msg.sender == owner || isApprovedForAll(owner, msg.sender), + "ERC721: approve caller is not owner nor approved for all" + ); _tokenApprovals[tokenId] = to; emit Approval(owner, to, tokenId); @@ -98,7 +103,8 @@ contract ERC721 is ERC165, IERC721 { * @return address currently approved for the given token ID */ function getApproved(uint256 tokenId) public view returns (address) { - require(_exists(tokenId)); + require(_exists(tokenId), "ERC721: approved query for nonexistent token"); + return _tokenApprovals[tokenId]; } @@ -109,7 +115,8 @@ contract ERC721 is ERC165, IERC721 { * @param approved representing the status of the approval to be set */ function setApprovalForAll(address to, bool approved) public { - require(to != msg.sender); + require(to != msg.sender, "ERC721: approve to caller"); + _operatorApprovals[msg.sender][to] = approved; emit ApprovalForAll(msg.sender, to, approved); } @@ -133,7 +140,8 @@ contract ERC721 is ERC165, IERC721 { * @param tokenId uint256 ID of the token to be transferred */ function transferFrom(address from, address to, uint256 tokenId) public { - require(_isApprovedOrOwner(msg.sender, tokenId)); + //solhint-disable-next-line max-line-length + require(_isApprovedOrOwner(msg.sender, tokenId), "ERC721: transfer caller is not owner nor approved"); _transferFrom(from, to, tokenId); } @@ -167,7 +175,7 @@ contract ERC721 is ERC165, IERC721 { */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public { transferFrom(from, to, tokenId); - require(_checkOnERC721Received(from, to, tokenId, _data)); + require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); } /** @@ -188,6 +196,7 @@ contract ERC721 is ERC165, IERC721 { * is an operator of the owner, or is the owner of the token */ function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) { + require(_exists(tokenId), "ERC721: operator query for nonexistent token"); address owner = ownerOf(tokenId); return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender)); } @@ -199,8 +208,8 @@ contract ERC721 is ERC165, IERC721 { * @param tokenId uint256 ID of the token to be minted */ function _mint(address to, uint256 tokenId) internal { - require(to != address(0)); - require(!_exists(tokenId)); + require(to != address(0), "ERC721: mint to the zero address"); + require(!_exists(tokenId), "ERC721: token already minted"); _tokenOwner[tokenId] = to; _ownedTokensCount[to].increment(); @@ -216,7 +225,7 @@ contract ERC721 is ERC165, IERC721 { * @param tokenId uint256 ID of the token being burned */ function _burn(address owner, uint256 tokenId) internal { - require(ownerOf(tokenId) == owner); + require(ownerOf(tokenId) == owner, "ERC721: burn of token that is not own"); _clearApproval(tokenId); @@ -243,8 +252,8 @@ contract ERC721 is ERC165, IERC721 { * @param tokenId uint256 ID of the token to be transferred */ function _transferFrom(address from, address to, uint256 tokenId) internal { - require(ownerOf(tokenId) == from); - require(to != address(0)); + require(ownerOf(tokenId) == from, "ERC721: transfer of token that is not own"); + require(to != address(0), "ERC721: transfer to the zero address"); _clearApproval(tokenId); diff --git a/contracts/token/ERC721/ERC721Burnable.sol b/contracts/token/ERC721/ERC721Burnable.sol index 249b1ed093e..52291eef2fe 100644 --- a/contracts/token/ERC721/ERC721Burnable.sol +++ b/contracts/token/ERC721/ERC721Burnable.sol @@ -12,7 +12,8 @@ contract ERC721Burnable is ERC721 { * @param tokenId uint256 id of the ERC721 token to be burned. */ function burn(uint256 tokenId) public { - require(_isApprovedOrOwner(msg.sender, tokenId)); + //solhint-disable-next-line max-line-length + require(_isApprovedOrOwner(msg.sender, 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 f79cbfa68a9..0ef5ea00f58 100644 --- a/contracts/token/ERC721/ERC721Enumerable.sol +++ b/contracts/token/ERC721/ERC721Enumerable.sol @@ -45,7 +45,7 @@ contract ERC721Enumerable is ERC165, ERC721, IERC721Enumerable { * @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) { - require(index < balanceOf(owner)); + require(index < balanceOf(owner), "ERC721Enumerable: owner index out of bounds"); return _ownedTokens[owner][index]; } @@ -64,7 +64,7 @@ contract ERC721Enumerable is ERC165, ERC721, IERC721Enumerable { * @return uint256 token ID at the given index of the tokens list */ function tokenByIndex(uint256 index) public view returns (uint256) { - require(index < totalSupply()); + require(index < totalSupply(), "ERC721Enumerable: global index out of bounds"); return _allTokens[index]; } diff --git a/contracts/token/ERC721/ERC721Metadata.sol b/contracts/token/ERC721/ERC721Metadata.sol index c28d6c500ba..685505ca3d7 100644 --- a/contracts/token/ERC721/ERC721Metadata.sol +++ b/contracts/token/ERC721/ERC721Metadata.sol @@ -56,7 +56,7 @@ contract ERC721Metadata is ERC165, ERC721, IERC721Metadata { * @param tokenId uint256 ID of the token to query */ function tokenURI(uint256 tokenId) external view returns (string memory) { - require(_exists(tokenId)); + require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token"); return _tokenURIs[tokenId]; } @@ -67,7 +67,7 @@ contract ERC721Metadata is ERC165, ERC721, IERC721Metadata { * @param uri string URI to assign */ function _setTokenURI(uint256 tokenId, string memory uri) internal { - require(_exists(tokenId)); + require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token"); _tokenURIs[tokenId] = uri; } diff --git a/contracts/utils/ReentrancyGuard.sol b/contracts/utils/ReentrancyGuard.sol index fb1f292d3ab..19a2b6bc83d 100644 --- a/contracts/utils/ReentrancyGuard.sol +++ b/contracts/utils/ReentrancyGuard.sol @@ -27,6 +27,6 @@ contract ReentrancyGuard { _guardCounter += 1; uint256 localCounter = _guardCounter; _; - require(localCounter == _guardCounter); + require(localCounter == _guardCounter, "ReentrancyGuard: reentrant call"); } } diff --git a/test/access/Roles.test.js b/test/access/Roles.test.js index 6e3e931501e..056a2b9a44d 100644 --- a/test/access/Roles.test.js +++ b/test/access/Roles.test.js @@ -9,7 +9,7 @@ contract('Roles', function ([_, authorized, otherAuthorized, other]) { }); it('reverts when querying roles for the zero account', async function () { - await shouldFail.reverting(this.roles.has(ZERO_ADDRESS)); + await shouldFail.reverting.withMessage(this.roles.has(ZERO_ADDRESS), 'Roles: account is the zero address'); }); context('initially', function () { @@ -28,11 +28,11 @@ contract('Roles', function ([_, authorized, otherAuthorized, other]) { it('reverts when adding roles to an already assigned account', async function () { await this.roles.add(authorized); - await shouldFail.reverting(this.roles.add(authorized)); + await shouldFail.reverting.withMessage(this.roles.add(authorized), 'Roles: account already has role'); }); it('reverts when adding roles to the zero account', async function () { - await shouldFail.reverting(this.roles.add(ZERO_ADDRESS)); + await shouldFail.reverting.withMessage(this.roles.add(ZERO_ADDRESS), 'Roles: account is the zero address'); }); }); }); @@ -51,11 +51,11 @@ contract('Roles', function ([_, authorized, otherAuthorized, other]) { }); it('reverts when removing unassigned roles', async function () { - await shouldFail.reverting(this.roles.remove(other)); + await shouldFail.reverting.withMessage(this.roles.remove(other), 'Roles: account does not have role'); }); it('reverts when removing roles from the zero account', async function () { - await shouldFail.reverting(this.roles.remove(ZERO_ADDRESS)); + await shouldFail.reverting.withMessage(this.roles.remove(ZERO_ADDRESS), 'Roles: account is the zero address'); }); }); }); diff --git a/test/behaviors/access/roles/PublicRole.behavior.js b/test/behaviors/access/roles/PublicRole.behavior.js index c7eb04adff6..fcdc03005a5 100644 --- a/test/behaviors/access/roles/PublicRole.behavior.js +++ b/test/behaviors/access/roles/PublicRole.behavior.js @@ -39,7 +39,9 @@ function shouldBehaveLikePublicRole (authorized, otherAuthorized, [other], rolen } it('reverts when querying roles for the null account', async function () { - await shouldFail.reverting(this.contract[`is${rolename}`](ZERO_ADDRESS)); + await shouldFail.reverting.withMessage(this.contract[`is${rolename}`](ZERO_ADDRESS), + 'Roles: account is the zero address' + ); }); describe('access control', function () { @@ -55,7 +57,9 @@ function shouldBehaveLikePublicRole (authorized, otherAuthorized, [other], rolen const from = other; it('reverts', async function () { - await shouldFail.reverting(this.contract[`only${rolename}Mock`]({ from })); + await shouldFail.reverting.withMessage(this.contract[`only${rolename}Mock`]({ from }), + `${rolename}Role: caller does not have the ${rolename} role` + ); }); }); }); @@ -75,11 +79,15 @@ function shouldBehaveLikePublicRole (authorized, otherAuthorized, [other], rolen }); it('reverts when adding role to an already assigned account', async function () { - await shouldFail.reverting(this.contract[`add${rolename}`](authorized, { from })); + await shouldFail.reverting.withMessage(this.contract[`add${rolename}`](authorized, { from }), + 'Roles: account already has role' + ); }); it('reverts when adding role to the null account', async function () { - await shouldFail.reverting(this.contract[`add${rolename}`](ZERO_ADDRESS, { from })); + await shouldFail.reverting.withMessage(this.contract[`add${rolename}`](ZERO_ADDRESS, { from }), + 'Roles: account is the zero address' + ); }); }); }); @@ -101,11 +109,15 @@ function shouldBehaveLikePublicRole (authorized, otherAuthorized, [other], rolen }); it('reverts when removing from an unassigned account', async function () { - await shouldFail.reverting(this.contract[`remove${rolename}`](other, { from })); + await shouldFail.reverting.withMessage(this.contract[`remove${rolename}`](other, { from }), + 'Roles: account does not have role' + ); }); it('reverts when removing role from the null account', async function () { - await shouldFail.reverting(this.contract[`remove${rolename}`](ZERO_ADDRESS, { from })); + await shouldFail.reverting.withMessage(this.contract[`remove${rolename}`](ZERO_ADDRESS, { from }), + 'Roles: account is the zero address' + ); }); }); }); @@ -122,7 +134,9 @@ function shouldBehaveLikePublicRole (authorized, otherAuthorized, [other], rolen }); it('reverts when renouncing unassigned role', async function () { - await shouldFail.reverting(this.contract[`renounce${rolename}`]({ from: other })); + await shouldFail.reverting.withMessage(this.contract[`renounce${rolename}`]({ from: other }), + 'Roles: account does not have role' + ); }); }); }); diff --git a/test/crowdsale/AllowanceCrowdsale.test.js b/test/crowdsale/AllowanceCrowdsale.test.js index 10d0d6a49ee..0a1d40c5baf 100644 --- a/test/crowdsale/AllowanceCrowdsale.test.js +++ b/test/crowdsale/AllowanceCrowdsale.test.js @@ -75,7 +75,9 @@ contract('AllowanceCrowdsale', function ([_, investor, wallet, purchaser, tokenW describe('when token wallet is the zero address', function () { it('creation reverts', async function () { this.token = await SimpleToken.new({ from: tokenWallet }); - await shouldFail.reverting(AllowanceCrowdsaleImpl.new(rate, wallet, this.token.address, ZERO_ADDRESS)); + await shouldFail.reverting.withMessage(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 index 37bfaedb3fe..dc0b8fbd421 100644 --- a/test/crowdsale/CappedCrowdsale.test.js +++ b/test/crowdsale/CappedCrowdsale.test.js @@ -14,7 +14,9 @@ contract('CappedCrowdsale', function ([_, wallet]) { }); it('rejects a cap of zero', async function () { - await shouldFail.reverting(CappedCrowdsaleImpl.new(rate, wallet, this.token.address, 0)); + await shouldFail.reverting.withMessage(CappedCrowdsaleImpl.new(rate, wallet, this.token.address, 0), + 'CappedCrowdsale: cap is 0' + ); }); context('with crowdsale', function () { @@ -31,11 +33,11 @@ contract('CappedCrowdsale', function ([_, wallet]) { it('should reject payments outside cap', async function () { await this.crowdsale.send(cap); - await shouldFail.reverting(this.crowdsale.send(1)); + await shouldFail.reverting.withMessage(this.crowdsale.send(1), 'CappedCrowdsale: cap exceeded'); }); it('should reject payments that exceed cap', async function () { - await shouldFail.reverting(this.crowdsale.send(cap.addn(1))); + await shouldFail.reverting.withMessage(this.crowdsale.send(cap.addn(1)), 'CappedCrowdsale: cap exceeded'); }); }); diff --git a/test/crowdsale/Crowdsale.test.js b/test/crowdsale/Crowdsale.test.js index 76eef628444..b6788d1895f 100644 --- a/test/crowdsale/Crowdsale.test.js +++ b/test/crowdsale/Crowdsale.test.js @@ -11,8 +11,9 @@ contract('Crowdsale', function ([_, investor, wallet, purchaser]) { const expectedTokenAmount = rate.mul(value); it('requires a non-null token', async function () { - await shouldFail.reverting( - Crowdsale.new(rate, wallet, ZERO_ADDRESS) + await shouldFail.reverting.withMessage( + Crowdsale.new(rate, wallet, ZERO_ADDRESS), + 'Crowdsale: token is the zero address' ); }); @@ -22,14 +23,14 @@ contract('Crowdsale', function ([_, investor, wallet, purchaser]) { }); it('requires a non-zero rate', async function () { - await shouldFail.reverting( - Crowdsale.new(0, wallet, this.token.address) + await shouldFail.reverting.withMessage( + Crowdsale.new(0, wallet, this.token.address), 'Crowdsale: rate is 0' ); }); it('requires a non-null wallet', async function () { - await shouldFail.reverting( - Crowdsale.new(rate, ZERO_ADDRESS, this.token.address) + await shouldFail.reverting.withMessage( + Crowdsale.new(rate, ZERO_ADDRESS, this.token.address), 'Crowdsale: wallet is the zero address' ); }); @@ -46,8 +47,8 @@ contract('Crowdsale', function ([_, investor, wallet, purchaser]) { }); it('reverts on zero-valued payments', async function () { - await shouldFail.reverting( - this.crowdsale.send(0, { from: purchaser }) + await shouldFail.reverting.withMessage( + this.crowdsale.send(0, { from: purchaser }), 'Crowdsale: weiAmount is 0' ); }); }); @@ -58,14 +59,15 @@ contract('Crowdsale', function ([_, investor, wallet, purchaser]) { }); it('reverts on zero-valued payments', async function () { - await shouldFail.reverting( - this.crowdsale.buyTokens(investor, { value: 0, from: purchaser }) + await shouldFail.reverting.withMessage( + this.crowdsale.buyTokens(investor, { value: 0, from: purchaser }), 'Crowdsale: weiAmount is 0' ); }); it('requires a non-null beneficiary', async function () { - await shouldFail.reverting( - this.crowdsale.buyTokens(ZERO_ADDRESS, { value: value, from: purchaser }) + await shouldFail.reverting.withMessage( + this.crowdsale.buyTokens(ZERO_ADDRESS, { value: value, from: purchaser }), + 'Crowdsale: beneficiary is the zero address' ); }); }); diff --git a/test/crowdsale/FinalizableCrowdsale.test.js b/test/crowdsale/FinalizableCrowdsale.test.js index 77724e3e3b7..b63410d625f 100644 --- a/test/crowdsale/FinalizableCrowdsale.test.js +++ b/test/crowdsale/FinalizableCrowdsale.test.js @@ -23,7 +23,9 @@ contract('FinalizableCrowdsale', function ([_, wallet, other]) { }); it('cannot be finalized before ending', async function () { - await shouldFail.reverting(this.crowdsale.finalize({ from: other })); + await shouldFail.reverting.withMessage(this.crowdsale.finalize({ from: other }), + 'FinalizableCrowdsale: not closed' + ); }); it('can be finalized by anyone after ending', async function () { @@ -34,7 +36,9 @@ contract('FinalizableCrowdsale', function ([_, wallet, other]) { it('cannot be finalized twice', async function () { await time.increaseTo(this.afterClosingTime); await this.crowdsale.finalize({ from: other }); - await shouldFail.reverting(this.crowdsale.finalize({ from: other })); + await shouldFail.reverting.withMessage(this.crowdsale.finalize({ from: other }), + 'FinalizableCrowdsale: already finalized' + ); }); it('logs finalized', async function () { diff --git a/test/crowdsale/IncreasingPriceCrowdsale.test.js b/test/crowdsale/IncreasingPriceCrowdsale.test.js index 387e3ff6fb0..ba4ad0b8747 100644 --- a/test/crowdsale/IncreasingPriceCrowdsale.test.js +++ b/test/crowdsale/IncreasingPriceCrowdsale.test.js @@ -26,21 +26,21 @@ contract('IncreasingPriceCrowdsale', function ([_, investor, wallet, purchaser]) }); it('reverts with a final rate larger than the initial rate', async function () { - await shouldFail.reverting(IncreasingPriceCrowdsaleImpl.new( + await shouldFail.reverting.withMessage(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 shouldFail.reverting(IncreasingPriceCrowdsaleImpl.new( + await shouldFail.reverting.withMessage(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 shouldFail.reverting(IncreasingPriceCrowdsaleImpl.new( + await shouldFail.reverting.withMessage(IncreasingPriceCrowdsaleImpl.new( this.startTime, this.closingTime, wallet, this.token.address, initialRate, 0 - )); + ), 'IncreasingPriceCrowdsale: final rate is 0'); }); context('with crowdsale', function () { @@ -57,7 +57,9 @@ contract('IncreasingPriceCrowdsale', function ([_, investor, wallet, purchaser]) }); it('reverts when the base Crowdsale\'s rate function is called', async function () { - await shouldFail.reverting(this.crowdsale.rate()); + await shouldFail.reverting.withMessage(this.crowdsale.rate(), + 'IncreasingPriceCrowdsale: rate() called' + ); }); it('returns a rate of 0 before the crowdsale starts', async function () { diff --git a/test/crowdsale/IndividuallyCappedCrowdsale.test.js b/test/crowdsale/IndividuallyCappedCrowdsale.test.js index 2465888fa65..a1c4ade2148 100644 --- a/test/crowdsale/IndividuallyCappedCrowdsale.test.js +++ b/test/crowdsale/IndividuallyCappedCrowdsale.test.js @@ -34,7 +34,9 @@ contract('IndividuallyCappedCrowdsale', function ( }); it('reverts when a non-capper sets a cap', async function () { - await shouldFail.reverting(this.crowdsale.setCap(alice, capAlice, { from: other })); + await shouldFail.reverting.withMessage(this.crowdsale.setCap(alice, capAlice, { from: other }), + 'CapperRole: caller does not have the Capper role' + ); }); context('with individual caps', function () { @@ -52,21 +54,31 @@ contract('IndividuallyCappedCrowdsale', function ( it('should reject payments outside cap', async function () { await this.crowdsale.buyTokens(alice, { value: capAlice }); - await shouldFail.reverting(this.crowdsale.buyTokens(alice, { value: 1 })); + await shouldFail.reverting.withMessage(this.crowdsale.buyTokens(alice, { value: 1 }), + 'IndividuallyCappedCrowdsale: beneficiary\'s cap exceeded' + ); }); it('should reject payments that exceed cap', async function () { - await shouldFail.reverting(this.crowdsale.buyTokens(alice, { value: capAlice.addn(1) })); - await shouldFail.reverting(this.crowdsale.buyTokens(bob, { value: capBob.addn(1) })); + await shouldFail.reverting.withMessage(this.crowdsale.buyTokens(alice, { value: capAlice.addn(1) }), + 'IndividuallyCappedCrowdsale: beneficiary\'s cap exceeded' + ); + await shouldFail.reverting.withMessage(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 shouldFail.reverting(this.crowdsale.buyTokens(bob, { value: lessThanCapAlice })); + await shouldFail.reverting.withMessage(this.crowdsale.buyTokens(bob, { value: lessThanCapAlice }), + 'IndividuallyCappedCrowdsale: beneficiary\'s cap exceeded' + ); }); it('should default to a cap of zero', async function () { - await shouldFail.reverting(this.crowdsale.buyTokens(charlie, { value: lessThanCapBoth })); + await shouldFail.reverting.withMessage(this.crowdsale.buyTokens(charlie, { value: lessThanCapBoth }), + 'IndividuallyCappedCrowdsale: beneficiary\'s cap exceeded' + ); }); }); diff --git a/test/crowdsale/PausableCrowdsale.test.js b/test/crowdsale/PausableCrowdsale.test.js index bd16972174d..c5b047bb5f9 100644 --- a/test/crowdsale/PausableCrowdsale.test.js +++ b/test/crowdsale/PausableCrowdsale.test.js @@ -26,8 +26,12 @@ contract('PausableCrowdsale', function ([_, pauser, wallet, other]) { }); it('purchases do not work', async function () { - await shouldFail.reverting(this.crowdsale.sendTransaction({ from: other, value })); - await shouldFail.reverting(this.crowdsale.buyTokens(other, { from: other, value })); + await shouldFail.reverting.withMessage(this.crowdsale.sendTransaction({ from: other, value }), + 'Pausable: paused' + ); + await shouldFail.reverting.withMessage(this.crowdsale.buyTokens(other, { from: other, value }), + 'Pausable: paused' + ); }); context('after unpause', function () { diff --git a/test/crowdsale/PostDeliveryCrowdsale.test.js b/test/crowdsale/PostDeliveryCrowdsale.test.js index 1417a1c76e5..daf40aa2001 100644 --- a/test/crowdsale/PostDeliveryCrowdsale.test.js +++ b/test/crowdsale/PostDeliveryCrowdsale.test.js @@ -41,7 +41,9 @@ contract('PostDeliveryCrowdsale', function ([_, investor, wallet, purchaser]) { }); it('does not allow beneficiaries to withdraw tokens before crowdsale ends', async function () { - await shouldFail.reverting(this.crowdsale.withdrawTokens(investor)); + await shouldFail.reverting.withMessage(this.crowdsale.withdrawTokens(investor), + 'PostDeliveryCrowdsale: not closed' + ); }); context('after closing time', function () { @@ -57,7 +59,9 @@ contract('PostDeliveryCrowdsale', function ([_, investor, wallet, purchaser]) { it('rejects multiple withdrawals', async function () { await this.crowdsale.withdrawTokens(investor); - await shouldFail.reverting(this.crowdsale.withdrawTokens(investor)); + await shouldFail.reverting.withMessage(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 index 3a14f24c1ca..7092dc78f98 100644 --- a/test/crowdsale/RefundableCrowdsale.test.js +++ b/test/crowdsale/RefundableCrowdsale.test.js @@ -24,8 +24,9 @@ contract('RefundableCrowdsale', function ([_, wallet, investor, purchaser, other }); it('rejects a goal of zero', async function () { - await shouldFail.reverting( - RefundableCrowdsaleImpl.new(this.openingTime, this.closingTime, rate, wallet, this.token.address, 0) + await shouldFail.reverting.withMessage( + RefundableCrowdsaleImpl.new(this.openingTime, this.closingTime, rate, wallet, this.token.address, 0), + 'RefundableCrowdsale: goal is 0' ); }); @@ -40,7 +41,9 @@ contract('RefundableCrowdsale', function ([_, wallet, investor, purchaser, other context('before opening time', function () { it('denies refunds', async function () { - await shouldFail.reverting(this.crowdsale.claimRefund(investor)); + await shouldFail.reverting.withMessage(this.crowdsale.claimRefund(investor), + 'RefundableCrowdsale: not finalized' + ); }); }); @@ -50,7 +53,9 @@ contract('RefundableCrowdsale', function ([_, wallet, investor, purchaser, other }); it('denies refunds', async function () { - await shouldFail.reverting(this.crowdsale.claimRefund(investor)); + await shouldFail.reverting.withMessage(this.crowdsale.claimRefund(investor), + 'RefundableCrowdsale: not finalized' + ); }); context('with unreached goal', function () { @@ -84,7 +89,9 @@ contract('RefundableCrowdsale', function ([_, wallet, investor, purchaser, other }); it('denies refunds', async function () { - await shouldFail.reverting(this.crowdsale.claimRefund(investor)); + await shouldFail.reverting.withMessage(this.crowdsale.claimRefund(investor), + 'RefundableCrowdsale: goal reached' + ); }); it('forwards funds to wallet', async function () { diff --git a/test/crowdsale/RefundablePostDeliveryCrowdsale.test.js b/test/crowdsale/RefundablePostDeliveryCrowdsale.test.js index 775bcc0a815..f2740d1fdc8 100644 --- a/test/crowdsale/RefundablePostDeliveryCrowdsale.test.js +++ b/test/crowdsale/RefundablePostDeliveryCrowdsale.test.js @@ -42,7 +42,9 @@ contract('RefundablePostDeliveryCrowdsale', function ([_, investor, wallet, purc }); it('does not allow beneficiaries to withdraw tokens before crowdsale ends', async function () { - await shouldFail.reverting(this.crowdsale.withdrawTokens(investor)); + await shouldFail.reverting.withMessage(this.crowdsale.withdrawTokens(investor), + 'RefundablePostDeliveryCrowdsale: not finalized' + ); }); context('after closing time and finalization', function () { @@ -52,7 +54,9 @@ contract('RefundablePostDeliveryCrowdsale', function ([_, investor, wallet, purc }); it('rejects token withdrawals', async function () { - await shouldFail.reverting(this.crowdsale.withdrawTokens(investor)); + await shouldFail.reverting.withMessage(this.crowdsale.withdrawTokens(investor), + 'RefundablePostDeliveryCrowdsale: goal not reached' + ); }); }); }); @@ -70,7 +74,9 @@ contract('RefundablePostDeliveryCrowdsale', function ([_, investor, wallet, purc }); it('does not allow beneficiaries to withdraw tokens before crowdsale ends', async function () { - await shouldFail.reverting(this.crowdsale.withdrawTokens(investor)); + await shouldFail.reverting.withMessage(this.crowdsale.withdrawTokens(investor), + 'RefundablePostDeliveryCrowdsale: not finalized' + ); }); context('after closing time and finalization', function () { @@ -87,7 +93,9 @@ contract('RefundablePostDeliveryCrowdsale', function ([_, investor, wallet, purc it('rejects multiple withdrawals', async function () { await this.crowdsale.withdrawTokens(investor); - await shouldFail.reverting(this.crowdsale.withdrawTokens(investor)); + await shouldFail.reverting.withMessage(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 index be42ba0ff26..bcc1c729673 100644 --- a/test/crowdsale/TimedCrowdsale.test.js +++ b/test/crowdsale/TimedCrowdsale.test.js @@ -21,21 +21,21 @@ contract('TimedCrowdsale', function ([_, investor, wallet, purchaser]) { }); it('reverts if the opening time is in the past', async function () { - await shouldFail.reverting(TimedCrowdsaleImpl.new( + await shouldFail.reverting.withMessage(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 shouldFail.reverting(TimedCrowdsaleImpl.new( + await shouldFail.reverting.withMessage(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 shouldFail.reverting(TimedCrowdsaleImpl.new( + await shouldFail.reverting.withMessage(TimedCrowdsaleImpl.new( this.openingTime, this.openingTime, rate, wallet, this.token.address - )); + ), 'TimedCrowdsale: opening time is not before closing time'); }); context('with crowdsale', function () { @@ -56,8 +56,10 @@ contract('TimedCrowdsale', function ([_, investor, wallet, purchaser]) { describe('accepting payments', function () { it('should reject payments before start', async function () { (await this.crowdsale.isOpen()).should.equal(false); - await shouldFail.reverting(this.crowdsale.send(value)); - await shouldFail.reverting(this.crowdsale.buyTokens(investor, { from: purchaser, value: value })); + await shouldFail.reverting.withMessage(this.crowdsale.send(value), 'TimedCrowdsale: not open'); + await shouldFail.reverting.withMessage(this.crowdsale.buyTokens(investor, { from: purchaser, value: value }), + 'TimedCrowdsale: not open' + ); }); it('should accept payments after start', async function () { @@ -69,25 +71,31 @@ contract('TimedCrowdsale', function ([_, investor, wallet, purchaser]) { it('should reject payments after end', async function () { await time.increaseTo(this.afterClosingTime); - await shouldFail.reverting(this.crowdsale.send(value)); - await shouldFail.reverting(this.crowdsale.buyTokens(investor, { value: value, from: purchaser })); + await shouldFail.reverting.withMessage(this.crowdsale.send(value), 'TimedCrowdsale: not open'); + await shouldFail.reverting.withMessage(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 shouldFail.reverting(this.crowdsale.extendTime(this.closingTime)); + await shouldFail.reverting.withMessage(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 shouldFail.reverting(this.crowdsale.extendTime(newClosingTime)); + await shouldFail.reverting.withMessage(this.crowdsale.extendTime(newClosingTime), + 'TimedCrowdsale: new closing time is before current closing time' + ); }); context('before crowdsale start', function () { beforeEach(async function () { (await this.crowdsale.isOpen()).should.equal(false); - await shouldFail.reverting(this.crowdsale.send(value)); + await shouldFail.reverting.withMessage(this.crowdsale.send(value), 'TimedCrowdsale: not open'); }); it('it extends end time', async function () { @@ -126,7 +134,9 @@ contract('TimedCrowdsale', function ([_, investor, wallet, purchaser]) { it('it reverts', async function () { const newClosingTime = await time.latest(); - await shouldFail.reverting(this.crowdsale.extendTime(newClosingTime)); + await shouldFail.reverting.withMessage(this.crowdsale.extendTime(newClosingTime), + 'TimedCrowdsale: already closed' + ); }); }); }); diff --git a/test/crowdsale/WhitelistCrowdsale.test.js b/test/crowdsale/WhitelistCrowdsale.test.js index f0d4a42d77d..be7b5249f25 100644 --- a/test/crowdsale/WhitelistCrowdsale.test.js +++ b/test/crowdsale/WhitelistCrowdsale.test.js @@ -20,8 +20,12 @@ contract('WhitelistCrowdsale', function ([_, wallet, whitelister, whitelisted, o } async function purchaseShouldFail (crowdsale, beneficiary, value) { - await shouldFail.reverting(crowdsale.buyTokens(beneficiary, { from: beneficiary, value })); - await shouldFail.reverting(crowdsale.sendTransaction({ from: beneficiary, value })); + await shouldFail.reverting.withMessage(crowdsale.buyTokens(beneficiary, { from: beneficiary, value }), + 'WhitelistCrowdsale: beneficiary doesn\'t have the Whitelisted role' + ); + await shouldFail.reverting.withMessage(crowdsale.sendTransaction({ from: beneficiary, value }), + 'WhitelistCrowdsale: beneficiary doesn\'t have the Whitelisted role' + ); } context('with no whitelisted addresses', function () { diff --git a/test/cryptography/ECDSA.test.js b/test/cryptography/ECDSA.test.js index 046096af43e..e89f2d84776 100644 --- a/test/cryptography/ECDSA.test.js +++ b/test/cryptography/ECDSA.test.js @@ -118,8 +118,9 @@ contract('ECDSA', function ([_, other]) { it.skip('reverts', async function () { // Create the signature const signature = await web3.eth.sign(TEST_MESSAGE, other); - await shouldFail.reverting( - this.ecdsa.recover(TEST_MESSAGE.substring(2), signature) + await shouldFail.reverting.withMessage( + this.ecdsa.recover(TEST_MESSAGE.substring(2), signature), + 'Failure message' ); }); }); diff --git a/test/drafts/Counters.test.js b/test/drafts/Counters.test.js index ad10d51c633..50dbc978ce3 100644 --- a/test/drafts/Counters.test.js +++ b/test/drafts/Counters.test.js @@ -39,7 +39,7 @@ contract('Counters', function () { it('reverts if the current value is 0', async function () { await this.counter.decrement(); - await shouldFail.reverting(this.counter.decrement()); + await shouldFail.reverting.withMessage(this.counter.decrement(), 'SafeMath: subtraction overflow'); }); it('can be called multiple times', async function () { diff --git a/test/drafts/ERC1820Implementer.test.js b/test/drafts/ERC1820Implementer.test.js index 083e8760abc..7f9472ca362 100644 --- a/test/drafts/ERC1820Implementer.test.js +++ b/test/drafts/ERC1820Implementer.test.js @@ -21,10 +21,11 @@ contract('ERC1820Implementer', function ([_, registryFunder, implementee, other] }); it('reverts when attempting to set as implementer in the registry', async function () { - await shouldFail.reverting( + await shouldFail.reverting.withMessage( this.registry.setInterfaceImplementer( implementee, this.interfaceA, this.implementer.address, { from: implementee } - ) + ), + 'Does not implement the interface' ); }); }); diff --git a/test/drafts/ERC20Migrator.test.js b/test/drafts/ERC20Migrator.test.js index 6e8fd451d40..558add2616b 100644 --- a/test/drafts/ERC20Migrator.test.js +++ b/test/drafts/ERC20Migrator.test.js @@ -9,7 +9,9 @@ contract('ERC20Migrator', function ([_, owner, recipient, anotherAccount]) { const totalSupply = new BN('200'); it('reverts with a null legacy token address', async function () { - await shouldFail.reverting(ERC20Migrator.new(ZERO_ADDRESS)); + await shouldFail.reverting.withMessage(ERC20Migrator.new(ZERO_ADDRESS), + 'ERC20Migrator: legacy token is the zero address' + ); }); describe('with tokens and migrator', function () { @@ -25,11 +27,15 @@ contract('ERC20Migrator', function ([_, owner, recipient, anotherAccount]) { describe('beginMigration', function () { it('reverts with a null new token address', async function () { - await shouldFail.reverting(this.migrator.beginMigration(ZERO_ADDRESS)); + await shouldFail.reverting.withMessage(this.migrator.beginMigration(ZERO_ADDRESS), + 'ERC20Migrator: new token is the zero address' + ); }); it('reverts if not a minter of the token', async function () { - await shouldFail.reverting(this.migrator.beginMigration(this.newToken.address)); + await shouldFail.reverting.withMessage(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 () { @@ -40,7 +46,9 @@ contract('ERC20Migrator', function ([_, owner, recipient, anotherAccount]) { 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 shouldFail.reverting(this.migrator.beginMigration(this.newToken.address)); + await shouldFail.reverting.withMessage(this.migrator.beginMigration(this.newToken.address), + 'ERC20Migrator: migration already started' + ); }); }); @@ -58,7 +66,9 @@ contract('ERC20Migrator', function ([_, owner, recipient, anotherAccount]) { }); it('reverts', async function () { - await shouldFail.reverting(this.migrator.migrateAll(owner)); + await shouldFail.reverting.withMessage(this.migrator.migrateAll(owner), + 'ERC20Migrator: migration not started' + ); }); }); }); @@ -72,7 +82,9 @@ contract('ERC20Migrator', function ([_, owner, recipient, anotherAccount]) { }); it('reverts', async function () { - await shouldFail.reverting(this.migrator.migrate(owner, amount)); + await shouldFail.reverting.withMessage(this.migrator.migrate(owner, amount), + 'ERC20Migrator: migration not started' + ); }); }); }); @@ -174,7 +186,9 @@ contract('ERC20Migrator', function ([_, owner, recipient, anotherAccount]) { const amount = baseAmount.addn(1); it('reverts', async function () { - await shouldFail.reverting(this.migrator.migrate(owner, amount)); + await shouldFail.reverting.withMessage(this.migrator.migrate(owner, amount), + 'SafeERC20: low-level call failed' + ); }); }); }); diff --git a/test/drafts/ERC20Snapshot.test.js b/test/drafts/ERC20Snapshot.test.js index 0a3e4de3dff..13d525c59da 100644 --- a/test/drafts/ERC20Snapshot.test.js +++ b/test/drafts/ERC20Snapshot.test.js @@ -24,11 +24,11 @@ contract('ERC20Snapshot', function ([_, initialHolder, recipient, other]) { describe('totalSupplyAt', function () { it('reverts with a snapshot id of 0', async function () { - await shouldFail.reverting(this.token.totalSupplyAt(0)); + await shouldFail.reverting.withMessage(this.token.totalSupplyAt(0), 'ERC20Snapshot: id is 0'); }); it('reverts with a not-yet-created snapshot id', async function () { - await shouldFail.reverting(this.token.totalSupplyAt(1)); + await shouldFail.reverting.withMessage(this.token.totalSupplyAt(1), 'ERC20Snapshot: nonexistent id'); }); context('with initial snapshot', function () { @@ -98,11 +98,11 @@ contract('ERC20Snapshot', function ([_, initialHolder, recipient, other]) { describe('balanceOfAt', function () { it('reverts with a snapshot id of 0', async function () { - await shouldFail.reverting(this.token.balanceOfAt(other, 0)); + await shouldFail.reverting.withMessage(this.token.balanceOfAt(other, 0), 'ERC20Snapshot: id is 0'); }); it('reverts with a not-yet-created snapshot id', async function () { - await shouldFail.reverting(this.token.balanceOfAt(other, 1)); + await shouldFail.reverting.withMessage(this.token.balanceOfAt(other, 1), 'ERC20Snapshot: nonexistent id'); }); context('with initial snapshot', function () { diff --git a/test/drafts/SignatureBouncer.test.js b/test/drafts/SignatureBouncer.test.js index 3d84eeff550..a7af33f72f4 100644 --- a/test/drafts/SignatureBouncer.test.js +++ b/test/drafts/SignatureBouncer.test.js @@ -30,21 +30,23 @@ contract('SignatureBouncer', function ([_, signer, otherSigner, other, authorize }); it('does not allow invalid signature for sender', async function () { - await shouldFail.reverting( - this.sigBouncer.onlyWithValidSignature(INVALID_SIGNATURE, { from: authorizedUser }) + await shouldFail.reverting.withMessage( + this.sigBouncer.onlyWithValidSignature(INVALID_SIGNATURE, { from: authorizedUser }), + 'SignatureBouncer: invalid signature for caller' ); }); it('does not allow valid signature for other sender', async function () { - await shouldFail.reverting( - this.sigBouncer.onlyWithValidSignature(await this.signFor(authorizedUser), { from: other }) + await shouldFail.reverting.withMessage( + this.sigBouncer.onlyWithValidSignature(await this.signFor(authorizedUser), { from: other }), + 'SignatureBouncer: invalid signature for caller' ); }); it('does not allow valid signature for method for sender', async function () { - await shouldFail.reverting( + await shouldFail.reverting.withMessage( this.sigBouncer.onlyWithValidSignature(await this.signFor(authorizedUser, 'onlyWithValidSignature'), - { from: authorizedUser }) + { from: authorizedUser }), 'SignatureBouncer: invalid signature for caller' ); }); }); @@ -57,29 +59,32 @@ contract('SignatureBouncer', function ([_, signer, otherSigner, other, authorize }); it('does not allow invalid signature with correct method for sender', async function () { - await shouldFail.reverting( - this.sigBouncer.onlyWithValidSignatureAndMethod(INVALID_SIGNATURE, { from: authorizedUser }) + await shouldFail.reverting.withMessage( + this.sigBouncer.onlyWithValidSignatureAndMethod(INVALID_SIGNATURE, { from: authorizedUser }), + 'SignatureBouncer: invalid signature for caller and method' ); }); it('does not allow valid signature with correct method for other sender', async function () { - await shouldFail.reverting( + await shouldFail.reverting.withMessage( this.sigBouncer.onlyWithValidSignatureAndMethod( await this.signFor(authorizedUser, 'onlyWithValidSignatureAndMethod'), { from: other } - ) + ), + 'SignatureBouncer: invalid signature for caller and method' ); }); it('does not allow valid method signature with incorrect method for sender', async function () { - await shouldFail.reverting( + await shouldFail.reverting.withMessage( this.sigBouncer.onlyWithValidSignatureAndMethod(await this.signFor(authorizedUser, 'theWrongMethod'), - { from: authorizedUser }) + { from: authorizedUser }), 'SignatureBouncer: invalid signature for caller and method' ); }); it('does not allow valid non-method signature method for sender', async function () { - await shouldFail.reverting( - this.sigBouncer.onlyWithValidSignatureAndMethod(await this.signFor(authorizedUser), { from: authorizedUser }) + await shouldFail.reverting.withMessage( + this.sigBouncer.onlyWithValidSignatureAndMethod(await this.signFor(authorizedUser), { from: authorizedUser }), + 'SignatureBouncer: invalid signature for caller and method' ); }); }); @@ -92,40 +97,41 @@ contract('SignatureBouncer', function ([_, signer, otherSigner, other, authorize }); it('does not allow invalid signature with correct method and data for sender', async function () { - await shouldFail.reverting( - this.sigBouncer.onlyWithValidSignatureAndData(UINT_VALUE, INVALID_SIGNATURE, { from: authorizedUser }) + await shouldFail.reverting.withMessage( + this.sigBouncer.onlyWithValidSignatureAndData(UINT_VALUE, INVALID_SIGNATURE, { from: authorizedUser }), + 'SignatureBouncer: invalid signature for caller and data' ); }); it('does not allow valid signature with correct method and incorrect data for sender', async function () { - await shouldFail.reverting( + await shouldFail.reverting.withMessage( this.sigBouncer.onlyWithValidSignatureAndData(UINT_VALUE + 10, await this.signFor(authorizedUser, 'onlyWithValidSignatureAndData', [UINT_VALUE]), { from: authorizedUser } - ) + ), 'SignatureBouncer: invalid signature for caller and data' ); }); it('does not allow valid signature with correct method and data for other sender', async function () { - await shouldFail.reverting( + await shouldFail.reverting.withMessage( this.sigBouncer.onlyWithValidSignatureAndData(UINT_VALUE, await this.signFor(authorizedUser, 'onlyWithValidSignatureAndData', [UINT_VALUE]), { from: other } - ) + ), 'SignatureBouncer: invalid signature for caller and data' ); }); it('does not allow valid non-method signature for sender', async function () { - await shouldFail.reverting( + await shouldFail.reverting.withMessage( this.sigBouncer.onlyWithValidSignatureAndData(UINT_VALUE, await this.signFor(authorizedUser), { from: authorizedUser } - ) + ), 'SignatureBouncer: invalid signature for caller and data' ); }); it('does not allow msg.data shorter than SIGNATURE_SIZE', async function () { - await shouldFail.reverting( - this.sigBouncer.tooShortMsgData({ from: authorizedUser }) + await shouldFail.reverting.withMessage( + this.sigBouncer.tooShortMsgData({ from: authorizedUser }), 'SignatureBouncer: data is too short' ); }); }); diff --git a/test/drafts/SignedSafeMath.test.js b/test/drafts/SignedSafeMath.test.js index b40adf6e6a6..2f24ce869d5 100644 --- a/test/drafts/SignedSafeMath.test.js +++ b/test/drafts/SignedSafeMath.test.js @@ -13,9 +13,9 @@ contract('SignedSafeMath', function () { (await fn(rhs, lhs)).should.be.bignumber.equal(expected); } - async function testFailsCommutative (fn, lhs, rhs) { - await shouldFail.reverting(fn(lhs, rhs)); - await shouldFail.reverting(fn(rhs, lhs)); + async function testFailsCommutative (fn, lhs, rhs, reason) { + await shouldFail.reverting.withMessage(fn(lhs, rhs), reason); + await shouldFail.reverting.withMessage(fn(rhs, lhs), reason); } describe('add', function () { @@ -37,14 +37,14 @@ contract('SignedSafeMath', function () { const a = MAX_INT256; const b = new BN('1'); - await testFailsCommutative(this.safeMath.add, a, b); + await testFailsCommutative(this.safeMath.add, a, b, 'SignedSafeMath: addition overflow'); }); it('reverts on negative addition overflow', async function () { const a = MIN_INT256; const b = new BN('-1'); - await testFailsCommutative(this.safeMath.add, a, b); + await testFailsCommutative(this.safeMath.add, a, b, 'SignedSafeMath: addition overflow'); }); }); @@ -69,14 +69,14 @@ contract('SignedSafeMath', function () { const a = MAX_INT256; const b = new BN('-1'); - await shouldFail.reverting(this.safeMath.sub(a, b)); + await shouldFail.reverting.withMessage(this.safeMath.sub(a, b), 'SignedSafeMath: subtraction overflow'); }); it('reverts on negative subtraction overflow', async function () { const a = MIN_INT256; const b = new BN('1'); - await shouldFail.reverting(this.safeMath.sub(a, b)); + await shouldFail.reverting.withMessage(this.safeMath.sub(a, b), 'SignedSafeMath: subtraction overflow'); }); }); @@ -99,14 +99,14 @@ contract('SignedSafeMath', function () { const a = MAX_INT256; const b = new BN('2'); - await testFailsCommutative(this.safeMath.mul, a, b); + await testFailsCommutative(this.safeMath.mul, a, b, 'SignedSafeMath: multiplication overflow'); }); it('reverts when minimum integer is multiplied by -1', async function () { const a = MIN_INT256; const b = new BN('-1'); - await testFailsCommutative(this.safeMath.mul, a, b); + await testFailsCommutative(this.safeMath.mul, a, b, 'SignedSafeMath: multiplication overflow'); }); }); @@ -137,14 +137,14 @@ contract('SignedSafeMath', function () { const a = new BN('-5678'); const b = new BN('0'); - await shouldFail.reverting(this.safeMath.div(a, b)); + await shouldFail.reverting.withMessage(this.safeMath.div(a, b), 'SignedSafeMath: division by zero'); }); it('reverts on overflow, negative second', async function () { const a = new BN(MIN_INT256); const b = new BN('-1'); - await shouldFail.reverting(this.safeMath.div(a, b)); + await shouldFail.reverting.withMessage(this.safeMath.div(a, b), 'SignedSafeMath: division overflow'); }); }); }); diff --git a/test/drafts/TokenVesting.test.js b/test/drafts/TokenVesting.test.js index d9474a1878f..6e6ac498c1c 100644 --- a/test/drafts/TokenVesting.test.js +++ b/test/drafts/TokenVesting.test.js @@ -20,21 +20,23 @@ contract('TokenVesting', function ([_, owner, beneficiary]) { cliffDuration.should.be.bignumber.that.is.at.least(duration); - await shouldFail.reverting( - TokenVesting.new(beneficiary, this.start, cliffDuration, duration, true, { from: owner }) + await shouldFail.reverting.withMessage( + TokenVesting.new(beneficiary, this.start, cliffDuration, duration, true, { from: owner }), + 'TokenVesting: cliff is longer than duration' ); }); it('reverts with a null beneficiary', async function () { - await shouldFail.reverting( - TokenVesting.new(ZERO_ADDRESS, this.start, this.cliffDuration, this.duration, true, { from: owner }) + await shouldFail.reverting.withMessage( + TokenVesting.new(ZERO_ADDRESS, this.start, this.cliffDuration, this.duration, true, { from: owner }), + 'TokenVesting: beneficiary is the zero address' ); }); it('reverts with a null duration', async function () { // cliffDuration should also be 0, since the duration must be larger than the cliff - await shouldFail.reverting( - TokenVesting.new(beneficiary, this.start, 0, 0, true, { from: owner }) + await shouldFail.reverting.withMessage( + TokenVesting.new(beneficiary, this.start, 0, 0, true, { from: owner }), 'TokenVesting: duration is 0' ); }); @@ -42,8 +44,9 @@ contract('TokenVesting', function ([_, owner, beneficiary]) { const now = await time.latest(); this.start = now.sub(this.duration).sub(time.duration.minutes(1)); - await shouldFail.reverting( - TokenVesting.new(beneficiary, this.start, this.cliffDuration, this.duration, true, { from: owner }) + await shouldFail.reverting.withMessage( + TokenVesting.new(beneficiary, this.start, this.cliffDuration, this.duration, true, { from: owner }), + 'TokenVesting: final time is before current time' ); }); @@ -65,7 +68,9 @@ contract('TokenVesting', function ([_, owner, beneficiary]) { }); it('cannot be released before cliff', async function () { - await shouldFail.reverting(this.vesting.release(this.token.address)); + await shouldFail.reverting.withMessage(this.vesting.release(this.token.address), + 'TokenVesting: no tokens are due' + ); }); it('can be released after cliff', async function () { @@ -121,7 +126,9 @@ contract('TokenVesting', function ([_, owner, beneficiary]) { beneficiary, this.start, this.cliffDuration, this.duration, false, { from: owner } ); - await shouldFail.reverting(vesting.revoke(this.token.address, { from: owner })); + await shouldFail.reverting.withMessage(vesting.revoke(this.token.address, { from: owner }), + 'TokenVesting: cannot revoke' + ); }); it('should return the non-vested tokens when revoked by owner', async function () { @@ -148,7 +155,9 @@ contract('TokenVesting', function ([_, owner, beneficiary]) { it('should fail to be revoked a second time', async function () { await this.vesting.revoke(this.token.address, { from: owner }); - await shouldFail.reverting(this.vesting.revoke(this.token.address, { from: owner })); + await shouldFail.reverting.withMessage(this.vesting.revoke(this.token.address, { from: owner }), + 'TokenVesting: token already revoked' + ); }); function vestedAmount (total, now, start, cliffDuration, duration) { diff --git a/test/examples/SampleCrowdsale.test.js b/test/examples/SampleCrowdsale.test.js index cd3061f1acc..b44347c8052 100644 --- a/test/examples/SampleCrowdsale.test.js +++ b/test/examples/SampleCrowdsale.test.js @@ -38,8 +38,10 @@ contract('SampleCrowdsale', function ([_, deployer, owner, wallet, investor]) { }); it('should not accept payments before start', async function () { - await shouldFail.reverting(this.crowdsale.send(ether('1'))); - await shouldFail.reverting(this.crowdsale.buyTokens(investor, { from: investor, value: ether('1') })); + await shouldFail.reverting.withMessage(this.crowdsale.send(ether('1')), 'TimedCrowdsale: not open'); + await shouldFail.reverting.withMessage(this.crowdsale.buyTokens(investor, { from: investor, value: ether('1') }), + 'TimedCrowdsale: not open' + ); }); it('should accept payments during the sale', async function () { @@ -55,14 +57,16 @@ contract('SampleCrowdsale', function ([_, deployer, owner, wallet, investor]) { it('should reject payments after end', async function () { await time.increaseTo(this.afterClosingTime); - await shouldFail.reverting(this.crowdsale.send(ether('1'))); - await shouldFail.reverting(this.crowdsale.buyTokens(investor, { value: ether('1'), from: investor })); + await shouldFail.reverting.withMessage(this.crowdsale.send(ether('1')), 'TimedCrowdsale: not open'); + await shouldFail.reverting.withMessage(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 shouldFail.reverting(this.crowdsale.send(1)); + await shouldFail.reverting.withMessage(this.crowdsale.send(1), 'CappedCrowdsale: cap exceeded'); }); it('should allow finalization and transfer funds to wallet if the goal is reached', async function () { @@ -93,9 +97,9 @@ contract('SampleCrowdsale', function ([_, deployer, owner, wallet, investor]) { const HIGH_GOAL = ether('30'); it('creation reverts', async function () { - await shouldFail.reverting(SampleCrowdsale.new( + await shouldFail.reverting.withMessage(SampleCrowdsale.new( this.openingTime, this.closingTime, RATE, wallet, CAP, this.token.address, HIGH_GOAL - )); + ), 'SampleCrowdSale: goal is greater than cap'); }); }); }); diff --git a/test/introspection/ERC165.test.js b/test/introspection/ERC165.test.js index 64ca89eb718..c3f14941a30 100644 --- a/test/introspection/ERC165.test.js +++ b/test/introspection/ERC165.test.js @@ -9,7 +9,7 @@ contract('ERC165', function () { }); it('does not allow 0xffffffff', async function () { - await shouldFail.reverting(this.mock.registerInterface('0xffffffff')); + await shouldFail.reverting.withMessage(this.mock.registerInterface('0xffffffff'), 'ERC165: invalid interface id'); }); shouldSupportInterfaces([ diff --git a/test/lifecycle/Pausable.test.js b/test/lifecycle/Pausable.test.js index d5698943eaf..acd036c2987 100644 --- a/test/lifecycle/Pausable.test.js +++ b/test/lifecycle/Pausable.test.js @@ -30,7 +30,9 @@ contract('Pausable', function ([_, pauser, otherPauser, other, ...otherAccounts] }); it('cannot take drastic measure in non-pause', async function () { - await shouldFail.reverting(this.pausable.drasticMeasure({ from: other })); + await shouldFail.reverting.withMessage(this.pausable.drasticMeasure({ from: other }), + 'Pausable: not paused' + ); (await this.pausable.drasticMeasureTaken()).should.equal(false); }); @@ -41,7 +43,9 @@ contract('Pausable', function ([_, pauser, otherPauser, other, ...otherAccounts] }); it('reverts when pausing from non-pauser', async function () { - await shouldFail.reverting(this.pausable.pause({ from: other })); + await shouldFail.reverting.withMessage(this.pausable.pause({ from: other }), + 'PauserRole: caller does not have the Pauser role' + ); }); context('when paused', function () { @@ -54,7 +58,7 @@ contract('Pausable', function ([_, pauser, otherPauser, other, ...otherAccounts] }); it('cannot perform normal process in pause', async function () { - await shouldFail.reverting(this.pausable.normalProcess({ from: other })); + await shouldFail.reverting.withMessage(this.pausable.normalProcess({ from: other }), 'Pausable: paused'); }); it('can take a drastic measure in a pause', async function () { @@ -63,7 +67,7 @@ contract('Pausable', function ([_, pauser, otherPauser, other, ...otherAccounts] }); it('reverts when re-pausing', async function () { - await shouldFail.reverting(this.pausable.pause({ from: pauser })); + await shouldFail.reverting.withMessage(this.pausable.pause({ from: pauser }), 'Pausable: paused'); }); describe('unpausing', function () { @@ -73,7 +77,9 @@ contract('Pausable', function ([_, pauser, otherPauser, other, ...otherAccounts] }); it('reverts when unpausing from non-pauser', async function () { - await shouldFail.reverting(this.pausable.unpause({ from: other })); + await shouldFail.reverting.withMessage(this.pausable.unpause({ from: other }), + 'PauserRole: caller does not have the Pauser role' + ); }); context('when unpaused', function () { @@ -92,11 +98,13 @@ contract('Pausable', function ([_, pauser, otherPauser, other, ...otherAccounts] }); it('should prevent drastic measure', async function () { - await shouldFail.reverting(this.pausable.drasticMeasure({ from: other })); + await shouldFail.reverting.withMessage(this.pausable.drasticMeasure({ from: other }), + 'Pausable: not paused' + ); }); it('reverts when re-unpausing', async function () { - await shouldFail.reverting(this.pausable.unpause({ from: pauser })); + await shouldFail.reverting.withMessage(this.pausable.unpause({ from: pauser }), 'Pausable: not paused'); }); }); }); diff --git a/test/math/SafeMath.test.js b/test/math/SafeMath.test.js index 78654465a85..3a717a6add3 100644 --- a/test/math/SafeMath.test.js +++ b/test/math/SafeMath.test.js @@ -13,9 +13,9 @@ contract('SafeMath', function () { (await fn(rhs, lhs)).should.be.bignumber.equal(expected); } - async function testFailsCommutative (fn, lhs, rhs) { - await shouldFail.reverting(fn(lhs, rhs)); - await shouldFail.reverting(fn(rhs, lhs)); + async function testFailsCommutative (fn, lhs, rhs, reason) { + await shouldFail.reverting.withMessage(fn(lhs, rhs), reason); + await shouldFail.reverting.withMessage(fn(rhs, lhs), reason); } describe('add', function () { @@ -30,7 +30,7 @@ contract('SafeMath', function () { const a = MAX_UINT256; const b = new BN('1'); - await testFailsCommutative(this.safeMath.add, a, b); + await testFailsCommutative(this.safeMath.add, a, b, 'SafeMath: addition overflow'); }); }); @@ -46,7 +46,7 @@ contract('SafeMath', function () { const a = new BN('1234'); const b = new BN('5678'); - await shouldFail.reverting(this.safeMath.sub(a, b)); + await shouldFail.reverting.withMessage(this.safeMath.sub(a, b), 'SafeMath: subtraction overflow'); }); }); @@ -69,7 +69,7 @@ contract('SafeMath', function () { const a = MAX_UINT256; const b = new BN('2'); - await testFailsCommutative(this.safeMath.mul, a, b); + await testFailsCommutative(this.safeMath.mul, a, b, 'SafeMath: multiplication overflow'); }); }); @@ -99,7 +99,7 @@ contract('SafeMath', function () { const a = new BN('5678'); const b = new BN('0'); - await shouldFail.reverting(this.safeMath.div(a, b)); + await shouldFail.reverting.withMessage(this.safeMath.div(a, b), 'SafeMath: division by zero'); }); }); @@ -138,7 +138,7 @@ contract('SafeMath', function () { const a = new BN('5678'); const b = new BN('0'); - await shouldFail.reverting(this.safeMath.mod(a, b)); + await shouldFail.reverting.withMessage(this.safeMath.mod(a, b), 'SafeMath: modulo by zero'); }); }); }); diff --git a/test/ownership/Ownable.behavior.js b/test/ownership/Ownable.behavior.js index 29a1218c45d..308de2ffead 100644 --- a/test/ownership/Ownable.behavior.js +++ b/test/ownership/Ownable.behavior.js @@ -17,11 +17,17 @@ function shouldBehaveLikeOwnable (owner, [other]) { }); it('should prevent non-owners from transferring', async function () { - await shouldFail.reverting(this.ownable.transferOwnership(other, { from: other })); + await shouldFail.reverting.withMessage( + this.ownable.transferOwnership(other, { from: other }), + 'Ownable: caller is not the owner' + ); }); it('should guard ownership against stuck state', async function () { - await shouldFail.reverting(this.ownable.transferOwnership(ZERO_ADDRESS, { from: owner })); + await shouldFail.reverting.withMessage( + this.ownable.transferOwnership(ZERO_ADDRESS, { from: owner }), + 'Ownable: new owner is the zero address' + ); }); it('loses owner after renouncement', async function () { @@ -32,7 +38,10 @@ function shouldBehaveLikeOwnable (owner, [other]) { }); it('should prevent non-owners from renouncement', async function () { - await shouldFail.reverting(this.ownable.renounceOwnership({ from: other })); + await shouldFail.reverting.withMessage( + this.ownable.renounceOwnership({ from: other }), + 'Ownable: caller is not the owner' + ); }); }); } diff --git a/test/ownership/Secondary.test.js b/test/ownership/Secondary.test.js index 7763e3a8fd5..2039f750e0c 100644 --- a/test/ownership/Secondary.test.js +++ b/test/ownership/Secondary.test.js @@ -18,7 +18,9 @@ contract('Secondary', function ([_, primary, newPrimary, other]) { }); it('reverts when anyone calls onlyPrimary functions', async function () { - await shouldFail.reverting(this.secondary.onlyPrimaryMock({ from: other })); + await shouldFail.reverting.withMessage(this.secondary.onlyPrimaryMock({ from: other }), + 'Secondary: caller is not the primary account' + ); }); }); @@ -30,11 +32,15 @@ contract('Secondary', function ([_, primary, newPrimary, other]) { }); it('reverts when transferring to the null address', async function () { - await shouldFail.reverting(this.secondary.transferPrimary(ZERO_ADDRESS, { from: primary })); + await shouldFail.reverting.withMessage(this.secondary.transferPrimary(ZERO_ADDRESS, { from: primary }), + 'Secondary: new primary is the zero address' + ); }); it('reverts when called by anyone', async function () { - await shouldFail.reverting(this.secondary.transferPrimary(newPrimary, { from: other })); + await shouldFail.reverting.withMessage(this.secondary.transferPrimary(newPrimary, { from: other }), + 'Secondary: caller is not the primary account' + ); }); context('with new primary', function () { @@ -47,7 +53,9 @@ contract('Secondary', function ([_, primary, newPrimary, other]) { }); it('reverts when the old primary account calls onlyPrimary functions', async function () { - await shouldFail.reverting(this.secondary.onlyPrimaryMock({ from: primary })); + await shouldFail.reverting.withMessage(this.secondary.onlyPrimaryMock({ from: primary }), + 'Secondary: caller is not the primary account' + ); }); }); }); diff --git a/test/payment/PaymentSplitter.test.js b/test/payment/PaymentSplitter.test.js index b9f097e7679..15e458f3af5 100644 --- a/test/payment/PaymentSplitter.test.js +++ b/test/payment/PaymentSplitter.test.js @@ -7,27 +7,37 @@ contract('PaymentSplitter', function ([_, owner, payee1, payee2, payee3, nonpaye const amount = ether('1'); it('rejects an empty set of payees', async function () { - await shouldFail.reverting(PaymentSplitter.new([], [])); + await shouldFail.reverting.withMessage(PaymentSplitter.new([], []), 'PaymentSplitter: no payees'); }); it('rejects more payees than shares', async function () { - await shouldFail.reverting(PaymentSplitter.new([payee1, payee2, payee3], [20, 30])); + await shouldFail.reverting.withMessage(PaymentSplitter.new([payee1, payee2, payee3], [20, 30]), + 'PaymentSplitter: payees and shares length mismatch' + ); }); it('rejects more shares than payees', async function () { - await shouldFail.reverting(PaymentSplitter.new([payee1, payee2], [20, 30, 40])); + await shouldFail.reverting.withMessage(PaymentSplitter.new([payee1, payee2], [20, 30, 40]), + 'PaymentSplitter: payees and shares length mismatch' + ); }); it('rejects null payees', async function () { - await shouldFail.reverting(PaymentSplitter.new([payee1, ZERO_ADDRESS], [20, 30])); + await shouldFail.reverting.withMessage(PaymentSplitter.new([payee1, ZERO_ADDRESS], [20, 30]), + 'PaymentSplitter: account is the zero address' + ); }); it('rejects zero-valued shares', async function () { - await shouldFail.reverting(PaymentSplitter.new([payee1, payee2], [20, 0])); + await shouldFail.reverting.withMessage(PaymentSplitter.new([payee1, payee2], [20, 0]), + 'PaymentSplitter: shares are 0' + ); }); it('rejects repeated payees', async function () { - await shouldFail.reverting(PaymentSplitter.new([payee1, payee1], [20, 30])); + await shouldFail.reverting.withMessage(PaymentSplitter.new([payee1, payee1], [20, 30]), + 'PaymentSplitter: account already has shares' + ); }); context('once deployed', function () { @@ -64,12 +74,16 @@ contract('PaymentSplitter', function ([_, owner, payee1, payee2, payee3, nonpaye }); it('should throw if no funds to claim', async function () { - await shouldFail.reverting(this.contract.release(payee1)); + await shouldFail.reverting.withMessage(this.contract.release(payee1), + 'PaymentSplitter: account is not due payment' + ); }); it('should throw if non-payee want to claim', async function () { await send.ether(payer1, this.contract.address, amount); - await shouldFail.reverting(this.contract.release(nonpayee1)); + await shouldFail.reverting.withMessage(this.contract.release(nonpayee1), + 'PaymentSplitter: account has no shares' + ); }); it('should distribute funds to payees', async function () { diff --git a/test/payment/escrow/ConditionalEscrow.test.js b/test/payment/escrow/ConditionalEscrow.test.js index eeb39e5ff95..705833567ba 100644 --- a/test/payment/escrow/ConditionalEscrow.test.js +++ b/test/payment/escrow/ConditionalEscrow.test.js @@ -26,7 +26,9 @@ contract('ConditionalEscrow', function ([_, owner, payee, ...otherAccounts]) { it('reverts on withdrawals', async function () { await this.escrow.deposit(payee, { from: owner, value: amount }); - await shouldFail.reverting(this.escrow.withdraw(payee, { from: owner })); + await shouldFail.reverting.withMessage(this.escrow.withdraw(payee, { from: owner }), + 'ConditionalEscrow: payee is not allowed to withdraw' + ); }); }); }); diff --git a/test/payment/escrow/Escrow.behavior.js b/test/payment/escrow/Escrow.behavior.js index 5789fd1ef32..f6c65fc02df 100644 --- a/test/payment/escrow/Escrow.behavior.js +++ b/test/payment/escrow/Escrow.behavior.js @@ -18,7 +18,9 @@ function shouldBehaveLikeEscrow (primary, [payee1, payee2]) { }); it('only the primary account can deposit', async function () { - await shouldFail.reverting(this.escrow.deposit(payee1, { from: payee2 })); + await shouldFail.reverting.withMessage(this.escrow.deposit(payee1, { from: payee2 }), + 'Secondary: caller is not the primary account' + ); }); it('emits a deposited event', async function () { @@ -68,7 +70,9 @@ function shouldBehaveLikeEscrow (primary, [payee1, payee2]) { }); it('only the primary account can withdraw', async function () { - await shouldFail.reverting(this.escrow.withdraw(payee1, { from: payee1 })); + await shouldFail.reverting.withMessage(this.escrow.withdraw(payee1, { from: payee1 }), + 'Secondary: caller is not the primary account' + ); }); it('emits a withdrawn event', async function () { diff --git a/test/payment/escrow/RefundEscrow.test.js b/test/payment/escrow/RefundEscrow.test.js index 0e9a78f4c98..8559c7997c1 100644 --- a/test/payment/escrow/RefundEscrow.test.js +++ b/test/payment/escrow/RefundEscrow.test.js @@ -8,8 +8,8 @@ contract('RefundEscrow', function ([_, primary, beneficiary, refundee1, refundee const refundees = [refundee1, refundee2]; it('requires a non-null beneficiary', async function () { - await shouldFail.reverting( - RefundEscrow.new(ZERO_ADDRESS, { from: primary }) + await shouldFail.reverting.withMessage( + RefundEscrow.new(ZERO_ADDRESS, { from: primary }), 'RefundEscrow: beneficiary is the zero address' ); }); @@ -32,17 +32,23 @@ contract('RefundEscrow', function ([_, primary, beneficiary, refundee1, refundee it('does not refund refundees', async function () { await this.escrow.deposit(refundee1, { from: primary, value: amount }); - await shouldFail.reverting(this.escrow.withdraw(refundee1)); + await shouldFail.reverting.withMessage(this.escrow.withdraw(refundee1), + 'ConditionalEscrow: payee is not allowed to withdraw' + ); }); it('does not allow beneficiary withdrawal', async function () { await this.escrow.deposit(refundee1, { from: primary, value: amount }); - await shouldFail.reverting(this.escrow.beneficiaryWithdraw()); + await shouldFail.reverting.withMessage(this.escrow.beneficiaryWithdraw(), + 'RefundEscrow: beneficiary can only withdraw while closed' + ); }); }); it('only the primary account can enter closed state', async function () { - await shouldFail.reverting(this.escrow.close({ from: beneficiary })); + await shouldFail.reverting.withMessage(this.escrow.close({ from: beneficiary }), + 'Secondary: caller is not the primary account' + ); const { logs } = await this.escrow.close({ from: primary }); expectEvent.inLogs(logs, 'RefundsClosed'); @@ -56,11 +62,15 @@ contract('RefundEscrow', function ([_, primary, beneficiary, refundee1, refundee }); it('rejects deposits', async function () { - await shouldFail.reverting(this.escrow.deposit(refundee1, { from: primary, value: amount })); + await shouldFail.reverting.withMessage(this.escrow.deposit(refundee1, { from: primary, value: amount }), + 'RefundEscrow: can only deposit while active' + ); }); it('does not refund refundees', async function () { - await shouldFail.reverting(this.escrow.withdraw(refundee1)); + await shouldFail.reverting.withMessage(this.escrow.withdraw(refundee1), + 'ConditionalEscrow: payee is not allowed to withdraw' + ); }); it('allows beneficiary withdrawal', async function () { @@ -70,16 +80,22 @@ contract('RefundEscrow', function ([_, primary, beneficiary, refundee1, refundee }); it('prevents entering the refund state', async function () { - await shouldFail.reverting(this.escrow.enableRefunds({ from: primary })); + await shouldFail.reverting.withMessage(this.escrow.enableRefunds({ from: primary }), + 'RefundEscrow: can only enable refunds while active' + ); }); it('prevents re-entering the closed state', async function () { - await shouldFail.reverting(this.escrow.close({ from: primary })); + await shouldFail.reverting.withMessage(this.escrow.close({ from: primary }), + 'RefundEscrow: can only close while active' + ); }); }); it('only the primary account can enter refund state', async function () { - await shouldFail.reverting(this.escrow.enableRefunds({ from: beneficiary })); + await shouldFail.reverting.withMessage(this.escrow.enableRefunds({ from: beneficiary }), + 'Secondary: caller is not the primary account' + ); const { logs } = await this.escrow.enableRefunds({ from: primary }); expectEvent.inLogs(logs, 'RefundsEnabled'); @@ -93,7 +109,9 @@ contract('RefundEscrow', function ([_, primary, beneficiary, refundee1, refundee }); it('rejects deposits', async function () { - await shouldFail.reverting(this.escrow.deposit(refundee1, { from: primary, value: amount })); + await shouldFail.reverting.withMessage(this.escrow.deposit(refundee1, { from: primary, value: amount }), + 'RefundEscrow: can only deposit while active' + ); }); it('refunds refundees', async function () { @@ -105,15 +123,21 @@ contract('RefundEscrow', function ([_, primary, beneficiary, refundee1, refundee }); it('does not allow beneficiary withdrawal', async function () { - await shouldFail.reverting(this.escrow.beneficiaryWithdraw()); + await shouldFail.reverting.withMessage(this.escrow.beneficiaryWithdraw(), + 'RefundEscrow: beneficiary can only withdraw while closed' + ); }); it('prevents entering the closed state', async function () { - await shouldFail.reverting(this.escrow.close({ from: primary })); + await shouldFail.reverting.withMessage(this.escrow.close({ from: primary }), + 'RefundEscrow: can only close while active' + ); }); it('prevents re-entering the refund state', async function () { - await shouldFail.reverting(this.escrow.enableRefunds({ from: primary })); + await shouldFail.reverting.withMessage(this.escrow.enableRefunds({ from: primary }), + 'RefundEscrow: can only enable refunds while active' + ); }); }); }); diff --git a/test/token/ERC20/ERC20.test.js b/test/token/ERC20/ERC20.test.js index 8511db3a2b3..ba506d51967 100644 --- a/test/token/ERC20/ERC20.test.js +++ b/test/token/ERC20/ERC20.test.js @@ -37,7 +37,9 @@ contract('ERC20', function ([_, initialHolder, recipient, anotherAccount]) { const amount = initialSupply.addn(1); it('reverts', async function () { - await shouldFail.reverting(this.token.transfer(to, amount, { from: initialHolder })); + await shouldFail.reverting.withMessage(this.token.transfer(to, amount, { from: initialHolder }), + 'SafeMath: subtraction overflow' + ); }); }); @@ -68,7 +70,9 @@ contract('ERC20', function ([_, initialHolder, recipient, anotherAccount]) { const to = ZERO_ADDRESS; it('reverts', async function () { - await shouldFail.reverting(this.token.transfer(to, initialSupply, { from: initialHolder })); + await shouldFail.reverting.withMessage(this.token.transfer(to, initialSupply, { from: initialHolder }), + 'ERC20: transfer to the zero address' + ); }); }); }); @@ -126,7 +130,9 @@ contract('ERC20', function ([_, initialHolder, recipient, anotherAccount]) { const amount = initialSupply.addn(1); it('reverts', async function () { - await shouldFail.reverting(this.token.transferFrom(initialHolder, to, amount, { from: spender })); + await shouldFail.reverting.withMessage(this.token.transferFrom( + initialHolder, to, amount, { from: spender }), 'SafeMath: subtraction overflow' + ); }); }); }); @@ -140,7 +146,9 @@ contract('ERC20', function ([_, initialHolder, recipient, anotherAccount]) { const amount = initialSupply; it('reverts', async function () { - await shouldFail.reverting(this.token.transferFrom(initialHolder, to, amount, { from: spender })); + await shouldFail.reverting.withMessage(this.token.transferFrom( + initialHolder, to, amount, { from: spender }), 'SafeMath: subtraction overflow' + ); }); }); @@ -148,7 +156,9 @@ contract('ERC20', function ([_, initialHolder, recipient, anotherAccount]) { const amount = initialSupply.addn(1); it('reverts', async function () { - await shouldFail.reverting(this.token.transferFrom(initialHolder, to, amount, { from: spender })); + await shouldFail.reverting.withMessage(this.token.transferFrom( + initialHolder, to, amount, { from: spender }), 'SafeMath: subtraction overflow' + ); }); }); }); @@ -163,7 +173,9 @@ contract('ERC20', function ([_, initialHolder, recipient, anotherAccount]) { }); it('reverts', async function () { - await shouldFail.reverting(this.token.transferFrom(initialHolder, to, amount, { from: spender })); + await shouldFail.reverting.withMessage(this.token.transferFrom( + initialHolder, to, amount, { from: spender }), 'ERC20: transfer to the zero address' + ); }); }); }); @@ -175,7 +187,9 @@ contract('ERC20', function ([_, initialHolder, recipient, anotherAccount]) { function shouldDecreaseApproval (amount) { describe('when there was no approved amount before', function () { it('reverts', async function () { - await shouldFail.reverting(this.token.decreaseAllowance(spender, amount, { from: initialHolder })); + await shouldFail.reverting.withMessage(this.token.decreaseAllowance( + spender, amount, { from: initialHolder }), 'SafeMath: subtraction overflow' + ); }); }); @@ -208,8 +222,9 @@ contract('ERC20', function ([_, initialHolder, recipient, anotherAccount]) { }); it('reverts when more than the full allowance is removed', async function () { - await shouldFail.reverting( - this.token.decreaseAllowance(spender, approvedAmount.addn(1), { from: initialHolder }) + await shouldFail.reverting.withMessage( + this.token.decreaseAllowance(spender, approvedAmount.addn(1), { from: initialHolder }), + 'SafeMath: subtraction overflow' ); }); }); @@ -233,7 +248,9 @@ contract('ERC20', function ([_, initialHolder, recipient, anotherAccount]) { const spender = ZERO_ADDRESS; it('reverts', async function () { - await shouldFail.reverting(this.token.decreaseAllowance(spender, amount, { from: initialHolder })); + await shouldFail.reverting.withMessage(this.token.decreaseAllowance( + spender, amount, { from: initialHolder }, 'ERC20: approve to the zero address') + ); }); }); }); @@ -315,16 +332,19 @@ contract('ERC20', function ([_, initialHolder, recipient, anotherAccount]) { const spender = ZERO_ADDRESS; it('reverts', async function () { - await shouldFail.reverting(this.token.increaseAllowance(spender, amount, { from: initialHolder })); + await shouldFail.reverting.withMessage( + this.token.increaseAllowance(spender, amount, { from: initialHolder }), 'ERC20: approve to the zero address' + ); }); }); }); describe('_mint', function () { const amount = new BN(50); - - it('rejects a zero account', async function () { - await shouldFail.reverting(this.token.mint(ZERO_ADDRESS, amount)); + it('rejects a null account', async function () { + await shouldFail.reverting.withMessage( + this.token.mint(ZERO_ADDRESS, amount), 'ERC20: mint to the zero address' + ); }); describe('for a non zero account', function () { @@ -354,13 +374,16 @@ contract('ERC20', function ([_, initialHolder, recipient, anotherAccount]) { }); describe('_burn', function () { - it('rejects a zero account', async function () { - await shouldFail.reverting(this.token.burn(ZERO_ADDRESS, new BN(1))); + it('rejects a null account', async function () { + await shouldFail.reverting.withMessage(this.token.burn(ZERO_ADDRESS, new BN(1)), + 'ERC20: burn from the zero address'); }); describe('for a non zero account', function () { it('rejects burning more than balance', async function () { - await shouldFail.reverting(this.token.burn(initialHolder, initialSupply.addn(1))); + await shouldFail.reverting.withMessage(this.token.burn( + initialHolder, initialSupply.addn(1)), 'SafeMath: subtraction overflow' + ); }); const describeBurn = function (description, amount) { @@ -405,17 +428,23 @@ contract('ERC20', function ([_, initialHolder, recipient, anotherAccount]) { await this.token.approve(spender, allowance, { from: initialHolder }); }); - it('rejects a zero account', async function () { - await shouldFail.reverting(this.token.burnFrom(ZERO_ADDRESS, new BN(1))); + it('rejects a null account', async function () { + await shouldFail.reverting.withMessage(this.token.burnFrom(ZERO_ADDRESS, new BN(1)), + 'ERC20: burn from the zero address' + ); }); describe('for a non zero account', function () { it('rejects burning more than allowance', async function () { - await shouldFail.reverting(this.token.burnFrom(initialHolder, allowance.addn(1))); + await shouldFail.reverting.withMessage(this.token.burnFrom(initialHolder, allowance.addn(1)), + 'SafeMath: subtraction overflow' + ); }); it('rejects burning more than balance', async function () { - await shouldFail.reverting(this.token.burnFrom(initialHolder, initialSupply.addn(1))); + await shouldFail.reverting.withMessage(this.token.burnFrom(initialHolder, initialSupply.addn(1)), + 'SafeMath: subtraction overflow' + ); }); const describeBurnFrom = function (description, amount) { @@ -477,7 +506,9 @@ contract('ERC20', function ([_, initialHolder, recipient, anotherAccount]) { describe('when the owner is the zero address', function () { it('reverts', async function () { - await shouldFail.reverting(this.token.approveInternal(ZERO_ADDRESS, recipient, initialSupply)); + await shouldFail.reverting.withMessage(this.token.approveInternal(ZERO_ADDRESS, recipient, initialSupply), + 'ERC20: approve from the zero address' + ); }); }); }); @@ -555,7 +586,9 @@ contract('ERC20', function ([_, initialHolder, recipient, anotherAccount]) { describe('when the spender is the zero address', function () { it('reverts', async function () { - await shouldFail.reverting(approve.call(this, owner, ZERO_ADDRESS, supply)); + await shouldFail.reverting.withMessage(approve.call(this, owner, ZERO_ADDRESS, supply), + 'ERC20: approve to the zero address' + ); }); }); } diff --git a/test/token/ERC20/ERC20Capped.test.js b/test/token/ERC20/ERC20Capped.test.js index 9986be6e4e3..2f4c7c3a1c4 100644 --- a/test/token/ERC20/ERC20Capped.test.js +++ b/test/token/ERC20/ERC20Capped.test.js @@ -8,8 +8,8 @@ contract('ERC20Capped', function ([_, minter, ...otherAccounts]) { const cap = ether('1000'); it('requires a non-zero cap', async function () { - await shouldFail.reverting( - ERC20Capped.new(new BN(0), { from: minter }) + await shouldFail.reverting.withMessage( + ERC20Capped.new(new BN(0), { from: minter }), 'ERC20Capped: cap is 0' ); }); diff --git a/test/token/ERC20/ERC20Pausable.test.js b/test/token/ERC20/ERC20Pausable.test.js index cee627ab301..9b9f2bedb19 100644 --- a/test/token/ERC20/ERC20Pausable.test.js +++ b/test/token/ERC20/ERC20Pausable.test.js @@ -42,7 +42,7 @@ contract('ERC20Pausable', function ([_, pauser, otherPauser, recipient, anotherA }); it('reverts', async function () { - await shouldFail.reverting(this.token.pause({ from })); + await shouldFail.reverting.withMessage(this.token.pause({ from }), 'Pausable: paused'); }); }); }); @@ -51,7 +51,9 @@ contract('ERC20Pausable', function ([_, pauser, otherPauser, recipient, anotherA const from = anotherAccount; it('reverts', async function () { - await shouldFail.reverting(this.token.pause({ from })); + await shouldFail.reverting.withMessage(this.token.pause({ from }), + 'PauserRole: caller does not have the Pauser role' + ); }); }); }); @@ -79,7 +81,7 @@ contract('ERC20Pausable', function ([_, pauser, otherPauser, recipient, anotherA describe('when the token is unpaused', function () { it('reverts', async function () { - await shouldFail.reverting(this.token.unpause({ from })); + await shouldFail.reverting.withMessage(this.token.unpause({ from }), 'Pausable: not paused'); }); }); }); @@ -88,7 +90,9 @@ contract('ERC20Pausable', function ([_, pauser, otherPauser, recipient, anotherA const from = anotherAccount; it('reverts', async function () { - await shouldFail.reverting(this.token.unpause({ from })); + await shouldFail.reverting.withMessage(this.token.unpause({ from }), + 'PauserRole: caller does not have the Pauser role' + ); }); }); }); @@ -134,7 +138,9 @@ contract('ERC20Pausable', function ([_, pauser, otherPauser, recipient, anotherA it('reverts when trying to transfer when paused', async function () { await this.token.pause({ from: pauser }); - await shouldFail.reverting(this.token.transfer(recipient, initialSupply, { from: pauser })); + await shouldFail.reverting.withMessage(this.token.transfer(recipient, initialSupply, { from: pauser }), + 'Pausable: paused' + ); }); }); @@ -159,7 +165,9 @@ contract('ERC20Pausable', function ([_, pauser, otherPauser, recipient, anotherA it('reverts when trying to approve when paused', async function () { await this.token.pause({ from: pauser }); - await shouldFail.reverting(this.token.approve(anotherAccount, allowance, { from: pauser })); + await shouldFail.reverting.withMessage(this.token.approve(anotherAccount, allowance, { from: pauser }), + 'Pausable: paused' + ); }); }); @@ -190,7 +198,9 @@ contract('ERC20Pausable', function ([_, pauser, otherPauser, recipient, anotherA it('reverts when trying to transfer from when paused', async function () { await this.token.pause({ from: pauser }); - await shouldFail.reverting(this.token.transferFrom(pauser, recipient, allowance, { from: anotherAccount })); + await shouldFail.reverting.withMessage(this.token.transferFrom( + pauser, recipient, allowance, { from: anotherAccount }), 'Pausable: paused' + ); }); }); @@ -220,7 +230,9 @@ contract('ERC20Pausable', function ([_, pauser, otherPauser, recipient, anotherA it('reverts when trying to transfer when paused', async function () { await this.token.pause({ from: pauser }); - await shouldFail.reverting(this.token.decreaseAllowance(anotherAccount, decrement, { from: pauser })); + await shouldFail.reverting.withMessage(this.token.decreaseAllowance( + anotherAccount, decrement, { from: pauser }), 'Pausable: paused' + ); }); }); @@ -250,7 +262,9 @@ contract('ERC20Pausable', function ([_, pauser, otherPauser, recipient, anotherA it('reverts when trying to increase approval when paused', async function () { await this.token.pause({ from: pauser }); - await shouldFail.reverting(this.token.increaseAllowance(anotherAccount, increment, { from: pauser })); + await shouldFail.reverting.withMessage(this.token.increaseAllowance( + anotherAccount, increment, { from: pauser }), 'Pausable: paused' + ); }); }); }); diff --git a/test/token/ERC20/SafeERC20.test.js b/test/token/ERC20/SafeERC20.test.js index fee236801bd..3271cae968b 100644 --- a/test/token/ERC20/SafeERC20.test.js +++ b/test/token/ERC20/SafeERC20.test.js @@ -11,7 +11,7 @@ contract('SafeERC20', function ([_, hasNoCode]) { this.wrapper = await SafeERC20Wrapper.new(hasNoCode); }); - shouldRevertOnAllCalls(); + shouldRevertOnAllCalls('SafeERC20: call to non-contract'); }); describe('with token that returns false on all calls', function () { @@ -19,7 +19,7 @@ contract('SafeERC20', function ([_, hasNoCode]) { this.wrapper = await SafeERC20Wrapper.new((await ERC20ReturnFalseMock.new()).address); }); - shouldRevertOnAllCalls(); + shouldRevertOnAllCalls('SafeERC20: ERC20 operation did not succeed'); }); describe('with token that returns true on all calls', function () { @@ -39,24 +39,26 @@ contract('SafeERC20', function ([_, hasNoCode]) { }); }); -function shouldRevertOnAllCalls () { +function shouldRevertOnAllCalls (reason) { it('reverts on transfer', async function () { - await shouldFail.reverting(this.wrapper.transfer()); + await shouldFail.reverting.withMessage(this.wrapper.transfer(), reason); }); it('reverts on transferFrom', async function () { - await shouldFail.reverting(this.wrapper.transferFrom()); + await shouldFail.reverting.withMessage(this.wrapper.transferFrom(), reason); }); it('reverts on approve', async function () { - await shouldFail.reverting(this.wrapper.approve(0)); + await shouldFail.reverting.withMessage(this.wrapper.approve(0), reason); }); it('reverts on increaseAllowance', async function () { + // [TODO] make sure it's reverting for the right reason await shouldFail.reverting(this.wrapper.increaseAllowance(0)); }); it('reverts on decreaseAllowance', async function () { + // [TODO] make sure it's reverting for the right reason await shouldFail.reverting(this.wrapper.decreaseAllowance(0)); }); } @@ -89,7 +91,10 @@ function shouldOnlyRevertOnErrors () { }); it('reverts when decreasing the allowance', async function () { - await shouldFail.reverting(this.wrapper.decreaseAllowance(10)); + await shouldFail.reverting.withMessage( + this.wrapper.decreaseAllowance(10), + 'SafeMath: subtraction overflow' + ); }); }); @@ -99,7 +104,10 @@ function shouldOnlyRevertOnErrors () { }); it('reverts when approving a non-zero allowance', async function () { - await shouldFail.reverting(this.wrapper.approve(20)); + await shouldFail.reverting.withMessage( + this.wrapper.approve(20), + 'SafeERC20: approve from non-zero to non-zero allowance' + ); }); it('doesn\'t revert when approving a zero allowance', async function () { @@ -115,7 +123,10 @@ function shouldOnlyRevertOnErrors () { }); it('reverts when decreasing the allowance to a negative value', async function () { - await shouldFail.reverting(this.wrapper.decreaseAllowance(200)); + await shouldFail.reverting.withMessage( + this.wrapper.decreaseAllowance(200), + 'SafeMath: subtraction overflow' + ); }); }); }); diff --git a/test/token/ERC20/TokenTimelock.test.js b/test/token/ERC20/TokenTimelock.test.js index eee78f78752..e88e2545536 100644 --- a/test/token/ERC20/TokenTimelock.test.js +++ b/test/token/ERC20/TokenTimelock.test.js @@ -13,7 +13,7 @@ contract('TokenTimelock', function ([_, minter, beneficiary]) { it('rejects a release time in the past', async function () { const pastReleaseTime = (await time.latest()).sub(time.duration.years(1)); - await shouldFail.reverting( + await shouldFail.reverting.withMessage( TokenTimelock.new(this.token.address, beneficiary, pastReleaseTime) ); }); @@ -32,12 +32,12 @@ contract('TokenTimelock', function ([_, minter, beneficiary]) { }); it('cannot be released before time limit', async function () { - await shouldFail.reverting(this.timelock.release()); + await shouldFail.reverting.withMessage(this.timelock.release()); }); it('cannot be released just before time limit', async function () { await time.increaseTo(this.releaseTime.sub(time.duration.seconds(3))); - await shouldFail.reverting(this.timelock.release()); + await shouldFail.reverting.withMessage(this.timelock.release()); }); it('can be released just after limit', async function () { @@ -55,7 +55,7 @@ contract('TokenTimelock', function ([_, minter, beneficiary]) { it('cannot be released twice', async function () { await time.increaseTo(this.releaseTime.add(time.duration.years(1))); await this.timelock.release(); - await shouldFail.reverting(this.timelock.release()); + await shouldFail.reverting.withMessage(this.timelock.release()); (await this.token.balanceOf(beneficiary)).should.be.bignumber.equal(amount); }); }); diff --git a/test/token/ERC20/behaviors/ERC20Burnable.behavior.js b/test/token/ERC20/behaviors/ERC20Burnable.behavior.js index 1c60d81edee..45f3f9c1a17 100644 --- a/test/token/ERC20/behaviors/ERC20Burnable.behavior.js +++ b/test/token/ERC20/behaviors/ERC20Burnable.behavior.js @@ -35,7 +35,9 @@ function shouldBehaveLikeERC20Burnable (owner, initialBalance, [burner]) { const amount = initialBalance.addn(1); it('reverts', async function () { - await shouldFail.reverting(this.token.burn(amount, { from: owner })); + await shouldFail.reverting.withMessage(this.token.burn(amount, { from: owner }), + 'SafeMath: subtraction overflow' + ); }); }); }); @@ -82,7 +84,9 @@ function shouldBehaveLikeERC20Burnable (owner, initialBalance, [burner]) { it('reverts', async function () { await this.token.approve(burner, amount, { from: owner }); - await shouldFail.reverting(this.token.burnFrom(owner, amount, { from: burner })); + await shouldFail.reverting.withMessage(this.token.burnFrom(owner, amount, { from: burner }), + 'SafeMath: subtraction overflow' + ); }); }); @@ -91,7 +95,9 @@ function shouldBehaveLikeERC20Burnable (owner, initialBalance, [burner]) { it('reverts', async function () { await this.token.approve(burner, allowance, { from: owner }); - await shouldFail.reverting(this.token.burnFrom(owner, allowance.addn(1), { from: burner })); + await shouldFail.reverting.withMessage(this.token.burnFrom(owner, allowance.addn(1), { from: burner }), + 'SafeMath: subtraction overflow' + ); }); }); }); diff --git a/test/token/ERC20/behaviors/ERC20Capped.behavior.js b/test/token/ERC20/behaviors/ERC20Capped.behavior.js index bf35e27ba9c..e3efff11c64 100644 --- a/test/token/ERC20/behaviors/ERC20Capped.behavior.js +++ b/test/token/ERC20/behaviors/ERC20Capped.behavior.js @@ -15,12 +15,12 @@ function shouldBehaveLikeERC20Capped (minter, [other], cap) { it('should fail to mint if the amount exceeds the cap', async function () { await this.token.mint(other, cap.subn(1), { from }); - await shouldFail.reverting(this.token.mint(other, 2, { from })); + await shouldFail.reverting.withMessage(this.token.mint(other, 2, { from })); }); it('should fail to mint after cap is reached', async function () { await this.token.mint(other, cap, { from }); - await shouldFail.reverting(this.token.mint(other, 1, { from })); + await shouldFail.reverting.withMessage(this.token.mint(other, 1, { from })); }); }); } diff --git a/test/token/ERC20/behaviors/ERC20Mintable.behavior.js b/test/token/ERC20/behaviors/ERC20Mintable.behavior.js index 994e636ff63..2c658868e3d 100644 --- a/test/token/ERC20/behaviors/ERC20Mintable.behavior.js +++ b/test/token/ERC20/behaviors/ERC20Mintable.behavior.js @@ -40,7 +40,9 @@ function shouldBehaveLikeERC20Mintable (minter, [other]) { const from = other; it('reverts', async function () { - await shouldFail.reverting(this.token.mint(other, amount, { from })); + await shouldFail.reverting.withMessage(this.token.mint(other, amount, { from }), + 'MinterRole: caller does not have the Minter role' + ); }); }); }); diff --git a/test/token/ERC721/ERC721.behavior.js b/test/token/ERC721/ERC721.behavior.js index 1cf68c47812..673e52be278 100644 --- a/test/token/ERC721/ERC721.behavior.js +++ b/test/token/ERC721/ERC721.behavior.js @@ -36,7 +36,9 @@ function shouldBehaveLikeERC721 ( context('when querying the zero address', function () { it('throws', async function () { - await shouldFail.reverting(this.token.balanceOf(ZERO_ADDRESS)); + await shouldFail.reverting.withMessage( + this.token.balanceOf(ZERO_ADDRESS), 'ERC721: balance query for the zero address' + ); }); }); }); @@ -54,7 +56,9 @@ function shouldBehaveLikeERC721 ( const tokenId = unknownTokenId; it('reverts', async function () { - await shouldFail.reverting(this.token.ownerOf(tokenId)); + await shouldFail.reverting.withMessage( + this.token.ownerOf(tokenId), 'ERC721: owner query for nonexistent token' + ); }); }); }); @@ -178,29 +182,36 @@ function shouldBehaveLikeERC721 ( context('when the address of the previous owner is incorrect', function () { it('reverts', async function () { - await shouldFail.reverting(transferFunction.call(this, other, other, tokenId, { from: owner }) + await shouldFail.reverting.withMessage( + transferFunction.call(this, other, other, tokenId, { from: owner }), + 'ERC721: transfer of token that is not own' ); }); }); context('when the sender is not authorized for the token id', function () { it('reverts', async function () { - await shouldFail.reverting(transferFunction.call(this, owner, other, tokenId, { from: other }) + await shouldFail.reverting.withMessage( + transferFunction.call(this, owner, other, tokenId, { from: other }), + 'ERC721: transfer caller is not owner nor approved' ); }); }); context('when the given token ID does not exist', function () { it('reverts', async function () { - await shouldFail.reverting(transferFunction.call(this, owner, other, unknownTokenId, { from: owner }) + await shouldFail.reverting.withMessage( + transferFunction.call(this, owner, other, unknownTokenId, { from: owner }), + 'ERC721: operator query for nonexistent token' ); }); }); context('when the address to transfer the token to is the zero address', function () { it('reverts', async function () { - await shouldFail.reverting( - transferFunction.call(this, owner, ZERO_ADDRESS, tokenId, { from: owner }) + await shouldFail.reverting.withMessage( + transferFunction.call(this, owner, ZERO_ADDRESS, tokenId, { from: owner }), + 'ERC721: transfer to the zero address' ); }); }); @@ -258,14 +269,15 @@ function shouldBehaveLikeERC721 ( describe('with an invalid token id', function () { it('reverts', async function () { - await shouldFail.reverting( + await shouldFail.reverting.withMessage( transferFun.call( this, owner, this.receiver.address, unknownTokenId, { from: owner }, - ) + ), + 'ERC721: operator query for nonexistent token' ); }); }); @@ -283,8 +295,9 @@ function shouldBehaveLikeERC721 ( describe('to a receiver contract returning unexpected value', function () { it('reverts', async function () { const invalidReceiver = await ERC721ReceiverMock.new('0x42', false); - await shouldFail.reverting( - this.token.safeTransferFrom(owner, invalidReceiver.address, tokenId, { from: owner }) + await shouldFail.reverting.withMessage( + this.token.safeTransferFrom(owner, invalidReceiver.address, tokenId, { from: owner }), + 'ERC721: transfer to non ERC721Receiver implementer' ); }); }); @@ -292,8 +305,9 @@ function shouldBehaveLikeERC721 ( describe('to a receiver contract that throws', function () { it('reverts', async function () { const invalidReceiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, true); - await shouldFail.reverting( - this.token.safeTransferFrom(owner, invalidReceiver.address, tokenId, { from: owner }) + await shouldFail.reverting.withMessage( + this.token.safeTransferFrom(owner, invalidReceiver.address, tokenId, { from: owner }), + 'ERC721ReceiverMock: reverting' ); }); }); @@ -301,8 +315,9 @@ function shouldBehaveLikeERC721 ( describe('to a contract that does not implement the required function', function () { it('reverts', async function () { const invalidReceiver = this.token; - await shouldFail.reverting( - this.token.safeTransferFrom(owner, invalidReceiver.address, tokenId, { from: owner }) + await shouldFail.reverting.withMessage( + this.token.safeTransferFrom(owner, invalidReceiver.address, tokenId, { from: owner }), + 'VM Exception while processing transaction: revert' ); }); }); @@ -390,22 +405,24 @@ function shouldBehaveLikeERC721 ( context('when the address that receives the approval is the owner', function () { it('reverts', async function () { - await shouldFail.reverting( - this.token.approve(owner, tokenId, { from: owner }) + await shouldFail.reverting.withMessage( + this.token.approve(owner, tokenId, { from: owner }), 'ERC721: transfer to current owner' ); }); }); context('when the sender does not own the given token ID', function () { it('reverts', async function () { - await shouldFail.reverting(this.token.approve(approved, tokenId, { from: other })); + await shouldFail.reverting.withMessage(this.token.approve(approved, tokenId, { from: other }), + 'ERC721: approve caller is not owner nor approved'); }); }); context('when the sender is approved for the given token ID', function () { it('reverts', async function () { await this.token.approve(approved, tokenId, { from: owner }); - await shouldFail.reverting(this.token.approve(anotherApproved, tokenId, { from: approved })); + await shouldFail.reverting.withMessage(this.token.approve(anotherApproved, tokenId, { from: approved }), + 'ERC721: approve caller is not owner nor approved for all'); }); }); @@ -421,7 +438,8 @@ function shouldBehaveLikeERC721 ( context('when the given token ID does not exist', function () { it('reverts', async function () { - await shouldFail.reverting(this.token.approve(approved, unknownTokenId, { from: operator })); + await shouldFail.reverting.withMessage(this.token.approve(approved, unknownTokenId, { from: operator }), + 'ERC721: owner query for nonexistent token'); }); }); }); @@ -499,7 +517,8 @@ function shouldBehaveLikeERC721 ( context('when the operator is the owner', function () { it('reverts', async function () { - await shouldFail.reverting(this.token.setApprovalForAll(owner, true, { from: owner })); + await shouldFail.reverting.withMessage(this.token.setApprovalForAll(owner, true, { from: owner }), + 'ERC721: approve to caller'); }); }); }); diff --git a/test/token/ERC721/ERC721.test.js b/test/token/ERC721/ERC721.test.js index 223f6ab4e86..95cd3f707c3 100644 --- a/test/token/ERC721/ERC721.test.js +++ b/test/token/ERC721/ERC721.test.js @@ -15,8 +15,10 @@ contract('ERC721', function ([_, creator, tokenOwner, other, ...accounts]) { const tokenId = new BN('5042'); describe('_mint(address, uint256)', function () { - it('reverts with a zero destination address', async function () { - await shouldFail.reverting(this.token.mint(ZERO_ADDRESS, tokenId)); + it('reverts with a null destination address', async function () { + await shouldFail.reverting.withMessage( + this.token.mint(ZERO_ADDRESS, tokenId), 'ERC721: mint to the zero address' + ); }); context('with minted token', async function () { @@ -34,14 +36,16 @@ contract('ERC721', function ([_, creator, tokenOwner, other, ...accounts]) { }); it('reverts when adding a token id that already exists', async function () { - await shouldFail.reverting(this.token.mint(tokenOwner, tokenId)); + await shouldFail.reverting.withMessage(this.token.mint(tokenOwner, tokenId), 'ERC721: token already minted'); }); }); }); describe('_burn(address, uint256)', function () { it('reverts when burning a non-existent token id', async function () { - await shouldFail.reverting(this.token.methods['burn(address,uint256)'](tokenOwner, tokenId)); + await shouldFail.reverting.withMessage( + this.token.methods['burn(address,uint256)'](tokenOwner, tokenId), 'ERC721: owner query for nonexistent token' + ); }); context('with minted token', function () { @@ -50,7 +54,9 @@ contract('ERC721', function ([_, creator, tokenOwner, other, ...accounts]) { }); it('reverts when the account is not the owner', async function () { - await shouldFail.reverting(this.token.methods['burn(address,uint256)'](other, tokenId)); + await shouldFail.reverting.withMessage( + this.token.methods['burn(address,uint256)'](other, tokenId), 'ERC721: burn of token that is not own' + ); }); context('with burnt token', function () { @@ -64,11 +70,16 @@ contract('ERC721', function ([_, creator, tokenOwner, other, ...accounts]) { it('deletes the token', async function () { (await this.token.balanceOf(tokenOwner)).should.be.bignumber.equal('0'); - await shouldFail.reverting(this.token.ownerOf(tokenId)); + await shouldFail.reverting.withMessage( + this.token.ownerOf(tokenId), 'ERC721: owner query for nonexistent token' + ); }); it('reverts when burning a token id that has been deleted', async function () { - await shouldFail.reverting(this.token.methods['burn(address,uint256)'](tokenOwner, tokenId)); + await shouldFail.reverting.withMessage( + this.token.methods['burn(address,uint256)'](tokenOwner, tokenId), + 'ERC721: owner query for nonexistent token' + ); }); }); }); @@ -76,7 +87,9 @@ contract('ERC721', function ([_, creator, tokenOwner, other, ...accounts]) { describe('_burn(uint256)', function () { it('reverts when burning a non-existent token id', async function () { - await shouldFail.reverting(this.token.methods['burn(uint256)'](tokenId)); + await shouldFail.reverting.withMessage( + this.token.methods['burn(uint256)'](tokenId), 'ERC721: owner query for nonexistent token' + ); }); context('with minted token', function () { @@ -95,11 +108,15 @@ contract('ERC721', function ([_, creator, tokenOwner, other, ...accounts]) { it('deletes the token', async function () { (await this.token.balanceOf(tokenOwner)).should.be.bignumber.equal('0'); - await shouldFail.reverting(this.token.ownerOf(tokenId)); + await shouldFail.reverting.withMessage( + this.token.ownerOf(tokenId), 'ERC721: owner query for nonexistent token' + ); }); it('reverts when burning a token id that has been deleted', async function () { - await shouldFail.reverting(this.token.methods['burn(uint256)'](tokenId)); + await shouldFail.reverting.withMessage( + this.token.methods['burn(uint256)'](tokenId), 'ERC721: owner query for nonexistent token' + ); }); }); }); diff --git a/test/token/ERC721/ERC721Full.test.js b/test/token/ERC721/ERC721Full.test.js index 975d1c0a56a..cb02c43c318 100644 --- a/test/token/ERC721/ERC721Full.test.js +++ b/test/token/ERC721/ERC721Full.test.js @@ -64,7 +64,9 @@ contract('ERC721Full', function ([ it('burns all tokens', async function () { await this.token.burn(secondTokenId, { from: owner }); (await this.token.totalSupply()).should.be.bignumber.equal('0'); - await shouldFail.reverting(this.token.tokenByIndex(0)); + await shouldFail.reverting.withMessage( + this.token.tokenByIndex(0), 'ERC721Enumerable: global index out of bounds' + ); }); }); @@ -85,7 +87,9 @@ contract('ERC721Full', function ([ }); it('reverts when setting metadata for non existent token id', async function () { - await shouldFail.reverting(this.token.setTokenURI(nonExistentTokenId, sampleUri)); + await shouldFail.reverting.withMessage( + this.token.setTokenURI(nonExistentTokenId, sampleUri), 'ERC721Metadata: URI set of nonexistent token' + ); }); it('can burn token with metadata', async function () { @@ -99,7 +103,9 @@ contract('ERC721Full', function ([ }); it('reverts when querying metadata for non existent token id', async function () { - await shouldFail.reverting(this.token.tokenURI(nonExistentTokenId)); + await shouldFail.reverting.withMessage( + this.token.tokenURI(nonExistentTokenId), 'ERC721Metadata: URI query for nonexistent token' + ); }); }); @@ -127,13 +133,17 @@ contract('ERC721Full', function ([ describe('when the index is greater than or equal to the total tokens owned by the given address', function () { it('reverts', async function () { - await shouldFail.reverting(this.token.tokenOfOwnerByIndex(owner, 2)); + await shouldFail.reverting.withMessage( + this.token.tokenOfOwnerByIndex(owner, 2), 'ERC721Enumerable: owner index out of bounds' + ); }); }); describe('when the given address does not own any token', function () { it('reverts', async function () { - await shouldFail.reverting(this.token.tokenOfOwnerByIndex(another, 0)); + await shouldFail.reverting.withMessage( + this.token.tokenOfOwnerByIndex(another, 0), 'ERC721Enumerable: owner index out of bounds' + ); }); }); @@ -153,7 +163,9 @@ contract('ERC721Full', function ([ it('returns empty collection for original owner', async function () { (await this.token.balanceOf(owner)).should.be.bignumber.equal('0'); - await shouldFail.reverting(this.token.tokenOfOwnerByIndex(owner, 0)); + await shouldFail.reverting.withMessage( + this.token.tokenOfOwnerByIndex(owner, 0), 'ERC721Enumerable: owner index out of bounds' + ); }); }); }); @@ -167,7 +179,9 @@ contract('ERC721Full', function ([ }); it('should revert if index is greater than supply', async function () { - await shouldFail.reverting(this.token.tokenByIndex(2)); + await shouldFail.reverting.withMessage( + this.token.tokenByIndex(2), 'ERC721Enumerable: global index out of bounds' + ); }); [firstTokenId, secondTokenId].forEach(function (tokenId) { diff --git a/test/token/ERC721/ERC721MintBurn.behavior.js b/test/token/ERC721/ERC721MintBurn.behavior.js index d629bed9ce9..814867222dd 100644 --- a/test/token/ERC721/ERC721MintBurn.behavior.js +++ b/test/token/ERC721/ERC721MintBurn.behavior.js @@ -46,13 +46,18 @@ function shouldBehaveLikeMintAndBurnERC721 ( describe('when the given owner address is the zero address', function () { it('reverts', async function () { - await shouldFail.reverting(this.token.mint(ZERO_ADDRESS, thirdTokenId, { from: minter })); + await shouldFail.reverting.withMessage( + 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 shouldFail.reverting(this.token.mint(owner, firstTokenId, { from: minter })); + await shouldFail.reverting.withMessage(this.token.mint(owner, firstTokenId, { from: minter }), + 'ERC721: token already minted.' + ); }); }); }); @@ -76,7 +81,10 @@ function shouldBehaveLikeMintAndBurnERC721 ( }); it('burns the given token ID and adjusts the balance of the owner', async function () { - await shouldFail.reverting(this.token.ownerOf(tokenId)); + await shouldFail.reverting.withMessage( + this.token.ownerOf(tokenId), + 'ERC721: owner query for nonexistent token' + ); (await this.token.balanceOf(owner)).should.be.bignumber.equal('1'); }); @@ -98,15 +106,17 @@ function shouldBehaveLikeMintAndBurnERC721 ( context('getApproved', function () { it('reverts', async function () { - await shouldFail.reverting(this.token.getApproved(tokenId)); + await shouldFail.reverting.withMessage( + 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 shouldFail.reverting( - this.token.burn(unknownTokenId, { from: creator }) + await shouldFail.reverting.withMessage( + this.token.burn(unknownTokenId, { from: creator }), 'ERC721: operator query for nonexistent token' ); }); }); diff --git a/test/token/ERC721/ERC721PausedToken.behavior.js b/test/token/ERC721/ERC721PausedToken.behavior.js index a116c8394ca..94d2e098638 100644 --- a/test/token/ERC721/ERC721PausedToken.behavior.js +++ b/test/token/ERC721/ERC721PausedToken.behavior.js @@ -12,24 +12,34 @@ function shouldBehaveLikeERC721PausedToken (owner, [recipient, operator]) { }); it('reverts when trying to approve', async function () { - await shouldFail.reverting(this.token.approve(recipient, firstTokenId, { from: owner })); + await shouldFail.reverting.withMessage( + this.token.approve(recipient, firstTokenId, { from: owner }), 'Pausable: paused' + ); }); it('reverts when trying to setApprovalForAll', async function () { - await shouldFail.reverting(this.token.setApprovalForAll(operator, true, { from: owner })); + await shouldFail.reverting.withMessage( + this.token.setApprovalForAll(operator, true, { from: owner }), 'Pausable: paused' + ); }); it('reverts when trying to transferFrom', async function () { - await shouldFail.reverting(this.token.transferFrom(owner, recipient, firstTokenId, { from: owner })); + await shouldFail.reverting.withMessage( + this.token.transferFrom(owner, recipient, firstTokenId, { from: owner }), 'Pausable: paused' + ); }); it('reverts when trying to safeTransferFrom', async function () { - await shouldFail.reverting(this.token.safeTransferFrom(owner, recipient, firstTokenId, { from: owner })); + await shouldFail.reverting.withMessage( + this.token.safeTransferFrom(owner, recipient, firstTokenId, { from: owner }), 'Pausable: paused' + ); }); it('reverts when trying to safeTransferFrom with data', async function () { - await shouldFail.reverting(this.token.methods['safeTransferFrom(address,address,uint256,bytes)']( - owner, recipient, firstTokenId, mockData, { from: owner }) + await shouldFail.reverting.withMessage( + this.token.methods['safeTransferFrom(address,address,uint256,bytes)']( + owner, recipient, firstTokenId, mockData, { from: owner } + ), 'Pausable: paused' ); }); diff --git a/test/utils/ReentrancyGuard.test.js b/test/utils/ReentrancyGuard.test.js index 9870665601b..c4a072db85e 100644 --- a/test/utils/ReentrancyGuard.test.js +++ b/test/utils/ReentrancyGuard.test.js @@ -11,7 +11,8 @@ contract('ReentrancyGuard', function () { it('should not allow remote callback', async function () { const attacker = await ReentrancyAttack.new(); - await shouldFail.reverting(this.reentrancyMock.countAndCall(attacker.address)); + await shouldFail.reverting.withMessage( + this.reentrancyMock.countAndCall(attacker.address), 'ReentrancyGuard: reentrant call'); }); // The following are more side-effects than intended behavior: @@ -19,10 +20,14 @@ contract('ReentrancyGuard', function () { // in the side-effects. it('should not allow local recursion', async function () { - await shouldFail.reverting(this.reentrancyMock.countLocalRecursive(10)); + await shouldFail.reverting.withMessage( + this.reentrancyMock.countLocalRecursive(10), 'ReentrancyGuard: reentrant call' + ); }); it('should not allow indirect local recursion', async function () { - await shouldFail.reverting(this.reentrancyMock.countThisRecursive(10)); + await shouldFail.reverting.withMessage( + this.reentrancyMock.countThisRecursive(10), 'ReentrancyMock: failed call' + ); }); });