Commit 2b9dc9ae by Francisco Giordano

Merge tag 'v2.2.0' of github.com:OpenZeppelin/openzeppelin-solidity

v2.2.0
parents f18fd173 9ed1b448
......@@ -16,6 +16,7 @@ Fixes #
(https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/CONTRIBUTING.md),
- added tests where applicable to test new functionality,
- made sure that your contracts are well-documented,
- run the JS/Solidity linters and fixed any issues (`npm run lint:fix`), and
- run the Solidity linter (`npm run lint:sol`) and fixed any issues,
- run the JS linter and fixed any issues (`npm run lint:fix`), and
- updated the changelog, if applicable.
-->
......@@ -32,10 +32,13 @@ npm-debug.log
# truffle build directory
build/
# lol macs
.DS_Store/
# macOS
.DS_Store
# truffle
.node-xmlhttprequest-*
.zos.session
# IntelliJ IDE
.idea
......@@ -25,11 +25,10 @@ jobs:
name: "Unit tests"
script: npm run test
# solidity-coverage fails at parsing 0.5.x code
# - stage: tests
# name: "Unit tests with coverage report"
# script: npm run test
# env: SOLIDITY_COVERAGE=true
- stage: tests
name: "Unit tests with coverage report"
script: npm run test
env: SOLIDITY_COVERAGE=true
- stage: tests
name: "Unit tests using solc nightly"
......
# Changelog
## 2.2.0 (unreleased)
## 2.2.0 (2019-03-14)
## 2.1.2 (2019-17-01)
### New features:
* `ERC20Snapshot`: create snapshots on demand of the token balances and total supply, to later retrieve and e.g. calculate dividends at a past time. ([#1617](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1617))
* `SafeERC20`: `ERC20` contracts with no return value (i.e. that revert on failure) are now supported. ([#1655](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/))
* `ERC20`: added internal `_approve(address owner, address spender, uint256 value)`, allowing derived contracts to set the allowance of arbitrary accounts. ([#1609](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1609))
* `ERC20Metadata`: added internal `_setTokenURI(string memory tokenURI)`. ([#1618](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1618))
* `TimedCrowdsale`: added internal `_extendTime(uint256 newClosingTime)` as well as `TimedCrowdsaleExtended(uint256 prevClosingTime, uint256 newClosingTime)` event allowing to extend the crowdsale, as long as it hasn't already closed.
### Improvements:
* Upgraded the minimum compiler version to v0.5.2: this removes many Solidity warnings that were false positives. ([#1606](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1606))
* `ECDSA`: `recover` no longer accepts malleable signatures (those using upper-range values for `s`, or 0/1 for `v`). ([#1622](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1622))
* `ERC721`'s transfers are now more gas efficient due to removal of unnecessary `SafeMath` calls. ([#1610](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1610))
* `Counter`'s API has been improved, and is now used by `ERC721` (though it is still in `drafts`). ([#1610](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1610))
* Fixed variable shadowing issues. ([#1606](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1606))
### Bugfixes:
* (minor) `SafeERC20`: `safeApprove` wasn't properly checking for a zero allowance when attempting to set a non-zero allowance. ([#1647](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1647))
### Breaking changes:
* `TokenMetadata` (in drafts) has been renamed to `ERC20Metadata`. ([#1618](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1618))
## 2.1.3 (2019-02-26)
* Backported `SafeERC20.safeApprove` bugfix. ([#1647](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1647))
## 2.1.2 (2019-01-17)
* Removed most of the test suite from the npm package, except `PublicRole.behavior.js`, which may be useful to users testing their own `Roles`.
## 2.1.1 (2019-04-01)
## 2.1.1 (2019-01-04)
* Version bump to avoid conflict in the npm registry.
## 2.1.0 (2019-04-01)
## 2.1.0 (2019-01-04)
### New features:
* Now targeting the 0.5.x line of Solidity compilers. For 0.4.24 support, use version 2.0 of OpenZeppelin.
......
......@@ -94,6 +94,24 @@ contract MyNFT is Initializable, ERC721Full, ERC721Mintable {
}
```
> You need an ethereum development framework for the above import statements to work! Check out these guides for [Truffle] or [Embark].
On our site you will find a few [guides] to learn about the different parts of OpenZeppelin, as well as [documentation for the API][API docs]. Keep in mind that the API docs are work in progress, and don’t hesitate to ask questions in [our Slack][Slack].
## Security
OpenZeppelin the project is maintained by [Zeppelin] the company, and developed following our high standards for code quality and security. OpenZeppelin is meant to provide tested and community-audited code, but please use common sense when doing anything that deals with real money! We take no responsibility for your implementation decisions and any security problems you might experience.
The core development principles and strategies that OpenZeppelin is based on include: security in depth, simple and modular code, clarity-driven naming conventions, comprehensive unit testing, pre-and-post-condition sanity checks, code consistency, and regular audits.
The latest audit was done on October 2018 on version 2.0.0.
Please report any security issues you find to security@openzeppelin.org.
## Contribute
OpenZeppelin exists thanks to its contributors. There are many ways you can participate and help build high quality software. Check out the [contribution guide]!
## License
OpenZeppelin is released under the [MIT License](LICENSE).
\ No newline at end of file
OpenZeppelin is released under the [MIT License](LICENSE).
......@@ -51,12 +51,15 @@ git checkout release-vX.Y.Z
git pull upstream
```
Before starting the release process, make one final commit to CHANGELOG.md, including the date of the release.
Change the version string in `package.json`, `package-lock.json` and `ethpm.json` removing the "-rc.R" suffix. Commit these changes and tag the commit as `vX.Y.Z`.
```
git add package.json package-lock.json ethpm.json
git commit -m "Release vX.Y.Z"
git tag -a vX.Y.Z
git push upstream release-vX.Y.Z
git push upstream vX.Y.Z
```
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
/**
* @title Roles
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "../Roles.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "../Roles.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "../Roles.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "../Roles.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "../token/ERC20/IERC20.sol";
......@@ -12,8 +12,8 @@ import "../utils/ReentrancyGuard.sol";
* allowing investors to purchase tokens with ether. This contract implements
* such functionality in its most fundamental form and can be extended to provide additional
* functionality and/or custom behavior.
* The external interface represents the basic interface for purchasing tokens, and conform
* the base architecture for crowdsales. They are *not* intended to be modified / overridden.
* The external interface represents the basic interface for purchasing tokens, and conforms
* the base architecture for crowdsales. It is *not* intended to be modified / overridden.
* The internal interface conforms the extensible and modifiable surface of crowdsales. Override
* the methods to add functionality. Consider using 'super' where appropriate to concatenate
* behavior.
......@@ -66,7 +66,7 @@ contract Crowdsale is Initializable, ReentrancyGuard {
/**
* @dev fallback function ***DO NOT OVERRIDE***
* Note that other contracts will transfer fund with a base gas stipend
* Note that other contracts will transfer funds with a base gas stipend
* of 2300, which is not enough to call buyTokens. Consider calling
* buyTokens directly when purchasing tokens from a contract.
*/
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "../../math/SafeMath.sol";
......@@ -6,7 +6,7 @@ import "../validation/TimedCrowdsale.sol";
/**
* @title FinalizableCrowdsale
* @dev Extension of Crowdsale with a one-off finalization action, where one
* @dev Extension of TimedCrowdsale with a one-off finalization action, where one
* can do extra work after finishing.
*/
contract FinalizableCrowdsale is Initializable, TimedCrowdsale {
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "../validation/TimedCrowdsale.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "../../math/SafeMath.sol";
......@@ -7,8 +7,8 @@ import "../../payment/escrow/RefundEscrow.sol";
/**
* @title RefundableCrowdsale
* @dev Extension of Crowdsale contract that adds a funding goal, and the possibility of users getting a refund if goal
* is not met.
* @dev Extension of FinalizableCrowdsale contract that adds a funding goal, and the possibility of users
* getting a refund if goal is not met.
*
* Deprecated, use RefundablePostDeliveryCrowdsale instead. Note that if you allow tokens to be traded before the goal
* is met, then an attack is possible in which the attacker purchases tokens from the crowdsale and when they sees that
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "../Crowdsale.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "../Crowdsale.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "../validation/TimedCrowdsale.sol";
......@@ -31,7 +31,7 @@ contract IncreasingPriceCrowdsale is Initializable, TimedCrowdsale {
}
/**
* The base rate function is overridden to revert, since this crowdsale doens't use it, and
* The base rate function is overridden to revert, since this crowdsale doesn't use it, and
* all calls to it are a mistake.
*/
function rate() public view returns (uint256) {
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "../../math/SafeMath.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "../../math/SafeMath.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "../../math/SafeMath.sol";
......@@ -15,6 +15,13 @@ contract TimedCrowdsale is Initializable, Crowdsale {
uint256 private _closingTime;
/**
* Event for crowdsale extending
* @param newClosingTime new closing time
* @param prevClosingTime old closing time
*/
event TimedCrowdsaleExtended(uint256 prevClosingTime, uint256 newClosingTime);
/**
* @dev Reverts if not in crowdsale time range.
*/
modifier onlyWhileOpen {
......@@ -82,5 +89,17 @@ contract TimedCrowdsale is Initializable, Crowdsale {
super._preValidatePurchase(beneficiary, weiAmount);
}
/**
* @dev Extend crowdsale
* @param newClosingTime Crowdsale closing time
*/
function _extendTime(uint256 newClosingTime) internal {
require(!hasClosed());
require(newClosingTime > _closingTime);
emit TimedCrowdsaleExtended(_closingTime, newClosingTime);
_closingTime = newClosingTime;
}
uint256[50] private ______gap;
}
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../Crowdsale.sol";
import "../../access/roles/WhitelistedRole.sol";
......@@ -15,11 +15,11 @@ contract WhitelistCrowdsale is Initializable, WhitelistedRole, Crowdsale {
}
/**
* @dev Extend parent behavior requiring beneficiary to be whitelisted. Note that no
* restriction is imposed on the account sending the transaction.
* @param _beneficiary Token beneficiary
* @param _weiAmount Amount of wei contributed
*/
* @dev Extend parent behavior requiring beneficiary to be whitelisted. Note that no
* restriction is imposed on the account sending the transaction.
* @param _beneficiary Token beneficiary
* @param _weiAmount Amount of wei contributed
*/
function _preValidatePurchase(address _beneficiary, uint256 _weiAmount) internal view {
require(isWhitelisted(_beneficiary));
super._preValidatePurchase(_beneficiary, _weiAmount);
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
/**
* @title Elliptic curve signature operations
......@@ -14,16 +14,16 @@ library ECDSA {
* @param signature bytes signature, the signature is generated using web3.eth.sign()
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
bytes32 r;
bytes32 s;
uint8 v;
// Check the signature length
if (signature.length != 65) {
return (address(0));
}
// Divide the signature in r, s and v variables
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
// solhint-disable-next-line no-inline-assembly
......@@ -33,17 +33,25 @@ library ECDSA {
v := byte(0, mload(add(signature, 0x60)))
}
// Version of signature should be 27 or 28, but 0 and 1 are also possible versions
if (v < 27) {
v += 27;
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return address(0);
}
// If the version is correct return the signer address
if (v != 27 && v != 28) {
return (address(0));
} else {
return ecrecover(hash, v, r, s);
return address(0);
}
// If the signature is valid (and not malleable), return the signer address
return ecrecover(hash, v, r, s);
}
/**
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
/**
* @title MerkleProof
......
pragma solidity ^0.5.0;
/**
* @title Counter
* @author Matt Condon (@shrugs)
* @dev Provides an incrementing uint256 id acquired by the `Counter#next` getter.
* Use this for issuing ERC721 ids or keeping track of request ids, anything you want, really.
*
* Include with `using Counter for Counter.Counter;`
* @notice Does not allow an Id of 0, which is popularly used to signify a null state in solidity.
* Does not protect from overflows, but if you have 2^256 ids, you have other problems.
* (But actually, it's generally impossible to increment a counter this many times, energy wise
* so it's not something you have to worry about.)
*/
library Counter {
struct Counter {
uint256 current; // default: 0
}
function next(Counter storage index) internal returns (uint256) {
index.current += 1;
return index.current;
}
}
pragma solidity ^0.5.2;
import "../math/SafeMath.sol";
/**
* @title Counters
* @author Matt Condon (@shrugs)
* @dev Provides counters that can only be incremented or decremented by one. This can be used e.g. to track the number
* of elements in a mapping, issuing ERC721 ids, or counting request ids
*
* Include with `using Counters for Counters.Counter;`
* Since it is not possible to overflow a 256 bit integer with increments of one, `increment` can skip the SafeMath
* overflow check, thereby saving gas. This does assume however correct usage, in that the underlying `_value` is never
* directly accessed.
*/
library Counters {
using SafeMath for uint256;
struct Counter {
// This variable should never be directly accessed by users of the library: interactions must be restricted to
// the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
// this feature: see https://github.com/ethereum/solidity/issues/4637
uint256 _value; // default: 0
}
function current(Counter storage counter) internal view returns (uint256) {
return counter._value;
}
function increment(Counter storage counter) internal {
counter._value += 1;
}
function decrement(Counter storage counter) internal {
counter._value = counter._value.sub(1);
}
}
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "../../token/ERC20/IERC20.sol";
......@@ -8,22 +8,20 @@ import "../../token/ERC20/IERC20.sol";
* @dev See https://eips.ethereum.org/EIPS/eip-1046
* @dev tokenURI must respond with a URI that implements https://eips.ethereum.org/EIPS/eip-1047
*/
contract ERC20TokenMetadata is Initializable, IERC20 {
function tokenURI() external view returns (string memory);
uint256[50] private ______gap;
}
contract ERC20WithMetadata is Initializable, ERC20TokenMetadata {
contract ERC20Metadata is Initializable {
string private _tokenURI;
function initialize(string memory tokenURI) public {
_tokenURI = tokenURI;
function initialize(string memory tokenURI_) public {
_setTokenURI(tokenURI_);
}
function tokenURI() external view returns (string memory) {
return _tokenURI;
}
function _setTokenURI(string memory tokenURI_) internal {
_tokenURI = tokenURI_;
}
uint256[50] private ______gap;
}
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "../token/ERC20/IERC20.sol";
......@@ -18,7 +18,7 @@ import "../math/Math.sol";
* OpenZeppelin's ERC20Mintable, but the only functions that are needed are
* `isMinter(address)` and `mint(address, amount)`. The migrator will check
* that it is a minter for the token.
* The balance from the legacy token will be transfered to the migrator, as it
* The balance from the legacy token will be transferred to the migrator, as it
* is migrated, and remain there forever.
* Although this contract can be used in many different scenarios, the main
* motivation was to provide a way to migrate ERC20 tokens into an upgradeable
......@@ -66,14 +66,14 @@ contract ERC20Migrator is Initializable {
/**
* @dev Begins the migration by setting which is the new token that will be
* minted. This contract must be a minter for the new token.
* @param newToken the token that will be minted
* @param newToken_ the token that will be minted
*/
function beginMigration(ERC20Mintable newToken) public {
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));
require(newToken_.isMinter(address(this)));
_newToken = newToken;
_newToken = newToken_;
}
/**
......@@ -83,6 +83,7 @@ contract ERC20Migrator is Initializable {
* @param amount amount of tokens to be migrated
*/
function migrate(address account, uint256 amount) public {
require(address(_newToken) != address(0));
_legacyToken.safeTransferFrom(account, address(this), amount);
_newToken.mint(account, amount);
}
......
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "../math/SafeMath.sol";
import "../utils/Arrays.sol";
import "../drafts/Counters.sol";
import "../token/ERC20/ERC20.sol";
/**
* @title ERC20 token with snapshots.
* @dev Inspired by Jordi Baylina's MiniMeToken to record historical balances:
* https://github.com/Giveth/minime/blob/ea04d950eea153a04c51fa510b068b9dded390cb/contracts/MiniMeToken.sol
* When a snapshot is made, the balances and totalSupply at the time of the snapshot are recorded for later
* access.
*
* To make a snapshot, call the `snapshot` function, which will emit the `Snapshot` event and return a snapshot id.
* To get the total supply from a snapshot, call the function `totalSupplyAt` with the snapshot id.
* To get the balance of an account from a snapshot, call the `balanceOfAt` function with the snapshot id and the
* account address.
* @author Validity Labs AG <info@validitylabs.org>
*/
contract ERC20Snapshot is Initializable, ERC20 {
using SafeMath for uint256;
using Arrays for uint256[];
using Counters for Counters.Counter;
// Snapshotted values have arrays of ids and the value corresponding to that id. These could be an array of a
// Snapshot struct, but that would impede usage of functions that work on an array.
struct Snapshots {
uint256[] ids;
uint256[] values;
}
mapping (address => Snapshots) private _accountBalanceSnapshots;
Snapshots private _totalSupplySnaphots;
// Snapshot ids increase monotonically, with the first value being 1. An id of 0 is invalid.
Counters.Counter private _currentSnapshotId;
event Snapshot(uint256 id);
// Creates a new snapshot id. Balances are only stored in snapshots on demand: unless a snapshot was taken, a
// balance change will not be recorded. This means the extra added cost of storing snapshotted balances is only paid
// when required, but is also flexible enough that it allows for e.g. daily snapshots.
function snapshot() public returns (uint256) {
_currentSnapshotId.increment();
uint256 currentId = _currentSnapshotId.current();
emit Snapshot(currentId);
return currentId;
}
function balanceOfAt(address account, uint256 snapshotId) public view returns (uint256) {
(bool snapshotted, uint256 value) = _valueAt(snapshotId, _accountBalanceSnapshots[account]);
return snapshotted ? value : balanceOf(account);
}
function totalSupplyAt(uint256 snapshotId) public view returns(uint256) {
(bool snapshotted, uint256 value) = _valueAt(snapshotId, _totalSupplySnaphots);
return snapshotted ? value : totalSupply();
}
// _transfer, _mint and _burn are the only functions where the balances are modified, so it is there that the
// snapshots are updated. Note that the update happens _before_ the balance change, with the pre-modified value.
// The same is true for the total supply and _mint and _burn.
function _transfer(address from, address to, uint256 value) internal {
_updateAccountSnapshot(from);
_updateAccountSnapshot(to);
super._transfer(from, to, value);
}
function _mint(address account, uint256 value) internal {
_updateAccountSnapshot(account);
_updateTotalSupplySnapshot();
super._mint(account, value);
}
function _burn(address account, uint256 value) internal {
_updateAccountSnapshot(account);
_updateTotalSupplySnapshot();
super._burn(account, value);
}
// When a valid snapshot is queried, there are three possibilities:
// a) The queried value was not modified after the snapshot was taken. Therefore, a snapshot entry was never
// created for this id, and all stored snapshot ids are smaller than the requested one. The value that corresponds
// to this id is the current one.
// b) The queried value was modified after the snapshot was taken. Therefore, there will be an entry with the
// requested id, and its value is the one to return.
// c) More snapshots were created after the requested one, and the queried value was later modified. There will be
// no entry for the requested id: the value that corresponds to it is that of the smallest snapshot id that is
// larger than the requested one.
//
// In summary, we need to find an element in an array, returning the index of the smallest value that is larger if
// it is not found, unless said value doesn't exist (e.g. when all values are smaller). Arrays.findUpperBound does
// exactly this.
function _valueAt(uint256 snapshotId, Snapshots storage snapshots)
private view returns (bool, uint256)
{
require(snapshotId > 0);
require(snapshotId <= _currentSnapshotId.current());
uint256 index = snapshots.ids.findUpperBound(snapshotId);
if (index == snapshots.ids.length) {
return (false, 0);
} else {
return (true, snapshots.values[index]);
}
}
function _updateAccountSnapshot(address account) private {
_updateSnapshot(_accountBalanceSnapshots[account], balanceOf(account));
}
function _updateTotalSupplySnapshot() private {
_updateSnapshot(_totalSupplySnaphots, totalSupply());
}
function _updateSnapshot(Snapshots storage snapshots, uint256 currentValue) private {
uint256 currentId = _currentSnapshotId.current();
if (_lastSnapshotId(snapshots.ids) < currentId) {
snapshots.ids.push(currentId);
snapshots.values.push(currentValue);
}
}
function _lastSnapshotId(uint256[] storage ids) private view returns (uint256) {
if (ids.length == 0) {
return 0;
} else {
return ids[ids.length - 1];
}
}
}
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "../access/roles/SignerRole.sol";
......@@ -30,7 +30,7 @@ import "../cryptography/ECDSA.sol";
* @notice A method that uses the `onlyValidSignatureAndData` modifier must make
* the _signature parameter the "last" parameter. You cannot sign a message that
* has its own signature in it so the last 128 bytes of msg.data (which
* represents the length of the _signature data and the _signaature data itself)
* represents the length of the _signature data and the _signature data itself)
* is ignored when validating. Also non fixed sized parameters make constructing
* the data in the signature much more complex.
* See https://ethereum.stackexchange.com/a/50616 for more details.
......@@ -57,7 +57,7 @@ contract SignatureBouncer is Initializable, SignerRole {
}
/**
* @dev requires that a valid signature with a specifed method of a signer was provided
* @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));
......@@ -65,7 +65,7 @@ contract SignatureBouncer is Initializable, SignerRole {
}
/**
* @dev requires that a valid signature with a specifed method and params of a signer was provided
* @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));
......@@ -73,7 +73,7 @@ contract SignatureBouncer is Initializable, SignerRole {
}
/**
* @dev is the signature of `this + sender` from a signer?
* @dev is the signature of `this + account` from a signer?
* @return bool
*/
function _isValidSignature(address account, bytes memory signature) internal view returns (bool) {
......@@ -81,7 +81,7 @@ contract SignatureBouncer is Initializable, SignerRole {
}
/**
* @dev is the signature of `this + sender + methodId` from a signer?
* @dev is the signature of `this + account + methodId` from a signer?
* @return bool
*/
function _isValidSignatureAndMethod(address account, bytes memory signature) internal view returns (bool) {
......@@ -93,10 +93,10 @@ contract SignatureBouncer is Initializable, SignerRole {
}
/**
* @dev is the signature of `this + sender + methodId + params(s)` from a signer?
* @notice the signature parameter of the method being validated must be the "last" parameter
* @return bool
*/
* @dev is the signature of `this + account + methodId + params(s)` from a signer?
* @notice the signature parameter of the method being validated must be the "last" parameter
* @return bool
*/
function _isValidSignatureAndData(address account, bytes memory signature) internal view returns (bool) {
require(msg.data.length > _SIGNATURE_SIZE);
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
/**
* @title SignedSafeMath
......@@ -8,8 +8,8 @@ library SignedSafeMath {
int256 constant private INT256_MIN = -2**255;
/**
* @dev Multiplies two signed integers, reverts on overflow.
*/
* @dev Multiplies two signed integers, reverts on overflow.
*/
function mul(int256 a, int256 b) internal pure returns (int256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
......@@ -27,8 +27,8 @@ library SignedSafeMath {
}
/**
* @dev Integer division of two signed integers truncating the quotient, reverts on division by zero.
*/
* @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
......@@ -39,8 +39,8 @@ library SignedSafeMath {
}
/**
* @dev Subtracts two signed integers, reverts on overflow.
*/
* @dev Subtracts two signed integers, reverts on overflow.
*/
function sub(int256 a, int256 b) internal pure returns (int256) {
int256 c = a - b;
require((b >= 0 && c <= a) || (b < 0 && c > a));
......@@ -49,8 +49,8 @@ library SignedSafeMath {
}
/**
* @dev Adds two signed integers, reverts on overflow.
*/
* @dev Adds two signed integers, reverts on overflow.
*/
function add(int256 a, int256 b) internal pure returns (int256) {
int256 c = a + b;
require((b >= 0 && c >= a) || (b < 0 && c < a));
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "../token/ERC20/SafeERC20.sol";
......@@ -14,8 +14,8 @@ import "../math/SafeMath.sol";
contract TokenVesting is Initializable, Ownable {
// The vesting schedule is time-based (i.e. using block timestamps as opposed to e.g. block numbers), and is
// therefore sensitive to timestamp manipulation (which is something miners can do, to a certain degree). Therefore,
// it is recommended to avoid using short time durations (less than a minute). Typical vesting schemes, with a cliff
// period of a year and a duration of four years, are safe to use.
// it is recommended to avoid using short time durations (less than a minute). Typical vesting schemes, with a
// cliff period of a year and a duration of four years, are safe to use.
// solhint-disable not-rely-on-time
using SafeMath for uint256;
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "../crowdsale/validation/CappedCrowdsale.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "../token/ERC20/ERC20.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "./IERC165.sol";
......@@ -10,7 +10,7 @@ import "./IERC165.sol";
*/
contract ERC165 is Initializable, IERC165 {
bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
/**
/*
* 0x01ffc9a7 ===
* bytes4(keccak256('supportsInterface(bytes4)'))
*/
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
/**
* @title ERC165Checker
* @dev Use `using ERC165Checker for address`; to include this library
* https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md
* https://eips.ethereum.org/EIPS/eip-165
*/
library ERC165Checker {
// As per the EIP-165 spec, no interface should ever match 0xffffffff
bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;
bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
/**
/*
* 0x01ffc9a7 ===
* bytes4(keccak256('supportsInterface(bytes4)'))
*/
......@@ -109,15 +109,15 @@ library ERC165Checker {
mstore(output, 0x0)
success := staticcall(
30000, // 30k gas
account, // To addr
30000, // 30k gas
account, // To addr
encodedParams_data,
encodedParams_size,
output,
0x20 // Outputs are 32 bytes long
0x20 // Outputs are 32 bytes long
)
result := mload(output) // Load the result
result := mload(output) // Load the result
}
}
}
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
/**
* @title IERC165
* @dev https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md
* @dev https://eips.ethereum.org/EIPS/eip-165
*/
interface IERC165 {
/**
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "../access/roles/PauserRole.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
/**
* @title Math
......@@ -6,24 +6,24 @@ pragma solidity ^0.5.0;
*/
library Math {
/**
* @dev Returns the largest of two numbers.
*/
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Calculates the average of two numbers. Since these are integers,
* averages of an even and odd number cannot be represented, and will be
* rounded down.
*/
* @dev Calculates the average of two numbers. Since these are integers,
* averages of an even and odd number cannot be represented, and will be
* rounded down.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow, so we distribute
return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
/**
* @title SafeMath
......@@ -6,8 +6,8 @@ pragma solidity ^0.5.0;
*/
library SafeMath {
/**
* @dev Multiplies two unsigned integers, reverts on overflow.
*/
* @dev Multiplies two unsigned integers, reverts on overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
......@@ -23,8 +23,8 @@ library SafeMath {
}
/**
* @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
*/
* @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// Solidity only automatically asserts when dividing by 0
require(b > 0);
......@@ -35,8 +35,8 @@ library SafeMath {
}
/**
* @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
*/
* @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);
uint256 c = a - b;
......@@ -45,8 +45,8 @@ library SafeMath {
}
/**
* @dev Adds two unsigned integers, reverts on overflow.
*/
* @dev Adds two unsigned integers, reverts on overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a);
......@@ -55,9 +55,9 @@ library SafeMath {
}
/**
* @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
* reverts when dividing by zero.
*/
* @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
* reverts when dividing by zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0);
return a % b;
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
contract Acknowledger {
event AcknowledgeFoo(uint256 a);
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../utils/Address.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../token/ERC20/IERC20.sol";
import "../crowdsale/emission/AllowanceCrowdsale.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../utils/Arrays.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../token/ERC20/IERC20.sol";
import "../crowdsale/validation/CappedCrowdsale.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../access/roles/CapperRole.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../payment/escrow/ConditionalEscrow.sol";
......
pragma solidity ^0.5.0;
import "../drafts/Counter.sol";
contract CounterImpl {
using Counter for Counter.Counter;
uint256 public theId;
// use whatever key you want to track your counters
mapping(string => Counter.Counter) private _counters;
function doThing(string memory key) public returns (uint256) {
theId = _counters[key].next();
return theId;
}
}
pragma solidity ^0.5.2;
import "../drafts/Counters.sol";
contract CountersImpl {
using Counters for Counters.Counter;
Counters.Counter private _counter;
function current() public view returns (uint256) {
return _counter.current();
}
function increment() public {
_counter.increment();
}
function decrement() public {
_counter.decrement();
}
}
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../crowdsale/Crowdsale.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../cryptography/ECDSA.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../../introspection/IERC165.sol";
/**
* https://github.com/ethereum/EIPs/blob/master/EIPS/eip-214.md#specification
* https://eips.ethereum.org/EIPS/eip-214#specification
* From the specification:
* > Any attempts to make state-changing operations inside an execution instance with STATIC set to true will instead
* throw an exception.
* > These operations include [...], LOG0, LOG1, LOG2, [...]
......@@ -13,7 +14,7 @@ import "../../introspection/IERC165.sol";
*/
contract SupportsInterfaceWithLookupMock is IERC165 {
bytes4 public constant INTERFACE_ID_ERC165 = 0x01ffc9a7;
/**
/*
* 0x01ffc9a7 ===
* bytes4(keccak256('supportsInterface(bytes4)'))
*/
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
contract ERC165NotSupported {
// solhint-disable-previous-line no-empty-blocks
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../introspection/ERC165Checker.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../introspection/ERC165.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../token/ERC20/ERC20Burnable.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../token/ERC20/ERC20.sol";
import "../token/ERC20/ERC20Detailed.sol";
......
pragma solidity ^0.5.0;
import "../token/ERC20/ERC20.sol";
import "../drafts/ERC1046/TokenMetadata.sol";
import "../drafts/ERC1046/ERC20Metadata.sol";
contract ERC20WithMetadataMock is ERC20, ERC20WithMetadata {
contract ERC20MetadataMock is ERC20, ERC20Metadata {
constructor (string memory tokenURI) public {
ERC20WithMetadata.initialize(tokenURI);
ERC20Metadata.initialize(tokenURI);
}
function setTokenURI(string memory tokenURI) public {
_setTokenURI(tokenURI);
}
}
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../token/ERC20/ERC20Mintable.sol";
import "./MinterRoleMock.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../token/ERC20/ERC20.sol";
......@@ -19,4 +19,8 @@ contract ERC20Mock is ERC20 {
function burnFrom(address account, uint256 amount) public {
_burnFrom(account, amount);
}
function approveInternal(address owner, address spender, uint256 value) public {
_approve(owner, spender, value);
}
}
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../token/ERC20/ERC20Pausable.sol";
import "./PauserRoleMock.sol";
......
pragma solidity ^0.5.2;
import "../drafts/ERC20Snapshot.sol";
contract ERC20SnapshotMock is ERC20Snapshot {
constructor(address initialAccount, uint256 initialBalance) public {
_mint(initialAccount, initialBalance);
}
function mint(address account, uint256 amount) public {
_mint(account, amount);
}
function burn(address account, uint256 amount) public {
_burn(account, amount);
}
}
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../token/ERC721/ERC721Full.sol";
import "../token/ERC721/ERC721Mintable.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../token/ERC721/ERC721Full.sol";
import "../token/ERC721/ERC721Mintable.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../token/ERC721/ERC721.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../token/ERC721/ERC721Pausable.sol";
import "./PauserRoleMock.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../token/ERC721/IERC721Receiver.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
contract EventEmitter {
event Argumentless();
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
contract Failer {
uint256[] private array;
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../token/ERC20/IERC20.sol";
import "../crowdsale/distribution/FinalizableCrowdsale.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../crowdsale/price/IncreasingPriceCrowdsale.sol";
import "../math/SafeMath.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../token/ERC20/IERC20.sol";
import "../crowdsale/validation/IndividuallyCappedCrowdsale.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../math/Math.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import { MerkleProof } from "../cryptography/MerkleProof.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../token/ERC20/ERC20Mintable.sol";
import "../crowdsale/emission/MintedCrowdsale.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../access/roles/MinterRole.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../ownership/Ownable.sol";
/**
* @title Ownable interface id calculator.
* @dev See the EIP165 specification for more information:
* https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md#specification
* https://eips.ethereum.org/EIPS/eip-165#specification
*/
contract OwnableInterfaceId {
function getInterfaceId() public pure returns (bytes4) {
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../ownership/Ownable.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../token/ERC20/ERC20.sol";
import "../crowdsale/validation/PausableCrowdsale.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../lifecycle/Pausable.sol";
import "./PauserRoleMock.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../access/roles/PauserRole.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../token/ERC20/IERC20.sol";
import "../crowdsale/distribution/PostDeliveryCrowdsale.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../payment/PullPayment.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
contract ReentrancyAttack {
function callSender(bytes4 data) public {
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../utils/ReentrancyGuard.sol";
import "./ReentrancyAttack.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../token/ERC20/IERC20.sol";
import "../crowdsale/distribution/RefundableCrowdsale.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../token/ERC20/IERC20.sol";
import "../crowdsale/distribution/RefundablePostDeliveryCrowdsale.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../access/Roles.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../token/ERC20/IERC20.sol";
import "../token/ERC20/SafeERC20.sol";
contract ERC20FailingMock {
contract ERC20ReturnFalseMock {
uint256 private _allowance;
// IERC20's functions are not pure, but these mock implementations are: to prevent Solidity from issuing warnings,
// we write to a dummy state variable.
uint256 private _dummy;
function transfer(address, uint256) public returns (bool) {
_dummy = 0;
return false;
}
function transferFrom(address, address, uint256) public returns (bool) {
_dummy = 0;
return false;
}
function approve(address, uint256) public returns (bool) {
_dummy = 0;
return false;
}
function allowance(address, address) public view returns (uint256) {
require(_dummy == 0);
return 0;
}
}
contract ERC20SucceedingMock {
uint256 private _allowance;
contract ERC20ReturnTrueMock {
mapping (address => uint256) private _allowances;
// IERC20's functions are not pure, but these mock implementations are: to prevent Solidity from issuing warnings,
// we write to a dummy state variable.
uint256 private _dummy;
function transfer(address, uint256) public returns (bool) {
_dummy = 0;
return true;
}
function transferFrom(address, address, uint256) public returns (bool) {
_dummy = 0;
return true;
}
function approve(address, uint256) public returns (bool) {
_dummy = 0;
return true;
}
function setAllowance(uint256 allowance_) public {
_allowance = allowance_;
_allowances[msg.sender] = allowance_;
}
function allowance(address, address) public view returns (uint256) {
return _allowance;
function allowance(address owner, address) public view returns (uint256) {
return _allowances[owner];
}
}
contract SafeERC20Helper {
using SafeERC20 for IERC20;
contract ERC20NoReturnMock {
mapping (address => uint256) private _allowances;
IERC20 private _failing;
IERC20 private _succeeding;
// IERC20's functions are not pure, but these mock implementations are: to prevent Solidity from issuing warnings,
// we write to a dummy state variable.
uint256 private _dummy;
constructor () public {
_failing = IERC20(address(new ERC20FailingMock()));
_succeeding = IERC20(address(new ERC20SucceedingMock()));
function transfer(address, uint256) public {
_dummy = 0;
}
function doFailingTransfer() public {
_failing.safeTransfer(address(0), 0);
function transferFrom(address, address, uint256) public {
_dummy = 0;
}
function doFailingTransferFrom() public {
_failing.safeTransferFrom(address(0), address(0), 0);
function approve(address, uint256) public {
_dummy = 0;
}
function doFailingApprove() public {
_failing.safeApprove(address(0), 0);
function setAllowance(uint256 allowance_) public {
_allowances[msg.sender] = allowance_;
}
function doFailingIncreaseAllowance() public {
_failing.safeIncreaseAllowance(address(0), 0);
function allowance(address owner, address) public view returns (uint256) {
return _allowances[owner];
}
}
contract SafeERC20Wrapper {
using SafeERC20 for IERC20;
IERC20 private _token;
function doFailingDecreaseAllowance() public {
_failing.safeDecreaseAllowance(address(0), 0);
constructor (IERC20 token) public {
_token = token;
}
function doSucceedingTransfer() public {
_succeeding.safeTransfer(address(0), 0);
function transfer() public {
_token.safeTransfer(address(0), 0);
}
function doSucceedingTransferFrom() public {
_succeeding.safeTransferFrom(address(0), address(0), 0);
function transferFrom() public {
_token.safeTransferFrom(address(0), address(0), 0);
}
function doSucceedingApprove(uint256 amount) public {
_succeeding.safeApprove(address(0), amount);
function approve(uint256 amount) public {
_token.safeApprove(address(0), amount);
}
function doSucceedingIncreaseAllowance(uint256 amount) public {
_succeeding.safeIncreaseAllowance(address(0), amount);
function increaseAllowance(uint256 amount) public {
_token.safeIncreaseAllowance(address(0), amount);
}
function doSucceedingDecreaseAllowance(uint256 amount) public {
_succeeding.safeDecreaseAllowance(address(0), amount);
function decreaseAllowance(uint256 amount) public {
_token.safeDecreaseAllowance(address(0), amount);
}
function setAllowance(uint256 allowance_) public {
ERC20SucceedingMock(address(_succeeding)).setAllowance(allowance_);
ERC20ReturnTrueMock(address(_token)).setAllowance(allowance_);
}
function allowance() public view returns (uint256) {
return _succeeding.allowance(address(0), address(0));
return _token.allowance(address(0), address(0));
}
}
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../math/SafeMath.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../ownership/Secondary.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../drafts/SignatureBouncer.sol";
import "./SignerRoleMock.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../drafts/SignedSafeMath.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../access/roles/SignerRole.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../token/ERC20/IERC20.sol";
import "../crowdsale/validation/TimedCrowdsale.sol";
......@@ -10,4 +10,8 @@ contract TimedCrowdsaleImpl is TimedCrowdsale {
Crowdsale.initialize(rate, wallet, token);
TimedCrowdsale.initialize(openingTime, closingTime);
}
function extendTime(uint256 closingTime) public {
_extendTime(closingTime);
}
}
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../access/roles/WhitelistAdminRole.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../token/ERC20/IERC20.sol";
import "../crowdsale/validation/WhitelistCrowdsale.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../access/roles/WhitelistedRole.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
......@@ -45,9 +45,10 @@ contract Ownable is Initializable {
/**
* @dev Allows the current owner to relinquish control of the contract.
* @notice Renouncing to ownership will leave the contract without an owner.
* It will not be possible to call the functions with the `onlyOwner`
* modifier anymore.
* @notice Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public onlyOwner {
emit OwnershipTransferred(_owner, address(0));
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
......@@ -21,26 +21,26 @@ contract PullPayment is Initializable {
}
/**
* @dev Withdraw accumulated balance.
* @param payee Whose balance will be withdrawn.
*/
* @dev Withdraw accumulated balance.
* @param payee Whose balance will be withdrawn.
*/
function withdrawPayments(address payable payee) public {
_escrow.withdraw(payee);
}
/**
* @dev Returns the credit owed to an address.
* @param dest The creditor's address.
*/
* @dev Returns the credit owed to an address.
* @param dest The creditor's address.
*/
function payments(address dest) public view returns (uint256) {
return _escrow.depositsOf(dest);
}
/**
* @dev Called by the payer to store the sent amount as credit to be pulled.
* @param dest The destination address of the funds.
* @param amount The amount to transfer.
*/
* @dev Called by the payer to store the sent amount as credit to be pulled.
* @param dest The destination address of the funds.
* @param amount The amount to transfer.
*/
function _asyncTransfer(address dest, uint256 amount) internal {
_escrow.deposit.value(amount)(dest);
}
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "./Escrow.sol";
......@@ -13,10 +13,10 @@ contract ConditionalEscrow is Initializable, Escrow {
}
/**
* @dev Returns whether an address is allowed to withdraw their funds. To be
* implemented by derived contracts.
* @param payee The destination address of the funds.
*/
* @dev Returns whether an address is allowed to withdraw their funds. To be
* implemented by derived contracts.
* @param payee The destination address of the funds.
*/
function withdrawalAllowed(address payee) public view returns (bool);
function withdraw(address payable payee) public {
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../../math/SafeMath.sol";
import "../../ownership/Secondary.sol";
/**
* @title Escrow
* @dev Base escrow contract, holds funds designated for a payee until they
* withdraw them.
* @dev Intended usage: This contract (and derived escrow contracts) should be a
* standalone contract, that only interacts with the contract that instantiated
* it. That way, it is guaranteed that all Ether will be handled according to
* the Escrow rules, and there is no need to check for payable functions or
* transfers in the inheritance tree. The contract that uses the escrow as its
* payment method should be its primary, and provide public methods redirecting
* to the escrow's deposit and withdraw.
*/
* @title Escrow
* @dev Base escrow contract, holds funds designated for a payee until they
* withdraw them.
* @dev Intended usage: This contract (and derived escrow contracts) should be a
* standalone contract, that only interacts with the contract that instantiated
* it. That way, it is guaranteed that all Ether will be handled according to
* the Escrow rules, and there is no need to check for payable functions or
* transfers in the inheritance tree. The contract that uses the escrow as its
* payment method should be its primary, and provide public methods redirecting
* to the escrow's deposit and withdraw.
*/
contract Escrow is Initializable, Secondary {
using SafeMath for uint256;
......@@ -32,9 +32,9 @@ contract Escrow is Initializable, Secondary {
}
/**
* @dev Stores the sent amount as credit to be withdrawn.
* @param payee The destination address of the funds.
*/
* @dev Stores the sent amount as credit to be withdrawn.
* @param payee The destination address of the funds.
*/
function deposit(address payee) public onlyPrimary payable {
uint256 amount = msg.value;
_deposits[payee] = _deposits[payee].add(amount);
......@@ -43,9 +43,9 @@ contract Escrow is Initializable, Secondary {
}
/**
* @dev Withdraw accumulated balance for a payee.
* @param payee The address whose funds will be withdrawn and transferred to.
*/
* @dev Withdraw accumulated balance for a payee.
* @param payee The address whose funds will be withdrawn and transferred to.
*/
function withdraw(address payable payee) public onlyPrimary {
uint256 payment = _deposits[payee];
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
......@@ -87,7 +87,7 @@ contract RefundEscrow is Initializable, ConditionalEscrow {
}
/**
* @dev Returns whether refundees can withdraw their deposits (be refunded). The overriden function receives a
* @dev Returns whether refundees can withdraw their deposits (be refunded). The overridden function receives a
* 'payee' argument, but we ignore it here since the condition is global, not per-payee.
*/
function withdrawalAllowed(address) public view returns (bool) {
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "./IERC20.sol";
......@@ -8,7 +8,7 @@ import "../../math/SafeMath.sol";
* @title Standard ERC20 token
*
* @dev Implementation of the basic standard token.
* https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
* https://eips.ethereum.org/EIPS/eip-20
* Originally based on code by FirstBlood:
* https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
*
......@@ -26,17 +26,17 @@ contract ERC20 is Initializable, IERC20 {
uint256 private _totalSupply;
/**
* @dev Total number of tokens in existence
*/
* @dev Total number of tokens in existence
*/
function totalSupply() public view returns (uint256) {
return _totalSupply;
}
/**
* @dev Gets the balance of the specified address.
* @param owner The address to query the balance of.
* @return An uint256 representing the amount owned by the passed address.
*/
* @dev Gets the balance of the specified address.
* @param owner The address to query the balance of.
* @return A uint256 representing the amount owned by the passed address.
*/
function balanceOf(address owner) public view returns (uint256) {
return _balances[owner];
}
......@@ -52,10 +52,10 @@ contract ERC20 is Initializable, IERC20 {
}
/**
* @dev Transfer token for a specified address
* @param to The address to transfer to.
* @param value The amount to be transferred.
*/
* @dev Transfer token to a specified address
* @param to The address to transfer to.
* @param value The amount to be transferred.
*/
function transfer(address to, uint256 value) public returns (bool) {
_transfer(msg.sender, to, value);
return true;
......@@ -71,10 +71,7 @@ contract ERC20 is Initializable, IERC20 {
* @param value The amount of tokens to be spent.
*/
function approve(address spender, uint256 value) public returns (bool) {
require(spender != address(0));
_allowed[msg.sender][spender] = value;
emit Approval(msg.sender, spender, value);
_approve(msg.sender, spender, value);
return true;
}
......@@ -87,15 +84,14 @@ contract ERC20 is Initializable, IERC20 {
* @param value uint256 the amount of tokens to be transferred
*/
function transferFrom(address from, address to, uint256 value) public returns (bool) {
_allowed[from][msg.sender] = _allowed[from][msg.sender].sub(value);
_transfer(from, to, value);
emit Approval(from, msg.sender, _allowed[from][msg.sender]);
_approve(from, msg.sender, _allowed[from][msg.sender].sub(value));
return true;
}
/**
* @dev Increase the amount of tokens that an owner allowed to a spender.
* approve should be called when allowed_[_spender] == 0. To increment
* approve should be called when _allowed[msg.sender][spender] == 0. To increment
* allowed value is better to use this function to avoid 2 calls (and wait until
* the first transaction is mined)
* From MonolithDAO Token.sol
......@@ -104,16 +100,13 @@ contract ERC20 is Initializable, IERC20 {
* @param addedValue The amount of tokens to increase the allowance by.
*/
function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
require(spender != address(0));
_allowed[msg.sender][spender] = _allowed[msg.sender][spender].add(addedValue);
emit Approval(msg.sender, spender, _allowed[msg.sender][spender]);
_approve(msg.sender, spender, _allowed[msg.sender][spender].add(addedValue));
return true;
}
/**
* @dev Decrease the amount of tokens that an owner allowed to a spender.
* approve should be called when allowed_[_spender] == 0. To decrement
* approve should be called when _allowed[msg.sender][spender] == 0. To decrement
* allowed value is better to use this function to avoid 2 calls (and wait until
* the first transaction is mined)
* From MonolithDAO Token.sol
......@@ -122,19 +115,16 @@ contract ERC20 is Initializable, IERC20 {
* @param subtractedValue The amount of tokens to decrease the allowance by.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
require(spender != address(0));
_allowed[msg.sender][spender] = _allowed[msg.sender][spender].sub(subtractedValue);
emit Approval(msg.sender, spender, _allowed[msg.sender][spender]);
_approve(msg.sender, spender, _allowed[msg.sender][spender].sub(subtractedValue));
return true;
}
/**
* @dev Transfer token for a specified addresses
* @param from The address to transfer from.
* @param to The address to transfer to.
* @param value The amount to be transferred.
*/
* @dev Transfer token for a specified addresses
* @param from The address to transfer from.
* @param to The address to transfer to.
* @param value The amount to be transferred.
*/
function _transfer(address from, address to, uint256 value) internal {
require(to != address(0));
......@@ -173,6 +163,20 @@ contract ERC20 is Initializable, IERC20 {
}
/**
* @dev Approve an address to spend another addresses' tokens.
* @param owner The address that owns the tokens.
* @param spender The address that will spend the tokens.
* @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));
_allowed[owner][spender] = value;
emit Approval(owner, spender, value);
}
/**
* @dev Internal function that burns an amount of the token of a given
* account, deducting from the sender's allowance for said account. Uses the
* internal burn function.
......@@ -181,9 +185,8 @@ contract ERC20 is Initializable, IERC20 {
* @param value The amount that will be burnt.
*/
function _burnFrom(address account, uint256 value) internal {
_allowed[account][msg.sender] = _allowed[account][msg.sender].sub(value);
_burn(account, value);
emit Approval(account, msg.sender, _allowed[account][msg.sender]);
_approve(account, msg.sender, _allowed[account][msg.sender].sub(value));
}
uint256[50] private ______gap;
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "./ERC20.sol";
......@@ -18,8 +18,8 @@ contract ERC20Burnable is Initializable, ERC20 {
/**
* @dev Burns a specific amount of tokens from the target address and decrements allowance
* @param from address The address which you want to send tokens from
* @param value uint256 The amount of token to be burned
* @param from address The account whose tokens will be burned.
* @param value uint256 The amount of token to be burned.
*/
function burnFrom(address from, uint256 value) public {
_burnFrom(from, value);
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "./ERC20Mintable.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "./IERC20.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "./ERC20.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "./ERC20.sol";
......@@ -7,7 +7,7 @@ import "../../lifecycle/Pausable.sol";
/**
* @title Pausable token
* @dev ERC20 modified with pausable transfers.
**/
*/
contract ERC20Pausable is Initializable, ERC20, Pausable {
function initialize(address sender) public initializer {
Pausable.initialize(sender);
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
/**
* @title ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/20
* @dev see https://eips.ethereum.org/EIPS/eip-20
*/
interface IERC20 {
function transfer(address to, uint256 value) external returns (bool);
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "./IERC20.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure.
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using SafeMath for uint256;
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
require(token.transfer(to, value));
callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
require(token.transferFrom(from, to, value));
callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// 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(msg.sender, spender) == 0));
require(token.approve(spender, value));
require((value == 0) || (token.allowance(address(this), spender) == 0));
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).add(value);
require(token.approve(spender, newAllowance));
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).sub(value);
require(token.approve(spender, newAllowance));
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must equal true).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves.
// A Solidity high level call has three parts:
// 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 avoid-low-level-calls
(bool success, bytes memory returndata) = address(token).call(data);
require(success);
if (returndata.length > 0) { // Return data is optional
require(abi.decode(returndata, (bool)));
}
}
}
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "./SafeERC20.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "./IERC721.sol";
import "./IERC721Receiver.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";
import "../../drafts/Counters.sol";
import "../../introspection/ERC165.sol";
/**
* @title ERC721 Non-Fungible Token Standard basic implementation
* @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
* @dev see https://eips.ethereum.org/EIPS/eip-721
*/
contract ERC721 is Initializable, ERC165, IERC721 {
using SafeMath for uint256;
using Address for address;
using Counters for Counters.Counter;
// Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
// which can be also obtained as `IERC721Receiver(0).onERC721Received.selector`
......@@ -26,7 +28,7 @@ contract ERC721 is Initializable, ERC165, IERC721 {
mapping (uint256 => address) private _tokenApprovals;
// Mapping from owner to number of owned token
mapping (address => uint256) private _ownedTokensCount;
mapping (address => Counters.Counter) private _ownedTokensCount;
// Mapping from owner to operator approvals
mapping (address => mapping (address => bool)) private _operatorApprovals;
......@@ -63,13 +65,13 @@ contract ERC721 is Initializable, ERC165, IERC721 {
*/
function balanceOf(address owner) public view returns (uint256) {
require(owner != address(0));
return _ownedTokensCount[owner];
return _ownedTokensCount[owner].current();
}
/**
* @dev Gets the owner of the specified token ID
* @param tokenId uint256 ID of the token to query the owner of
* @return owner address currently marked as the owner of the given token ID
* @return address currently marked as the owner of the given token ID
*/
function ownerOf(uint256 tokenId) public view returns (address) {
address owner = _tokenOwner[tokenId];
......@@ -130,11 +132,11 @@ contract ERC721 is Initializable, ERC165, IERC721 {
/**
* @dev Transfers the ownership of a given token ID to another address
* Usage of this method is discouraged, use `safeTransferFrom` whenever possible
* Requires the msg sender to be the owner, approved, or operator
* Requires the msg.sender to be the owner, approved, or operator
* @param from current owner of the token
* @param to address to receive the ownership of the given token ID
* @param tokenId uint256 ID of the token to be transferred
*/
*/
function transferFrom(address from, address to, uint256 tokenId) public {
require(_isApprovedOrOwner(msg.sender, tokenId));
......@@ -147,12 +149,11 @@ contract ERC721 is Initializable, ERC165, IERC721 {
* which is called upon a safe transfer, and return the magic value
* `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
* the transfer is reverted.
*
* Requires the msg sender to be the owner, approved, or operator
* Requires the msg.sender to be the owner, approved, or operator
* @param from current owner of the token
* @param to address to receive the ownership of the given token ID
* @param tokenId uint256 ID of the token to be transferred
*/
*/
function safeTransferFrom(address from, address to, uint256 tokenId) public {
safeTransferFrom(from, to, tokenId, "");
}
......@@ -163,7 +164,7 @@ contract ERC721 is Initializable, ERC165, IERC721 {
* which is called upon a safe transfer, and return the magic value
* `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
* the transfer is reverted.
* Requires the msg sender to be the owner, approved, or operator
* Requires the msg.sender to be the owner, approved, or operator
* @param from current owner of the token
* @param to address to receive the ownership of the given token ID
* @param tokenId uint256 ID of the token to be transferred
......@@ -177,7 +178,7 @@ contract ERC721 is Initializable, ERC165, IERC721 {
/**
* @dev Returns whether the specified token exists
* @param tokenId uint256 ID of the token to query the existence of
* @return whether the token exists
* @return bool whether the token exists
*/
function _exists(uint256 tokenId) internal view returns (bool) {
address owner = _tokenOwner[tokenId];
......@@ -189,7 +190,7 @@ contract ERC721 is Initializable, ERC165, IERC721 {
* @param spender address of the spender to query
* @param tokenId uint256 ID of the token to be transferred
* @return bool whether the msg.sender is approved for the given token ID,
* is an operator of the owner, or is the owner of the token
* is an operator of the owner, or is the owner of the token
*/
function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) {
address owner = ownerOf(tokenId);
......@@ -207,7 +208,7 @@ contract ERC721 is Initializable, ERC165, IERC721 {
require(!_exists(tokenId));
_tokenOwner[tokenId] = to;
_ownedTokensCount[to] = _ownedTokensCount[to].add(1);
_ownedTokensCount[to].increment();
emit Transfer(address(0), to, tokenId);
}
......@@ -224,7 +225,7 @@ contract ERC721 is Initializable, ERC165, IERC721 {
_clearApproval(tokenId);
_ownedTokensCount[owner] = _ownedTokensCount[owner].sub(1);
_ownedTokensCount[owner].decrement();
_tokenOwner[tokenId] = address(0);
emit Transfer(owner, address(0), tokenId);
......@@ -245,15 +246,15 @@ contract ERC721 is Initializable, ERC165, IERC721 {
* @param from current owner of the token
* @param to address to receive the ownership of the given token ID
* @param tokenId uint256 ID of the token to be transferred
*/
*/
function _transferFrom(address from, address to, uint256 tokenId) internal {
require(ownerOf(tokenId) == from);
require(to != address(0));
_clearApproval(tokenId);
_ownedTokensCount[from] = _ownedTokensCount[from].sub(1);
_ownedTokensCount[to] = _ownedTokensCount[to].add(1);
_ownedTokensCount[from].decrement();
_ownedTokensCount[to].increment();
_tokenOwner[tokenId] = to;
......@@ -267,7 +268,7 @@ contract ERC721 is Initializable, ERC165, IERC721 {
* @param to target address that will receive the tokens
* @param tokenId uint256 ID of the token to be transferred
* @param _data bytes optional data to send along with the call
* @return whether the call correctly returned the expected magic value
* @return bool whether the call correctly returned the expected magic value
*/
function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data)
internal returns (bool)
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "./ERC721.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "./IERC721Enumerable.sol";
......@@ -7,7 +7,7 @@ import "../../introspection/ERC165.sol";
/**
* @title ERC-721 Non-Fungible Token with optional enumeration extension logic
* @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
contract ERC721Enumerable is Initializable, ERC165, ERC721, IERC721Enumerable {
// Mapping from owner to list of owned token IDs
......@@ -23,7 +23,7 @@ contract ERC721Enumerable is Initializable, ERC165, ERC721, IERC721Enumerable {
mapping(uint256 => uint256) private _allTokensIndex;
bytes4 private constant _INTERFACE_ID_ERC721_ENUMERABLE = 0x780e9d63;
/**
/*
* 0x780e9d63 ===
* bytes4(keccak256('totalSupply()')) ^
* bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) ^
......@@ -35,8 +35,7 @@ contract ERC721Enumerable is Initializable, ERC165, ERC721, IERC721Enumerable {
*/
function initialize() public initializer {
require(ERC721._hasBeenInitialized());
// register the supported interface to conform to ERC721 via ERC165
// register the supported interface to conform to ERC721Enumerable via ERC165
_registerInterface(_INTERFACE_ID_ERC721_ENUMERABLE);
}
......@@ -80,7 +79,7 @@ contract ERC721Enumerable is Initializable, ERC165, ERC721, IERC721Enumerable {
* @param from current owner of the token
* @param to address to receive the ownership of the given token ID
* @param tokenId uint256 ID of the token to be transferred
*/
*/
function _transferFrom(address from, address to, uint256 tokenId) internal {
super._transferFrom(from, to, tokenId);
......@@ -174,8 +173,8 @@ contract ERC721Enumerable is Initializable, ERC165, ERC721, IERC721Enumerable {
// This also deletes the contents at the last position of the array
_ownedTokens[from].length--;
// Note that _ownedTokensIndex[tokenId] hasn't been cleared: it still points to the old slot (now occcupied by
// lasTokenId, or just over the end of the array if the token was the last one).
// Note that _ownedTokensIndex[tokenId] hasn't been cleared: it still points to the old slot (now occupied by
// lastTokenId, or just over the end of the array if the token was the last one).
}
/**
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "./ERC721.sol";
......@@ -9,7 +9,7 @@ import "./ERC721Metadata.sol";
* @title Full ERC721 Token
* This implementation includes all the required and some optional functionality of the ERC721 standard
* Moreover, it includes approve all functionality using operator terminology
* @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
* @dev see https://eips.ethereum.org/EIPS/eip-721
*/
contract ERC721Full is Initializable, ERC721, ERC721Enumerable, ERC721Metadata {
uint256[50] private ______gap;
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "./IERC721Receiver.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "./ERC721.sol";
......@@ -16,7 +16,7 @@ contract ERC721Metadata is Initializable, ERC165, ERC721, IERC721Metadata {
mapping(uint256 => string) private _tokenURIs;
bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f;
/**
/*
* 0x5b5e139f ===
* bytes4(keccak256('name()')) ^
* bytes4(keccak256('symbol()')) ^
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "./ERC721Metadata.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "./ERC721.sol";
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "./ERC721.sol";
......@@ -7,7 +7,7 @@ import "../../lifecycle/Pausable.sol";
/**
* @title ERC721 Non-Fungible Pausable token
* @dev ERC721 modified with pausable transfers.
**/
*/
contract ERC721Pausable is Initializable, ERC721, Pausable {
function initialize(address sender) public initializer {
require(ERC721._hasBeenInitialized());
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "../../introspection/IERC165.sol";
/**
* @title ERC721 Non-Fungible Token Standard basic interface
* @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
* @dev see https://eips.ethereum.org/EIPS/eip-721
*/
contract IERC721 is Initializable, IERC165 {
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "./IERC721.sol";
/**
* @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
* @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
contract IERC721Enumerable is Initializable, IERC721 {
function totalSupply() public view returns (uint256);
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "./IERC721.sol";
......@@ -7,7 +7,7 @@ import "./IERC721Metadata.sol";
/**
* @title ERC-721 Non-Fungible Token Standard, full implementation interface
* @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
contract IERC721Full is Initializable, IERC721, IERC721Enumerable, IERC721Metadata {
// solhint-disable-previous-line no-empty-blocks
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
import "./IERC721.sol";
/**
* @title ERC-721 Non-Fungible Token Standard, optional metadata extension
* @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
contract IERC721Metadata is Initializable, IERC721 {
function name() external view returns (string memory);
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
/**
* @title ERC721 token receiver interface
......@@ -18,7 +18,7 @@ contract IERC721Receiver {
* @param from The address which previously owned the token
* @param tokenId The NFT identifier which is being transferred
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
* @return bytes4 `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
*/
function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data)
public returns (bytes4);
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
/**
* Utility library of inline functions on addresses
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "../math/Math.sol";
......@@ -9,13 +9,13 @@ import "../math/Math.sol";
*/
library Arrays {
/**
* @dev Upper bound search function which is kind of binary search algoritm. It searches sorted
* array to find index of the element value. If element is found then returns it's index otherwise
* it returns index of first element which is grater than searched value. If searched element is
* @dev Upper bound search function which is kind of binary search algorithm. It searches sorted
* array to find index of the element value. If element is found then returns its index otherwise
* it returns index of first element which is greater than searched value. If searched element is
* bigger than any array element function then returns first index after last element (i.e. all
* values inside the array are smaller than the target). Complexity O(log n).
* @param array The array sorted in ascending order.
* @param element The element's value to be find.
* @param element The element's value to be found.
* @return The calculated index value. Returns 0 for empty array.
*/
function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
......
pragma solidity ^0.5.0;
pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol";
......
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "openzeppelin-eth",
"version": "2.1.3",
"version": "2.2.0",
"description": "Secure Smart Contract library for Solidity",
"files": [
"build",
......@@ -58,7 +58,7 @@
"openzeppelin-test-helpers": "^0.1.1",
"pify": "^4.0.1",
"solhint": "^1.5.0",
"solidity-coverage": "^0.5.4",
"solidity-coverage": "https://github.com:rotcivegaf/solidity-coverage.git#5875f5b7bc74d447f3312c9c0e9fc7814b482477",
"truffle": "^5.0.0",
"zos": "^2.0.0",
"zos-lib": "^2.1.0"
......
......@@ -54,7 +54,7 @@ contract('AllowanceCrowdsale', function ([_, investor, wallet, purchaser, tokenW
});
describe('check remaining allowance', function () {
it('should report correct allowace left', async function () {
it('should report correct allowance left', async function () {
const remainingAllowance = tokenAllowance.sub(expectedTokenAmount);
await this.crowdsale.buyTokens(investor, { value: value, from: purchaser });
(await this.crowdsale.remainingTokens()).should.be.bignumber.equal(remainingAllowance);
......@@ -72,7 +72,7 @@ contract('AllowanceCrowdsale', function ([_, investor, wallet, purchaser, tokenW
});
});
describe('when token wallet is different from token address', function () {
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));
......
......@@ -31,7 +31,7 @@ contract('IncreasingPriceCrowdsale', function ([_, investor, wallet, purchaser])
));
});
it('reverts with a final equal to the initial rate', async function () {
it('reverts with a final rate equal to the initial rate', async function () {
await shouldFail.reverting(IncreasingPriceCrowdsaleImpl.new(
this.startTime, this.closingTime, wallet, this.token.address, initialRate, initialRate
));
......
const { BN, ether, shouldFail, time } = require('openzeppelin-test-helpers');
const { BN, ether, expectEvent, shouldFail, time } = require('openzeppelin-test-helpers');
const TimedCrowdsaleImpl = artifacts.require('TimedCrowdsaleImpl');
const SimpleToken = artifacts.require('SimpleTokenMock');
......@@ -73,5 +73,62 @@ contract('TimedCrowdsale', function ([_, investor, wallet, purchaser]) {
await shouldFail.reverting(this.crowdsale.buyTokens(investor, { value: value, from: purchaser }));
});
});
describe('extending closing time', function () {
it('should not reduce duration', async function () {
// Same date
await shouldFail.reverting(this.crowdsale.extendTime(this.closingTime));
// Prescending date
const newClosingTime = this.closingTime.sub(time.duration.seconds(1));
await shouldFail.reverting(this.crowdsale.extendTime(newClosingTime));
});
context('before crowdsale start', function () {
beforeEach(async function () {
(await this.crowdsale.isOpen()).should.equal(false);
await shouldFail.reverting(this.crowdsale.send(value));
});
it('it extends end time', async function () {
const newClosingTime = this.closingTime.add(time.duration.days(1));
const { logs } = await this.crowdsale.extendTime(newClosingTime);
expectEvent.inLogs(logs, 'TimedCrowdsaleExtended', {
prevClosingTime: this.closingTime,
newClosingTime: newClosingTime,
});
(await this.crowdsale.closingTime()).should.be.bignumber.equal(newClosingTime);
});
});
context('after crowdsale start', function () {
beforeEach(async function () {
await time.increaseTo(this.openingTime);
(await this.crowdsale.isOpen()).should.equal(true);
await this.crowdsale.send(value);
});
it('it extends end time', async function () {
const newClosingTime = this.closingTime.add(time.duration.days(1));
const { logs } = await this.crowdsale.extendTime(newClosingTime);
expectEvent.inLogs(logs, 'TimedCrowdsaleExtended', {
prevClosingTime: this.closingTime,
newClosingTime: newClosingTime,
});
(await this.crowdsale.closingTime()).should.be.bignumber.equal(newClosingTime);
});
});
context('after crowdsale end', function () {
beforeEach(async function () {
await time.increaseTo(this.afterClosingTime);
});
it('it reverts', async function () {
const newClosingTime = await time.latest();
await shouldFail.reverting(this.crowdsale.extendTime(newClosingTime));
});
});
});
});
});
const { shouldFail } = require('openzeppelin-test-helpers');
const { signMessage, toEthSignedMessageHash } = require('../helpers/sign');
const { constants, shouldFail } = require('openzeppelin-test-helpers');
const { ZERO_ADDRESS } = constants;
const { toEthSignedMessageHash, fixSignature } = require('../helpers/sign');
const ECDSAMock = artifacts.require('ECDSAMock');
......@@ -19,10 +20,10 @@ contract('ECDSA', function ([_, anyone]) {
const signatureWithoutVersion = '0x5d99b6f7f6d1f73d1a26497f2b1c89b24c0993913f86e9a2d02cd69887d9c94f3c880358579d811b21dd1b7fd9bb01c1d81d10e69f0384e675c32b39643be892';
context('with 00 as version value', function () {
it('works', async function () {
it('returns 0', async function () {
const version = '00';
const signature = signatureWithoutVersion + version;
(await this.ecdsa.recover(TEST_MESSAGE, signature)).should.equal(signer);
(await this.ecdsa.recover(TEST_MESSAGE, signature)).should.equal(ZERO_ADDRESS);
});
});
......@@ -40,8 +41,7 @@ contract('ECDSA', function ([_, anyone]) {
// The only valid values are 0, 1, 27 and 28.
const version = '02';
const signature = signatureWithoutVersion + version;
(await this.ecdsa.recover(TEST_MESSAGE, signature)).should.equal(
'0x0000000000000000000000000000000000000000');
(await this.ecdsa.recover(TEST_MESSAGE, signature)).should.equal(ZERO_ADDRESS);
});
});
});
......@@ -52,14 +52,14 @@ contract('ECDSA', function ([_, anyone]) {
const signatureWithoutVersion = '0x331fe75a821c982f9127538858900d87d3ec1f9f737338ad67cad133fa48feff48e6fa0c18abc62e42820f05943e47af3e9fbe306ce74d64094bdf1691ee53e0';
context('with 01 as version value', function () {
it('works', async function () {
it('returns 0', async function () {
const version = '01';
const signature = signatureWithoutVersion + version;
(await this.ecdsa.recover(TEST_MESSAGE, signature)).should.equal(signer);
(await this.ecdsa.recover(TEST_MESSAGE, signature)).should.equal(ZERO_ADDRESS);
});
});
context('with 28 signature', function () {
context('with 28 as version value', function () {
it('works', async function () {
const version = '1c'; // 28 = 1c.
const signature = signatureWithoutVersion + version;
......@@ -73,17 +73,26 @@ contract('ECDSA', function ([_, anyone]) {
// The only valid values are 0, 1, 27 and 28.
const version = '02';
const signature = signatureWithoutVersion + version;
(await this.ecdsa.recover(TEST_MESSAGE, signature)).should.equal(
'0x0000000000000000000000000000000000000000');
(await this.ecdsa.recover(TEST_MESSAGE, signature)).should.equal(ZERO_ADDRESS);
});
});
});
context('with high-s value signature', function () {
it('returns 0', async function () {
const message = '0xb94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9';
// eslint-disable-next-line max-len
const highSSignature = '0xe742ff452d41413616a5bf43fe15dd88294e983d3d36206c2712f39083d638bde0a0fc89be718fbc1033e1d30d78be1c68081562ed2e97af876f286f3453231d1b';
(await this.ecdsa.recover(message, highSSignature)).should.equal(ZERO_ADDRESS);
});
});
context('using web3.eth.sign', function () {
context('with correct signature', function () {
it('returns signer address', async function () {
// Create the signature
const signature = await signMessage(anyone, TEST_MESSAGE);
const signature = fixSignature(await web3.eth.sign(TEST_MESSAGE, anyone));
// Recover the signer address from the generated message and signature.
(await this.ecdsa.recover(
......@@ -96,23 +105,23 @@ contract('ECDSA', function ([_, anyone]) {
context('with wrong signature', function () {
it('does not return signer address', async function () {
// Create the signature
const signature = await signMessage(anyone, TEST_MESSAGE);
const signature = await web3.eth.sign(TEST_MESSAGE, anyone);
// Recover the signer address from the generated message and wrong signature.
(await this.ecdsa.recover(WRONG_MESSAGE, signature)).should.not.equal(anyone);
});
});
});
});
context('with small hash', function () {
// @TODO - remove `skip` once we upgrade to solc^0.5
it.skip('reverts', async function () {
// Create the signature
const signature = await signMessage(anyone, TEST_MESSAGE);
await shouldFail.reverting(
this.ecdsa.recover(TEST_MESSAGE.substring(2), signature)
);
context('with small hash', function () {
// @TODO - remove `skip` once we upgrade to solc^0.5
it.skip('reverts', async function () {
// Create the signature
const signature = await web3.eth.sign(TEST_MESSAGE, anyone);
await shouldFail.reverting(
this.ecdsa.recover(TEST_MESSAGE.substring(2), signature)
);
});
});
});
......
const { BN } = require('openzeppelin-test-helpers');
const CounterImpl = artifacts.require('CounterImpl');
const EXPECTED = [new BN(1), new BN(2), new BN(3), new BN(4)];
const KEY1 = web3.utils.sha3('key1');
const KEY2 = web3.utils.sha3('key2');
contract('Counter', function ([_, owner]) {
beforeEach(async function () {
this.mock = await CounterImpl.new({ from: owner });
});
context('custom key', async function () {
it('should return expected values', async function () {
for (const expectedId of EXPECTED) {
await this.mock.doThing(KEY1, { from: owner });
const actualId = await this.mock.theId();
actualId.should.be.bignumber.equal(expectedId);
}
});
});
context('parallel keys', async function () {
it('should return expected values for each counter', async function () {
for (const expectedId of EXPECTED) {
await this.mock.doThing(KEY1, { from: owner });
let actualId = await this.mock.theId();
actualId.should.be.bignumber.equal(expectedId);
await this.mock.doThing(KEY2, { from: owner });
actualId = await this.mock.theId();
actualId.should.be.bignumber.equal(expectedId);
}
});
});
});
const { shouldFail } = require('openzeppelin-test-helpers');
const CountersImpl = artifacts.require('CountersImpl');
contract('Counters', function () {
beforeEach(async function () {
this.counter = await CountersImpl.new();
});
it('starts at zero', async function () {
(await this.counter.current()).should.be.bignumber.equal('0');
});
describe('increment', function () {
it('increments the current value by one', async function () {
await this.counter.increment();
(await this.counter.current()).should.be.bignumber.equal('1');
});
it('can be called multiple times', async function () {
await this.counter.increment();
await this.counter.increment();
await this.counter.increment();
(await this.counter.current()).should.be.bignumber.equal('3');
});
});
describe('decrement', function () {
beforeEach(async function () {
await this.counter.increment();
(await this.counter.current()).should.be.bignumber.equal('1');
});
it('decrements the current value by one', async function () {
await this.counter.decrement();
(await this.counter.current()).should.be.bignumber.equal('0');
});
it('reverts if the current value is 0', async function () {
await this.counter.decrement();
await shouldFail.reverting(this.counter.decrement());
});
it('can be called multiple times', async function () {
await this.counter.increment();
await this.counter.increment();
(await this.counter.current()).should.be.bignumber.equal('3');
await this.counter.decrement();
await this.counter.decrement();
await this.counter.decrement();
(await this.counter.current()).should.be.bignumber.equal('0');
});
});
});
require('openzeppelin-test-helpers');
const ERC20WithMetadataMock = artifacts.require('ERC20WithMetadataMock');
const ERC20MetadataMock = artifacts.require('ERC20MetadataMock');
const metadataURI = 'https://example.com';
describe('ERC20WithMetadata', function () {
describe('ERC20Metadata', function () {
beforeEach(async function () {
this.token = await ERC20WithMetadataMock.new(metadataURI);
this.token = await ERC20MetadataMock.new(metadataURI);
});
it('responds with the metadata', async function () {
(await this.token.tokenURI()).should.equal(metadataURI);
});
describe('setTokenURI', function () {
it('changes the original URI', async function () {
const newMetadataURI = 'https://betterexample.com';
await this.token.setTokenURI(newMetadataURI);
(await this.token.tokenURI()).should.equal(newMetadataURI);
});
});
});
......@@ -44,6 +44,40 @@ contract('ERC20Migrator', function ([_, owner, recipient, anotherAccount]) {
});
});
context('before starting the migration', function () {
it('returns the zero address for the new token', async function () {
(await this.migrator.newToken()).should.be.equal(ZERO_ADDRESS);
});
describe('migrateAll', function () {
const amount = totalSupply;
describe('when the approved balance is equal to the owned balance', function () {
beforeEach('approving the whole balance to the new contract', async function () {
await this.legacyToken.approve(this.migrator.address, amount, { from: owner });
});
it('reverts', async function () {
await shouldFail.reverting(this.migrator.migrateAll(owner));
});
});
});
describe('migrate', function () {
const amount = new BN(50);
describe('when the amount is equal to the approved value', function () {
beforeEach('approving tokens to the new contract', async function () {
await this.legacyToken.approve(this.migrator.address, amount, { from: owner });
});
it('reverts', async function () {
await shouldFail.reverting(this.migrator.migrate(owner, amount));
});
});
});
});
describe('once migration began', function () {
beforeEach('beginning migration', async function () {
await this.newToken.addMinter(this.migrator.address);
......
const { BN, expectEvent, shouldFail } = require('openzeppelin-test-helpers');
const ERC20SnapshotMock = artifacts.require('ERC20SnapshotMock');
contract('ERC20Snapshot', function ([_, initialHolder, recipient, anyone]) {
const initialSupply = new BN(100);
beforeEach(async function () {
this.token = await ERC20SnapshotMock.new(initialHolder, initialSupply);
});
describe('snapshot', function () {
it('emits a snapshot event', async function () {
const { logs } = await this.token.snapshot();
expectEvent.inLogs(logs, 'Snapshot');
});
it('creates increasing snapshots ids, starting from 1', async function () {
for (const id of ['1', '2', '3', '4', '5']) {
const { logs } = await this.token.snapshot();
expectEvent.inLogs(logs, 'Snapshot', { id });
}
});
});
describe('totalSupplyAt', function () {
it('reverts with a snapshot id of 0', async function () {
await shouldFail.reverting(this.token.totalSupplyAt(0));
});
it('reverts with a not-yet-created snapshot id', async function () {
await shouldFail.reverting(this.token.totalSupplyAt(1));
});
context('with initial snapshot', function () {
beforeEach(async function () {
this.initialSnapshotId = new BN('1');
const { logs } = await this.token.snapshot();
expectEvent.inLogs(logs, 'Snapshot', { id: this.initialSnapshotId });
});
context('with no supply changes after the snapshot', function () {
it('returns the current total supply', async function () {
(await this.token.totalSupplyAt(this.initialSnapshotId)).should.be.bignumber.equal(initialSupply);
});
});
context('with supply changes after the snapshot', function () {
beforeEach(async function () {
await this.token.mint(anyone, new BN('50'));
await this.token.burn(initialHolder, new BN('20'));
});
it('returns the total supply before the changes', async function () {
(await this.token.totalSupplyAt(this.initialSnapshotId)).should.be.bignumber.equal(initialSupply);
});
context('with a second snapshot after supply changes', function () {
beforeEach(async function () {
this.secondSnapshotId = new BN('2');
const { logs } = await this.token.snapshot();
expectEvent.inLogs(logs, 'Snapshot', { id: this.secondSnapshotId });
});
it('snapshots return the supply before and after the changes', async function () {
(await this.token.totalSupplyAt(this.initialSnapshotId)).should.be.bignumber.equal(initialSupply);
(await this.token.totalSupplyAt(this.secondSnapshotId)).should.be.bignumber.equal(
await this.token.totalSupply()
);
});
});
context('with multiple snapshots after supply changes', function () {
beforeEach(async function () {
this.secondSnapshotIds = ['2', '3', '4'];
for (const id of this.secondSnapshotIds) {
const { logs } = await this.token.snapshot();
expectEvent.inLogs(logs, 'Snapshot', { id });
}
});
it('all posterior snapshots return the supply after the changes', async function () {
(await this.token.totalSupplyAt(this.initialSnapshotId)).should.be.bignumber.equal(initialSupply);
const currentSupply = await this.token.totalSupply();
for (const id of this.secondSnapshotIds) {
(await this.token.totalSupplyAt(id)).should.be.bignumber.equal(currentSupply);
}
});
});
});
});
});
describe('balanceOfAt', function () {
it('reverts with a snapshot id of 0', async function () {
await shouldFail.reverting(this.token.balanceOfAt(anyone, 0));
});
it('reverts with a not-yet-created snapshot id', async function () {
await shouldFail.reverting(this.token.balanceOfAt(anyone, 1));
});
context('with initial snapshot', function () {
beforeEach(async function () {
this.initialSnapshotId = new BN('1');
const { logs } = await this.token.snapshot();
expectEvent.inLogs(logs, 'Snapshot', { id: this.initialSnapshotId });
});
context('with no balance changes after the snapshot', function () {
it('returns the current balance for all accounts', async function () {
(await this.token.balanceOfAt(initialHolder, this.initialSnapshotId))
.should.be.bignumber.equal(initialSupply);
(await this.token.balanceOfAt(recipient, this.initialSnapshotId)).should.be.bignumber.equal('0');
(await this.token.balanceOfAt(anyone, this.initialSnapshotId)).should.be.bignumber.equal('0');
});
});
context('with balance changes after the snapshot', function () {
beforeEach(async function () {
await this.token.transfer(recipient, new BN('10'), { from: initialHolder });
await this.token.mint(recipient, new BN('50'));
await this.token.burn(initialHolder, new BN('20'));
});
it('returns the balances before the changes', async function () {
(await this.token.balanceOfAt(initialHolder, this.initialSnapshotId))
.should.be.bignumber.equal(initialSupply);
(await this.token.balanceOfAt(recipient, this.initialSnapshotId)).should.be.bignumber.equal('0');
(await this.token.balanceOfAt(anyone, this.initialSnapshotId)).should.be.bignumber.equal('0');
});
context('with a second snapshot after supply changes', function () {
beforeEach(async function () {
this.secondSnapshotId = new BN('2');
const { logs } = await this.token.snapshot();
expectEvent.inLogs(logs, 'Snapshot', { id: this.secondSnapshotId });
});
it('snapshots return the balances before and after the changes', async function () {
(await this.token.balanceOfAt(initialHolder, this.initialSnapshotId))
.should.be.bignumber.equal(initialSupply);
(await this.token.balanceOfAt(recipient, this.initialSnapshotId)).should.be.bignumber.equal('0');
(await this.token.balanceOfAt(anyone, this.initialSnapshotId)).should.be.bignumber.equal('0');
(await this.token.balanceOfAt(initialHolder, this.secondSnapshotId)).should.be.bignumber.equal(
await this.token.balanceOf(initialHolder)
);
(await this.token.balanceOfAt(recipient, this.secondSnapshotId)).should.be.bignumber.equal(
await this.token.balanceOf(recipient)
);
(await this.token.balanceOfAt(anyone, this.secondSnapshotId)).should.be.bignumber.equal(
await this.token.balanceOf(anyone)
);
});
});
context('with multiple snapshots after supply changes', function () {
beforeEach(async function () {
this.secondSnapshotIds = ['2', '3', '4'];
for (const id of this.secondSnapshotIds) {
const { logs } = await this.token.snapshot();
expectEvent.inLogs(logs, 'Snapshot', { id });
}
});
it('all posterior snapshots return the supply after the changes', async function () {
(await this.token.balanceOfAt(initialHolder, this.initialSnapshotId))
.should.be.bignumber.equal(initialSupply);
(await this.token.balanceOfAt(recipient, this.initialSnapshotId)).should.be.bignumber.equal('0');
(await this.token.balanceOfAt(anyone, this.initialSnapshotId)).should.be.bignumber.equal('0');
for (const id of this.secondSnapshotIds) {
(await this.token.balanceOfAt(initialHolder, id)).should.be.bignumber.equal(
await this.token.balanceOf(initialHolder)
);
(await this.token.balanceOfAt(recipient, id)).should.be.bignumber.equal(
await this.token.balanceOf(recipient)
);
(await this.token.balanceOfAt(anyone, id)).should.be.bignumber.equal(
await this.token.balanceOf(anyone)
);
}
});
});
});
});
});
});
......@@ -8,34 +8,43 @@ contract('SignedSafeMath', function () {
this.safeMath = await SignedSafeMathMock.new();
});
async function testCommutative (fn, lhs, rhs, expected) {
(await fn(lhs, rhs)).should.be.bignumber.equal(expected);
(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));
}
describe('add', function () {
it('adds correctly if it does not overflow and the result is positve', async function () {
it('adds correctly if it does not overflow and the result is positive', async function () {
const a = new BN('1234');
const b = new BN('5678');
(await this.safeMath.add(a, b)).should.be.bignumber.equal(a.add(b));
await testCommutative(this.safeMath.add, a, b, a.add(b));
});
it('adds correctly if it does not overflow and the result is negative', async function () {
const a = MAX_INT256;
const b = MIN_INT256;
const result = await this.safeMath.add(a, b);
result.should.be.bignumber.equal(a.add(b));
await testCommutative(this.safeMath.add, a, b, a.add(b));
});
it('reverts on positive addition overflow', async function () {
const a = MAX_INT256;
const b = new BN('1');
await shouldFail.reverting(this.safeMath.add(a, b));
await testFailsCommutative(this.safeMath.add, a, b);
});
it('reverts on negative addition overflow', async function () {
const a = MIN_INT256;
const b = new BN('-1');
await shouldFail.reverting(this.safeMath.add(a, b));
await testFailsCommutative(this.safeMath.add, a, b);
});
});
......@@ -76,37 +85,28 @@ contract('SignedSafeMath', function () {
const a = new BN('5678');
const b = new BN('-1234');
const result = await this.safeMath.mul(a, b);
result.should.be.bignumber.equal(a.mul(b));
await testCommutative(this.safeMath.mul, a, b, a.mul(b));
});
it('handles a zero product correctly', async function () {
it('multiplies by zero correctly', async function () {
const a = new BN('0');
const b = new BN('5678');
const result = await this.safeMath.mul(a, b);
result.should.be.bignumber.equal(a.mul(b));
await testCommutative(this.safeMath.mul, a, b, '0');
});
it('reverts on multiplication overflow, positive operands', async function () {
const a = MAX_INT256;
const b = new BN('2');
await shouldFail.reverting(this.safeMath.mul(a, b));
await testFailsCommutative(this.safeMath.mul, a, b);
});
it('reverts when minimum integer is multiplied by -1', async function () {
const a = MIN_INT256;
const b = new BN('-1');
await shouldFail.reverting(this.safeMath.mul(a, b));
});
it('reverts when -1 is multiplied by minimum integer', async function () {
const a = new BN('-1');
const b = MIN_INT256;
await shouldFail.reverting(this.safeMath.mul(a, b));
await testFailsCommutative(this.safeMath.mul, a, b);
});
});
......@@ -119,7 +119,21 @@ contract('SignedSafeMath', function () {
result.should.be.bignumber.equal(a.div(b));
});
it('reverts on zero division', async function () {
it('divides zero correctly', async function () {
const a = new BN('0');
const b = new BN('5678');
(await this.safeMath.div(a, b)).should.be.bignumber.equal('0');
});
it('returns complete number result on non-even division', async function () {
const a = new BN('7000');
const b = new BN('5678');
(await this.safeMath.div(a, b)).should.be.bignumber.equal('1');
});
it('reverts on division by zero', async function () {
const a = new BN('-5678');
const b = new BN('0');
......
......@@ -9,9 +9,21 @@ function toEthSignedMessageHash (messageHex) {
return web3.utils.sha3(Buffer.concat([prefix, messageBuffer]));
}
function fixSignature (signature) {
// in geth its always 27/28, in ganache its 0/1. Change to 27/28 to prevent
// signature malleability if version is 0/1
// see https://github.com/ethereum/go-ethereum/blob/v1.8.23/internal/ethapi/api.go#L465
let v = parseInt(signature.slice(130, 132), 16);
if (v < 27) {
v += 27;
}
const vHex = v.toString(16);
return signature.slice(0, 130) + vHex;
}
// signs message in node (ganache auto-applies "Ethereum Signed Message" prefix)
const signMessage = (signer, messageHex = '0x') => {
return web3.eth.sign(messageHex, signer);
async function signMessage (signer, messageHex = '0x') {
return fixSignature(await web3.eth.sign(messageHex, signer));
};
/**
......@@ -50,5 +62,6 @@ const getSignFor = (contract, signer) => (redeemer, methodName, methodArgs = [])
module.exports = {
signMessage,
toEthSignedMessageHash,
fixSignature,
getSignFor,
};
......@@ -17,7 +17,7 @@ contract('Pausable', function ([_, pauser, otherPauser, anyone, ...otherAccounts
shouldBehaveLikePublicRole(pauser, otherPauser, otherAccounts, 'pauser');
});
context('when unapused', function () {
context('when unpaused', function () {
beforeEach(async function () {
(await this.pausable.paused()).should.equal(false);
});
......
......@@ -8,19 +8,29 @@ contract('SafeMath', function () {
this.safeMath = await SafeMathMock.new();
});
async function testCommutative (fn, lhs, rhs, expected) {
(await fn(lhs, rhs)).should.be.bignumber.equal(expected);
(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));
}
describe('add', function () {
it('adds correctly', async function () {
const a = new BN('5678');
const b = new BN('1234');
(await this.safeMath.add(a, b)).should.be.bignumber.equal(a.add(b));
await testCommutative(this.safeMath.add, a, b, a.add(b));
});
it('reverts on addition overflow', async function () {
const a = MAX_UINT256;
const b = new BN('1');
await shouldFail.reverting(this.safeMath.add(a, b));
await testFailsCommutative(this.safeMath.add, a, b);
});
});
......@@ -45,28 +55,21 @@ contract('SafeMath', function () {
const a = new BN('1234');
const b = new BN('5678');
(await this.safeMath.mul(a, b)).should.be.bignumber.equal(a.mul(b));
await testCommutative(this.safeMath.mul, a, b, a.mul(b));
});
it('handles a zero product correctly (first number as zero)', async function () {
it('multiplies by zero correctly', async function () {
const a = new BN('0');
const b = new BN('5678');
(await this.safeMath.mul(a, b)).should.be.bignumber.equal(a.mul(b));
});
it('handles a zero product correctly (second number as zero)', async function () {
const a = new BN('5678');
const b = new BN('0');
(await this.safeMath.mul(a, b)).should.be.bignumber.equal(a.mul(b));
await testCommutative(this.safeMath.mul, a, b, '0');
});
it('reverts on multiplication overflow', async function () {
const a = MAX_UINT256;
const b = new BN('2');
await shouldFail.reverting(this.safeMath.mul(a, b));
await testFailsCommutative(this.safeMath.mul, a, b);
});
});
......@@ -92,7 +95,7 @@ contract('SafeMath', function () {
(await this.safeMath.div(a, b)).should.be.bignumber.equal('1');
});
it('reverts on zero division', async function () {
it('reverts on divison by zero', async function () {
const a = new BN('5678');
const b = new BN('0');
......
......@@ -16,7 +16,7 @@ function shouldBehaveLikeOwnable (owner, [anyone]) {
(await this.ownable.isOwner({ from: anyone })).should.be.equal(true);
});
it('should prevent non-owners from transfering', async function () {
it('should prevent non-owners from transferring', async function () {
await shouldFail.reverting(this.ownable.transferOwnership(anyone, { from: anyone }));
});
......
......@@ -29,7 +29,7 @@ contract('Secondary', function ([_, primary, newPrimary, anyone]) {
(await this.secondary.primary()).should.equal(newPrimary);
});
it('reverts when transfering to the null address', async function () {
it('reverts when transferring to the null address', async function () {
await shouldFail.reverting(this.secondary.transferPrimary(ZERO_ADDRESS, { from: primary }));
});
......
......@@ -84,19 +84,19 @@ contract('PaymentSplitter', function ([_, owner, payee1, payee2, payee3, nonpaye
const initAmount1 = await balance.current(payee1);
const { logs: logs1 } = await this.contract.release(payee1, { gasPrice: 0 });
const profit1 = (await balance.current(payee1)).sub(initAmount1);
profit1.should.be.bignumber.equal(ether('0.20', 'ether'));
profit1.should.be.bignumber.equal(ether('0.20'));
expectEvent.inLogs(logs1, 'PaymentReleased', { to: payee1, amount: profit1 });
const initAmount2 = await balance.current(payee2);
const { logs: logs2 } = await this.contract.release(payee2, { gasPrice: 0 });
const profit2 = (await balance.current(payee2)).sub(initAmount2);
profit2.should.be.bignumber.equal(ether('0.10', 'ether'));
profit2.should.be.bignumber.equal(ether('0.10'));
expectEvent.inLogs(logs2, 'PaymentReleased', { to: payee2, amount: profit2 });
const initAmount3 = await balance.current(payee3);
const { logs: logs3 } = await this.contract.release(payee3, { gasPrice: 0 });
const profit3 = (await balance.current(payee3)).sub(initAmount3);
profit3.should.be.bignumber.equal(ether('0.70', 'ether'));
profit3.should.be.bignumber.equal(ether('0.70'));
expectEvent.inLogs(logs3, 'PaymentReleased', { to: payee3, amount: profit3 });
// end balance should be zero
......
......@@ -73,89 +73,6 @@ contract('ERC20', function ([_, initialHolder, recipient, anotherAccount]) {
});
});
describe('approve', function () {
describe('when the spender is not the zero address', function () {
const spender = recipient;
describe('when the sender has enough balance', function () {
const amount = initialSupply;
it('emits an approval event', async function () {
const { logs } = await this.token.approve(spender, amount, { from: initialHolder });
expectEvent.inLogs(logs, 'Approval', {
owner: initialHolder,
spender: spender,
value: amount,
});
});
describe('when there was no approved amount before', function () {
it('approves the requested amount', async function () {
await this.token.approve(spender, amount, { from: initialHolder });
(await this.token.allowance(initialHolder, spender)).should.be.bignumber.equal(amount);
});
});
describe('when the spender had an approved amount', function () {
beforeEach(async function () {
await this.token.approve(spender, new BN(1), { from: initialHolder });
});
it('approves the requested amount and replaces the previous one', async function () {
await this.token.approve(spender, amount, { from: initialHolder });
(await this.token.allowance(initialHolder, spender)).should.be.bignumber.equal(amount);
});
});
});
describe('when the sender does not have enough balance', function () {
const amount = initialSupply.addn(1);
it('emits an approval event', async function () {
const { logs } = await this.token.approve(spender, amount, { from: initialHolder });
expectEvent.inLogs(logs, 'Approval', {
owner: initialHolder,
spender: spender,
value: amount,
});
});
describe('when there was no approved amount before', function () {
it('approves the requested amount', async function () {
await this.token.approve(spender, amount, { from: initialHolder });
(await this.token.allowance(initialHolder, spender)).should.be.bignumber.equal(amount);
});
});
describe('when the spender had an approved amount', function () {
beforeEach(async function () {
await this.token.approve(spender, new BN(1), { from: initialHolder });
});
it('approves the requested amount and replaces the previous one', async function () {
await this.token.approve(spender, amount, { from: initialHolder });
(await this.token.allowance(initialHolder, spender)).should.be.bignumber.equal(amount);
});
});
});
});
describe('when the spender is the zero address', function () {
const amount = initialSupply;
const spender = ZERO_ADDRESS;
it('reverts', async function () {
await shouldFail.reverting(this.token.approve(spender, amount, { from: initialHolder }));
});
});
});
describe('transfer from', function () {
const spender = recipient;
......@@ -546,4 +463,100 @@ contract('ERC20', function ([_, initialHolder, recipient, anotherAccount]) {
describeBurnFrom('for less amount than allowance', allowance.subn(1));
});
});
describe('approve', function () {
testApprove(initialHolder, recipient, initialSupply, function (owner, spender, amount) {
return this.token.approve(spender, amount, { from: owner });
});
});
describe('_approve', function () {
testApprove(initialHolder, recipient, initialSupply, function (owner, spender, amount) {
return this.token.approveInternal(owner, spender, amount);
});
describe('when the owner is the zero address', function () {
it('reverts', async function () {
await shouldFail.reverting(this.token.approveInternal(ZERO_ADDRESS, recipient, initialSupply));
});
});
});
function testApprove (owner, spender, supply, approve) {
describe('when the spender is not the zero address', function () {
describe('when the sender has enough balance', function () {
const amount = supply;
it('emits an approval event', async function () {
const { logs } = await approve.call(this, owner, spender, amount);
expectEvent.inLogs(logs, 'Approval', {
owner: owner,
spender: spender,
value: amount,
});
});
describe('when there was no approved amount before', function () {
it('approves the requested amount', async function () {
await approve.call(this, owner, spender, amount);
(await this.token.allowance(owner, spender)).should.be.bignumber.equal(amount);
});
});
describe('when the spender had an approved amount', function () {
beforeEach(async function () {
await approve.call(this, owner, spender, new BN(1));
});
it('approves the requested amount and replaces the previous one', async function () {
await approve.call(this, owner, spender, amount);
(await this.token.allowance(owner, spender)).should.be.bignumber.equal(amount);
});
});
});
describe('when the sender does not have enough balance', function () {
const amount = supply.addn(1);
it('emits an approval event', async function () {
const { logs } = await approve.call(this, owner, spender, amount);
expectEvent.inLogs(logs, 'Approval', {
owner: owner,
spender: spender,
value: amount,
});
});
describe('when there was no approved amount before', function () {
it('approves the requested amount', async function () {
await approve.call(this, owner, spender, amount);
(await this.token.allowance(owner, spender)).should.be.bignumber.equal(amount);
});
});
describe('when the spender had an approved amount', function () {
beforeEach(async function () {
await approve.call(this, owner, spender, new BN(1));
});
it('approves the requested amount and replaces the previous one', async function () {
await approve.call(this, owner, spender, amount);
(await this.token.allowance(owner, spender)).should.be.bignumber.equal(amount);
});
});
});
});
describe('when the spender is the zero address', function () {
it('reverts', async function () {
await shouldFail.reverting(approve.call(this, owner, ZERO_ADDRESS, supply));
});
});
}
});
const { shouldFail } = require('openzeppelin-test-helpers');
const SafeERC20Helper = artifacts.require('SafeERC20Helper');
const ERC20ReturnFalseMock = artifacts.require('ERC20ReturnFalseMock');
const ERC20ReturnTrueMock = artifacts.require('ERC20ReturnTrueMock');
const ERC20NoReturnMock = artifacts.require('ERC20NoReturnMock');
const SafeERC20Wrapper = artifacts.require('SafeERC20Wrapper');
contract('SafeERC20', function ([_, hasNoCode]) {
describe('with address that has no contract code', function () {
beforeEach(async function () {
this.wrapper = await SafeERC20Wrapper.new(hasNoCode);
});
contract('SafeERC20', function () {
beforeEach(async function () {
this.helper = await SafeERC20Helper.new();
shouldRevertOnAllCalls();
});
describe('with token that returns false on all calls', function () {
it('reverts on transfer', async function () {
await shouldFail.reverting(this.helper.doFailingTransfer());
beforeEach(async function () {
this.wrapper = await SafeERC20Wrapper.new((await ERC20ReturnFalseMock.new()).address);
});
it('reverts on transferFrom', async function () {
await shouldFail.reverting(this.helper.doFailingTransferFrom());
});
shouldRevertOnAllCalls();
});
it('reverts on approve', async function () {
await shouldFail.reverting(this.helper.doFailingApprove());
describe('with token that returns true on all calls', function () {
beforeEach(async function () {
this.wrapper = await SafeERC20Wrapper.new((await ERC20ReturnTrueMock.new()).address);
});
it('reverts on increaseAllowance', async function () {
await shouldFail.reverting(this.helper.doFailingIncreaseAllowance());
});
shouldOnlyRevertOnErrors();
});
it('reverts on decreaseAllowance', async function () {
await shouldFail.reverting(this.helper.doFailingDecreaseAllowance());
describe('with token that returns no boolean values', function () {
beforeEach(async function () {
this.wrapper = await SafeERC20Wrapper.new((await ERC20NoReturnMock.new()).address);
});
shouldOnlyRevertOnErrors();
});
});
describe('with token that returns true on all calls', function () {
it('doesn\'t revert on transfer', async function () {
await this.helper.doSucceedingTransfer();
});
function shouldRevertOnAllCalls () {
it('reverts on transfer', async function () {
await shouldFail.reverting(this.wrapper.transfer());
});
it('doesn\'t revert on transferFrom', async function () {
await this.helper.doSucceedingTransferFrom();
});
it('reverts on transferFrom', async function () {
await shouldFail.reverting(this.wrapper.transferFrom());
});
it('reverts on approve', async function () {
await shouldFail.reverting(this.wrapper.approve(0));
});
it('reverts on increaseAllowance', async function () {
await shouldFail.reverting(this.wrapper.increaseAllowance(0));
});
describe('approvals', function () {
context('with zero allowance', function () {
beforeEach(async function () {
await this.helper.setAllowance(0);
});
it('reverts on decreaseAllowance', async function () {
await shouldFail.reverting(this.wrapper.decreaseAllowance(0));
});
}
it('doesn\'t revert when approving a non-zero allowance', async function () {
await this.helper.doSucceedingApprove(100);
});
function shouldOnlyRevertOnErrors () {
it('doesn\'t revert on transfer', async function () {
await this.wrapper.transfer();
});
it('doesn\'t revert when approving a zero allowance', async function () {
await this.helper.doSucceedingApprove(0);
});
it('doesn\'t revert on transferFrom', async function () {
await this.wrapper.transferFrom();
});
it('doesn\'t revert when increasing the allowance', async function () {
await this.helper.doSucceedingIncreaseAllowance(10);
});
describe('approvals', function () {
context('with zero allowance', function () {
beforeEach(async function () {
await this.wrapper.setAllowance(0);
});
it('reverts when decreasing the allowance', async function () {
await shouldFail.reverting(this.helper.doSucceedingDecreaseAllowance(10));
});
it('doesn\'t revert when approving a non-zero allowance', async function () {
await this.wrapper.approve(100);
});
context('with non-zero allowance', function () {
beforeEach(async function () {
await this.helper.setAllowance(100);
});
it('doesn\'t revert when approving a zero allowance', async function () {
await this.wrapper.approve(0);
});
it('reverts when approving a non-zero allowance', async function () {
await shouldFail.reverting(this.helper.doSucceedingApprove(20));
});
it('doesn\'t revert when increasing the allowance', async function () {
await this.wrapper.increaseAllowance(10);
});
it('doesn\'t revert when approving a zero allowance', async function () {
await this.helper.doSucceedingApprove(0);
});
it('reverts when decreasing the allowance', async function () {
await shouldFail.reverting(this.wrapper.decreaseAllowance(10));
});
});
it('doesn\'t revert when increasing the allowance', async function () {
await this.helper.doSucceedingIncreaseAllowance(10);
});
context('with non-zero allowance', function () {
beforeEach(async function () {
await this.wrapper.setAllowance(100);
});
it('doesn\'t revert when decreasing the allowance to a positive value', async function () {
await this.helper.doSucceedingDecreaseAllowance(50);
});
it('reverts when approving a non-zero allowance', async function () {
await shouldFail.reverting(this.wrapper.approve(20));
});
it('doesn\'t revert when approving a zero allowance', async function () {
await this.wrapper.approve(0);
});
it('doesn\'t revert when increasing the allowance', async function () {
await this.wrapper.increaseAllowance(10);
});
it('doesn\'t revert when decreasing the allowance to a positive value', async function () {
await this.wrapper.decreaseAllowance(50);
});
it('reverts when decreasing the allowance to a negative value', async function () {
await shouldFail.reverting(this.helper.doSucceedingDecreaseAllowance(200));
});
it('reverts when decreasing the allowance to a negative value', async function () {
await shouldFail.reverting(this.wrapper.decreaseAllowance(200));
});
});
});
});
}
......@@ -55,7 +55,7 @@ function shouldBehaveLikeERC721PausedToken (owner, [recipient, operator]) {
});
describe('exists', function () {
it('should return token existance', async function () {
it('should return token existence', async function () {
(await this.token.exists(firstTokenId)).should.equal(true);
});
});
......
......@@ -16,7 +16,7 @@ module.exports = {
compilers: {
solc: {
version: '0.5.0',
version: '0.5.2',
},
},
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment