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 # ...@@ -16,6 +16,7 @@ Fixes #
(https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/CONTRIBUTING.md), (https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/CONTRIBUTING.md),
- added tests where applicable to test new functionality, - added tests where applicable to test new functionality,
- made sure that your contracts are well-documented, - 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. - updated the changelog, if applicable.
--> -->
...@@ -32,10 +32,13 @@ npm-debug.log ...@@ -32,10 +32,13 @@ npm-debug.log
# truffle build directory # truffle build directory
build/ build/
# lol macs # macOS
.DS_Store/ .DS_Store
# truffle # truffle
.node-xmlhttprequest-* .node-xmlhttprequest-*
.zos.session .zos.session
# IntelliJ IDE
.idea
...@@ -25,11 +25,10 @@ jobs: ...@@ -25,11 +25,10 @@ jobs:
name: "Unit tests" name: "Unit tests"
script: npm run test script: npm run test
# solidity-coverage fails at parsing 0.5.x code - stage: tests
# - stage: tests name: "Unit tests with coverage report"
# name: "Unit tests with coverage report" script: npm run test
# script: npm run test env: SOLIDITY_COVERAGE=true
# env: SOLIDITY_COVERAGE=true
- stage: tests - stage: tests
name: "Unit tests using solc nightly" name: "Unit tests using solc nightly"
......
# Changelog # 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`. * 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. * Version bump to avoid conflict in the npm registry.
## 2.1.0 (2019-04-01) ## 2.1.0 (2019-01-04)
### New features: ### New features:
* Now targeting the 0.5.x line of Solidity compilers. For 0.4.24 support, use version 2.0 of OpenZeppelin. * 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 { ...@@ -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 ## License
OpenZeppelin is released under the [MIT License](LICENSE). OpenZeppelin is released under the [MIT License](LICENSE).
\ No newline at end of file
...@@ -51,12 +51,15 @@ git checkout release-vX.Y.Z ...@@ -51,12 +51,15 @@ git checkout release-vX.Y.Z
git pull upstream 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`. 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 add package.json package-lock.json ethpm.json
git commit -m "Release vX.Y.Z" git commit -m "Release vX.Y.Z"
git tag -a vX.Y.Z git tag -a vX.Y.Z
git push upstream release-vX.Y.Z
git push upstream vX.Y.Z git push upstream vX.Y.Z
``` ```
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
/** /**
* @title Roles * @title Roles
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "../Roles.sol"; import "../Roles.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "../Roles.sol"; import "../Roles.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "../Roles.sol"; import "../Roles.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "../Roles.sol"; import "../Roles.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "../token/ERC20/IERC20.sol"; import "../token/ERC20/IERC20.sol";
...@@ -12,8 +12,8 @@ import "../utils/ReentrancyGuard.sol"; ...@@ -12,8 +12,8 @@ import "../utils/ReentrancyGuard.sol";
* allowing investors to purchase tokens with ether. This contract implements * allowing investors to purchase tokens with ether. This contract implements
* such functionality in its most fundamental form and can be extended to provide additional * such functionality in its most fundamental form and can be extended to provide additional
* functionality and/or custom behavior. * functionality and/or custom behavior.
* The external interface represents the basic interface for purchasing tokens, and conform * The external interface represents the basic interface for purchasing tokens, and conforms
* the base architecture for crowdsales. They are *not* intended to be modified / overridden. * 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 internal interface conforms the extensible and modifiable surface of crowdsales. Override
* the methods to add functionality. Consider using 'super' where appropriate to concatenate * the methods to add functionality. Consider using 'super' where appropriate to concatenate
* behavior. * behavior.
...@@ -66,7 +66,7 @@ contract Crowdsale is Initializable, ReentrancyGuard { ...@@ -66,7 +66,7 @@ contract Crowdsale is Initializable, ReentrancyGuard {
/** /**
* @dev fallback function ***DO NOT OVERRIDE*** * @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 * of 2300, which is not enough to call buyTokens. Consider calling
* buyTokens directly when purchasing tokens from a contract. * 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 "zos-lib/contracts/Initializable.sol";
import "../../math/SafeMath.sol"; import "../../math/SafeMath.sol";
...@@ -6,7 +6,7 @@ import "../validation/TimedCrowdsale.sol"; ...@@ -6,7 +6,7 @@ import "../validation/TimedCrowdsale.sol";
/** /**
* @title FinalizableCrowdsale * @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. * can do extra work after finishing.
*/ */
contract FinalizableCrowdsale is Initializable, TimedCrowdsale { contract FinalizableCrowdsale is Initializable, TimedCrowdsale {
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "../validation/TimedCrowdsale.sol"; import "../validation/TimedCrowdsale.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "../../math/SafeMath.sol"; import "../../math/SafeMath.sol";
...@@ -7,8 +7,8 @@ import "../../payment/escrow/RefundEscrow.sol"; ...@@ -7,8 +7,8 @@ import "../../payment/escrow/RefundEscrow.sol";
/** /**
* @title RefundableCrowdsale * @title RefundableCrowdsale
* @dev Extension of Crowdsale contract that adds a funding goal, and the possibility of users getting a refund if goal * @dev Extension of FinalizableCrowdsale contract that adds a funding goal, and the possibility of users
* is not met. * getting a refund if goal is not met.
* *
* Deprecated, use RefundablePostDeliveryCrowdsale instead. Note that if you allow tokens to be traded before the goal * 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 * 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"; import "zos-lib/contracts/Initializable.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "../Crowdsale.sol"; import "../Crowdsale.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "../Crowdsale.sol"; import "../Crowdsale.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "../validation/TimedCrowdsale.sol"; import "../validation/TimedCrowdsale.sol";
...@@ -31,7 +31,7 @@ contract IncreasingPriceCrowdsale is Initializable, TimedCrowdsale { ...@@ -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. * all calls to it are a mistake.
*/ */
function rate() public view returns (uint256) { function rate() public view returns (uint256) {
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "../../math/SafeMath.sol"; import "../../math/SafeMath.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "../../math/SafeMath.sol"; import "../../math/SafeMath.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "../../math/SafeMath.sol"; import "../../math/SafeMath.sol";
...@@ -15,6 +15,13 @@ contract TimedCrowdsale is Initializable, Crowdsale { ...@@ -15,6 +15,13 @@ contract TimedCrowdsale is Initializable, Crowdsale {
uint256 private _closingTime; 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. * @dev Reverts if not in crowdsale time range.
*/ */
modifier onlyWhileOpen { modifier onlyWhileOpen {
...@@ -82,5 +89,17 @@ contract TimedCrowdsale is Initializable, Crowdsale { ...@@ -82,5 +89,17 @@ contract TimedCrowdsale is Initializable, Crowdsale {
super._preValidatePurchase(beneficiary, weiAmount); 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; uint256[50] private ______gap;
} }
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../Crowdsale.sol"; import "../Crowdsale.sol";
import "../../access/roles/WhitelistedRole.sol"; import "../../access/roles/WhitelistedRole.sol";
...@@ -15,11 +15,11 @@ contract WhitelistCrowdsale is Initializable, WhitelistedRole, Crowdsale { ...@@ -15,11 +15,11 @@ contract WhitelistCrowdsale is Initializable, WhitelistedRole, Crowdsale {
} }
/** /**
* @dev Extend parent behavior requiring beneficiary to be whitelisted. Note that no * @dev Extend parent behavior requiring beneficiary to be whitelisted. Note that no
* restriction is imposed on the account sending the transaction. * restriction is imposed on the account sending the transaction.
* @param _beneficiary Token beneficiary * @param _beneficiary Token beneficiary
* @param _weiAmount Amount of wei contributed * @param _weiAmount Amount of wei contributed
*/ */
function _preValidatePurchase(address _beneficiary, uint256 _weiAmount) internal view { function _preValidatePurchase(address _beneficiary, uint256 _weiAmount) internal view {
require(isWhitelisted(_beneficiary)); require(isWhitelisted(_beneficiary));
super._preValidatePurchase(_beneficiary, _weiAmount); super._preValidatePurchase(_beneficiary, _weiAmount);
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
/** /**
* @title Elliptic curve signature operations * @title Elliptic curve signature operations
...@@ -14,16 +14,16 @@ library ECDSA { ...@@ -14,16 +14,16 @@ library ECDSA {
* @param signature bytes signature, the signature is generated using web3.eth.sign() * @param signature bytes signature, the signature is generated using web3.eth.sign()
*/ */
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
bytes32 r;
bytes32 s;
uint8 v;
// Check the signature length // Check the signature length
if (signature.length != 65) { if (signature.length != 65) {
return (address(0)); return (address(0));
} }
// Divide the signature in r, s and v variables // 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 // ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly. // currently is to use assembly.
// solhint-disable-next-line no-inline-assembly // solhint-disable-next-line no-inline-assembly
...@@ -33,17 +33,25 @@ library ECDSA { ...@@ -33,17 +33,25 @@ library ECDSA {
v := byte(0, mload(add(signature, 0x60))) v := byte(0, mload(add(signature, 0x60)))
} }
// Version of signature should be 27 or 28, but 0 and 1 are also possible versions // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
if (v < 27) { // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
v += 27; // 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) { if (v != 27 && v != 28) {
return (address(0)); return address(0);
} else {
return ecrecover(hash, v, r, s);
} }
// 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 * @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 "zos-lib/contracts/Initializable.sol";
import "../../token/ERC20/IERC20.sol"; import "../../token/ERC20/IERC20.sol";
...@@ -8,22 +8,20 @@ import "../../token/ERC20/IERC20.sol"; ...@@ -8,22 +8,20 @@ import "../../token/ERC20/IERC20.sol";
* @dev See https://eips.ethereum.org/EIPS/eip-1046 * @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 * @dev tokenURI must respond with a URI that implements https://eips.ethereum.org/EIPS/eip-1047
*/ */
contract ERC20TokenMetadata is Initializable, IERC20 { contract ERC20Metadata is Initializable {
function tokenURI() external view returns (string memory);
uint256[50] private ______gap;
}
contract ERC20WithMetadata is Initializable, ERC20TokenMetadata {
string private _tokenURI; string private _tokenURI;
function initialize(string memory tokenURI) public { function initialize(string memory tokenURI_) public {
_tokenURI = tokenURI; _setTokenURI(tokenURI_);
} }
function tokenURI() external view returns (string memory) { function tokenURI() external view returns (string memory) {
return _tokenURI; return _tokenURI;
} }
function _setTokenURI(string memory tokenURI_) internal {
_tokenURI = tokenURI_;
}
uint256[50] private ______gap; uint256[50] private ______gap;
} }
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "../token/ERC20/IERC20.sol"; import "../token/ERC20/IERC20.sol";
...@@ -18,7 +18,7 @@ import "../math/Math.sol"; ...@@ -18,7 +18,7 @@ import "../math/Math.sol";
* OpenZeppelin's ERC20Mintable, but the only functions that are needed are * OpenZeppelin's ERC20Mintable, but the only functions that are needed are
* `isMinter(address)` and `mint(address, amount)`. The migrator will check * `isMinter(address)` and `mint(address, amount)`. The migrator will check
* that it is a minter for the token. * 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. * is migrated, and remain there forever.
* Although this contract can be used in many different scenarios, the main * 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 * motivation was to provide a way to migrate ERC20 tokens into an upgradeable
...@@ -66,14 +66,14 @@ contract ERC20Migrator is Initializable { ...@@ -66,14 +66,14 @@ contract ERC20Migrator is Initializable {
/** /**
* @dev Begins the migration by setting which is the new token that will be * @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. * 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(address(newToken) != address(0)); require(address(newToken_) != address(0));
require(newToken.isMinter(address(this))); require(newToken_.isMinter(address(this)));
_newToken = newToken; _newToken = newToken_;
} }
/** /**
...@@ -83,6 +83,7 @@ contract ERC20Migrator is Initializable { ...@@ -83,6 +83,7 @@ contract ERC20Migrator is Initializable {
* @param amount amount of tokens to be migrated * @param amount amount of tokens to be migrated
*/ */
function migrate(address account, uint256 amount) public { function migrate(address account, uint256 amount) public {
require(address(_newToken) != address(0));
_legacyToken.safeTransferFrom(account, address(this), amount); _legacyToken.safeTransferFrom(account, address(this), amount);
_newToken.mint(account, 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 "zos-lib/contracts/Initializable.sol";
import "../access/roles/SignerRole.sol"; import "../access/roles/SignerRole.sol";
...@@ -30,7 +30,7 @@ import "../cryptography/ECDSA.sol"; ...@@ -30,7 +30,7 @@ import "../cryptography/ECDSA.sol";
* @notice A method that uses the `onlyValidSignatureAndData` modifier must make * @notice A method that uses the `onlyValidSignatureAndData` modifier must make
* the _signature parameter the "last" parameter. You cannot sign a message that * 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 * 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 * is ignored when validating. Also non fixed sized parameters make constructing
* the data in the signature much more complex. * the data in the signature much more complex.
* See https://ethereum.stackexchange.com/a/50616 for more details. * See https://ethereum.stackexchange.com/a/50616 for more details.
...@@ -57,7 +57,7 @@ contract SignatureBouncer is Initializable, SignerRole { ...@@ -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) { modifier onlyValidSignatureAndMethod(bytes memory signature) {
require(_isValidSignatureAndMethod(msg.sender, signature)); require(_isValidSignatureAndMethod(msg.sender, signature));
...@@ -65,7 +65,7 @@ contract SignatureBouncer is Initializable, SignerRole { ...@@ -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) { modifier onlyValidSignatureAndData(bytes memory signature) {
require(_isValidSignatureAndData(msg.sender, signature)); require(_isValidSignatureAndData(msg.sender, signature));
...@@ -73,7 +73,7 @@ contract SignatureBouncer is Initializable, SignerRole { ...@@ -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 * @return bool
*/ */
function _isValidSignature(address account, bytes memory signature) internal view returns (bool) { function _isValidSignature(address account, bytes memory signature) internal view returns (bool) {
...@@ -81,7 +81,7 @@ contract SignatureBouncer is Initializable, SignerRole { ...@@ -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 * @return bool
*/ */
function _isValidSignatureAndMethod(address account, bytes memory signature) internal view returns (bool) { function _isValidSignatureAndMethod(address account, bytes memory signature) internal view returns (bool) {
...@@ -93,10 +93,10 @@ contract SignatureBouncer is Initializable, SignerRole { ...@@ -93,10 +93,10 @@ contract SignatureBouncer is Initializable, SignerRole {
} }
/** /**
* @dev is the signature of `this + sender + methodId + params(s)` from a signer? * @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 * @notice the signature parameter of the method being validated must be the "last" parameter
* @return bool * @return bool
*/ */
function _isValidSignatureAndData(address account, bytes memory signature) internal view returns (bool) { function _isValidSignatureAndData(address account, bytes memory signature) internal view returns (bool) {
require(msg.data.length > _SIGNATURE_SIZE); require(msg.data.length > _SIGNATURE_SIZE);
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
/** /**
* @title SignedSafeMath * @title SignedSafeMath
...@@ -8,8 +8,8 @@ library SignedSafeMath { ...@@ -8,8 +8,8 @@ library SignedSafeMath {
int256 constant private INT256_MIN = -2**255; 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) { function mul(int256 a, int256 b) internal pure returns (int256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested. // benefit is lost if 'b' is also tested.
...@@ -27,8 +27,8 @@ library SignedSafeMath { ...@@ -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) { function div(int256 a, int256 b) internal pure returns (int256) {
require(b != 0); // Solidity only automatically asserts when dividing by 0 require(b != 0); // Solidity only automatically asserts when dividing by 0
require(!(b == -1 && a == INT256_MIN)); // This is the only case of overflow require(!(b == -1 && a == INT256_MIN)); // This is the only case of overflow
...@@ -39,8 +39,8 @@ library SignedSafeMath { ...@@ -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) { function sub(int256 a, int256 b) internal pure returns (int256) {
int256 c = a - b; int256 c = a - b;
require((b >= 0 && c <= a) || (b < 0 && c > a)); require((b >= 0 && c <= a) || (b < 0 && c > a));
...@@ -49,8 +49,8 @@ library SignedSafeMath { ...@@ -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) { function add(int256 a, int256 b) internal pure returns (int256) {
int256 c = a + b; int256 c = a + b;
require((b >= 0 && c >= a) || (b < 0 && c < a)); 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 "zos-lib/contracts/Initializable.sol";
import "../token/ERC20/SafeERC20.sol"; import "../token/ERC20/SafeERC20.sol";
...@@ -14,8 +14,8 @@ import "../math/SafeMath.sol"; ...@@ -14,8 +14,8 @@ import "../math/SafeMath.sol";
contract TokenVesting is Initializable, Ownable { 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 // 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, // 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 // it is recommended to avoid using short time durations (less than a minute). Typical vesting schemes, with a
// period of a year and a duration of four years, are safe to use. // cliff period of a year and a duration of four years, are safe to use.
// solhint-disable not-rely-on-time // solhint-disable not-rely-on-time
using SafeMath for uint256; using SafeMath for uint256;
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "../crowdsale/validation/CappedCrowdsale.sol"; import "../crowdsale/validation/CappedCrowdsale.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "../token/ERC20/ERC20.sol"; import "../token/ERC20/ERC20.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "./IERC165.sol"; import "./IERC165.sol";
...@@ -10,7 +10,7 @@ import "./IERC165.sol"; ...@@ -10,7 +10,7 @@ import "./IERC165.sol";
*/ */
contract ERC165 is Initializable, IERC165 { contract ERC165 is Initializable, IERC165 {
bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7; bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
/** /*
* 0x01ffc9a7 === * 0x01ffc9a7 ===
* bytes4(keccak256('supportsInterface(bytes4)')) * bytes4(keccak256('supportsInterface(bytes4)'))
*/ */
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
/** /**
* @title ERC165Checker * @title ERC165Checker
* @dev Use `using ERC165Checker for address`; to include this library * @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 { library ERC165Checker {
// As per the EIP-165 spec, no interface should ever match 0xffffffff // As per the EIP-165 spec, no interface should ever match 0xffffffff
bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff; bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;
bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7; bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
/** /*
* 0x01ffc9a7 === * 0x01ffc9a7 ===
* bytes4(keccak256('supportsInterface(bytes4)')) * bytes4(keccak256('supportsInterface(bytes4)'))
*/ */
...@@ -109,15 +109,15 @@ library ERC165Checker { ...@@ -109,15 +109,15 @@ library ERC165Checker {
mstore(output, 0x0) mstore(output, 0x0)
success := staticcall( success := staticcall(
30000, // 30k gas 30000, // 30k gas
account, // To addr account, // To addr
encodedParams_data, encodedParams_data,
encodedParams_size, encodedParams_size,
output, 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 * @title IERC165
* @dev https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md * @dev https://eips.ethereum.org/EIPS/eip-165
*/ */
interface IERC165 { interface IERC165 {
/** /**
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "../access/roles/PauserRole.sol"; import "../access/roles/PauserRole.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
/** /**
* @title Math * @title Math
...@@ -6,24 +6,24 @@ pragma solidity ^0.5.0; ...@@ -6,24 +6,24 @@ pragma solidity ^0.5.0;
*/ */
library Math { 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) { function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b; 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) { function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b; return a < b ? a : b;
} }
/** /**
* @dev Calculates the average of two numbers. Since these are integers, * @dev Calculates the average of two numbers. Since these are integers,
* averages of an even and odd number cannot be represented, and will be * averages of an even and odd number cannot be represented, and will be
* rounded down. * rounded down.
*/ */
function average(uint256 a, uint256 b) internal pure returns (uint256) { function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow, so we distribute // (a + b) / 2 can overflow, so we distribute
return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2); return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
/** /**
* @title SafeMath * @title SafeMath
...@@ -6,8 +6,8 @@ pragma solidity ^0.5.0; ...@@ -6,8 +6,8 @@ pragma solidity ^0.5.0;
*/ */
library SafeMath { 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) { function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested. // benefit is lost if 'b' is also tested.
...@@ -23,8 +23,8 @@ library SafeMath { ...@@ -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) { function div(uint256 a, uint256 b) internal pure returns (uint256) {
// Solidity only automatically asserts when dividing by 0 // Solidity only automatically asserts when dividing by 0
require(b > 0); require(b > 0);
...@@ -35,8 +35,8 @@ library SafeMath { ...@@ -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) { function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a); require(b <= a);
uint256 c = a - b; uint256 c = a - b;
...@@ -45,8 +45,8 @@ library SafeMath { ...@@ -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) { function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b; uint256 c = a + b;
require(c >= a); require(c >= a);
...@@ -55,9 +55,9 @@ library SafeMath { ...@@ -55,9 +55,9 @@ library SafeMath {
} }
/** /**
* @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo), * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
* reverts when dividing by zero. * reverts when dividing by zero.
*/ */
function mod(uint256 a, uint256 b) internal pure returns (uint256) { function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0); require(b != 0);
return a % b; return a % b;
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
contract Acknowledger { contract Acknowledger {
event AcknowledgeFoo(uint256 a); event AcknowledgeFoo(uint256 a);
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../utils/Address.sol"; import "../utils/Address.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../token/ERC20/IERC20.sol"; import "../token/ERC20/IERC20.sol";
import "../crowdsale/emission/AllowanceCrowdsale.sol"; import "../crowdsale/emission/AllowanceCrowdsale.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../utils/Arrays.sol"; import "../utils/Arrays.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../token/ERC20/IERC20.sol"; import "../token/ERC20/IERC20.sol";
import "../crowdsale/validation/CappedCrowdsale.sol"; import "../crowdsale/validation/CappedCrowdsale.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../access/roles/CapperRole.sol"; import "../access/roles/CapperRole.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../payment/escrow/ConditionalEscrow.sol"; 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"; import "../crowdsale/Crowdsale.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../cryptography/ECDSA.sol"; import "../cryptography/ECDSA.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../../introspection/IERC165.sol"; 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 * > Any attempts to make state-changing operations inside an execution instance with STATIC set to true will instead
* throw an exception. * throw an exception.
* > These operations include [...], LOG0, LOG1, LOG2, [...] * > These operations include [...], LOG0, LOG1, LOG2, [...]
...@@ -13,7 +14,7 @@ import "../../introspection/IERC165.sol"; ...@@ -13,7 +14,7 @@ import "../../introspection/IERC165.sol";
*/ */
contract SupportsInterfaceWithLookupMock is IERC165 { contract SupportsInterfaceWithLookupMock is IERC165 {
bytes4 public constant INTERFACE_ID_ERC165 = 0x01ffc9a7; bytes4 public constant INTERFACE_ID_ERC165 = 0x01ffc9a7;
/** /*
* 0x01ffc9a7 === * 0x01ffc9a7 ===
* bytes4(keccak256('supportsInterface(bytes4)')) * bytes4(keccak256('supportsInterface(bytes4)'))
*/ */
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
contract ERC165NotSupported { contract ERC165NotSupported {
// solhint-disable-previous-line no-empty-blocks // solhint-disable-previous-line no-empty-blocks
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../introspection/ERC165Checker.sol"; import "../introspection/ERC165Checker.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../introspection/ERC165.sol"; import "../introspection/ERC165.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../token/ERC20/ERC20Burnable.sol"; import "../token/ERC20/ERC20Burnable.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../token/ERC20/ERC20.sol"; import "../token/ERC20/ERC20.sol";
import "../token/ERC20/ERC20Detailed.sol"; import "../token/ERC20/ERC20Detailed.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.0;
import "../token/ERC20/ERC20.sol"; 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 { 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 "../token/ERC20/ERC20Mintable.sol";
import "./MinterRoleMock.sol"; import "./MinterRoleMock.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../token/ERC20/ERC20.sol"; import "../token/ERC20/ERC20.sol";
...@@ -19,4 +19,8 @@ contract ERC20Mock is ERC20 { ...@@ -19,4 +19,8 @@ contract ERC20Mock is ERC20 {
function burnFrom(address account, uint256 amount) public { function burnFrom(address account, uint256 amount) public {
_burnFrom(account, amount); _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 "../token/ERC20/ERC20Pausable.sol";
import "./PauserRoleMock.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/ERC721Full.sol";
import "../token/ERC721/ERC721Mintable.sol"; import "../token/ERC721/ERC721Mintable.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../token/ERC721/ERC721Full.sol"; import "../token/ERC721/ERC721Full.sol";
import "../token/ERC721/ERC721Mintable.sol"; import "../token/ERC721/ERC721Mintable.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../token/ERC721/ERC721.sol"; import "../token/ERC721/ERC721.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../token/ERC721/ERC721Pausable.sol"; import "../token/ERC721/ERC721Pausable.sol";
import "./PauserRoleMock.sol"; import "./PauserRoleMock.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../token/ERC721/IERC721Receiver.sol"; import "../token/ERC721/IERC721Receiver.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
contract EventEmitter { contract EventEmitter {
event Argumentless(); event Argumentless();
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
contract Failer { contract Failer {
uint256[] private array; uint256[] private array;
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../token/ERC20/IERC20.sol"; import "../token/ERC20/IERC20.sol";
import "../crowdsale/distribution/FinalizableCrowdsale.sol"; import "../crowdsale/distribution/FinalizableCrowdsale.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../crowdsale/price/IncreasingPriceCrowdsale.sol"; import "../crowdsale/price/IncreasingPriceCrowdsale.sol";
import "../math/SafeMath.sol"; import "../math/SafeMath.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../token/ERC20/IERC20.sol"; import "../token/ERC20/IERC20.sol";
import "../crowdsale/validation/IndividuallyCappedCrowdsale.sol"; import "../crowdsale/validation/IndividuallyCappedCrowdsale.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../math/Math.sol"; import "../math/Math.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import { MerkleProof } from "../cryptography/MerkleProof.sol"; import { MerkleProof } from "../cryptography/MerkleProof.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../token/ERC20/ERC20Mintable.sol"; import "../token/ERC20/ERC20Mintable.sol";
import "../crowdsale/emission/MintedCrowdsale.sol"; import "../crowdsale/emission/MintedCrowdsale.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../access/roles/MinterRole.sol"; import "../access/roles/MinterRole.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../ownership/Ownable.sol"; import "../ownership/Ownable.sol";
/** /**
* @title Ownable interface id calculator. * @title Ownable interface id calculator.
* @dev See the EIP165 specification for more information: * @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 { contract OwnableInterfaceId {
function getInterfaceId() public pure returns (bytes4) { function getInterfaceId() public pure returns (bytes4) {
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../ownership/Ownable.sol"; import "../ownership/Ownable.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../token/ERC20/ERC20.sol"; import "../token/ERC20/ERC20.sol";
import "../crowdsale/validation/PausableCrowdsale.sol"; import "../crowdsale/validation/PausableCrowdsale.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../lifecycle/Pausable.sol"; import "../lifecycle/Pausable.sol";
import "./PauserRoleMock.sol"; import "./PauserRoleMock.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../access/roles/PauserRole.sol"; import "../access/roles/PauserRole.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../token/ERC20/IERC20.sol"; import "../token/ERC20/IERC20.sol";
import "../crowdsale/distribution/PostDeliveryCrowdsale.sol"; import "../crowdsale/distribution/PostDeliveryCrowdsale.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../payment/PullPayment.sol"; import "../payment/PullPayment.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
contract ReentrancyAttack { contract ReentrancyAttack {
function callSender(bytes4 data) public { function callSender(bytes4 data) public {
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../utils/ReentrancyGuard.sol"; import "../utils/ReentrancyGuard.sol";
import "./ReentrancyAttack.sol"; import "./ReentrancyAttack.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../token/ERC20/IERC20.sol"; import "../token/ERC20/IERC20.sol";
import "../crowdsale/distribution/RefundableCrowdsale.sol"; import "../crowdsale/distribution/RefundableCrowdsale.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../token/ERC20/IERC20.sol"; import "../token/ERC20/IERC20.sol";
import "../crowdsale/distribution/RefundablePostDeliveryCrowdsale.sol"; import "../crowdsale/distribution/RefundablePostDeliveryCrowdsale.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../access/Roles.sol"; import "../access/Roles.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../token/ERC20/IERC20.sol"; import "../token/ERC20/IERC20.sol";
import "../token/ERC20/SafeERC20.sol"; import "../token/ERC20/SafeERC20.sol";
contract ERC20FailingMock { contract ERC20ReturnFalseMock {
uint256 private _allowance; 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) { function transfer(address, uint256) public returns (bool) {
_dummy = 0;
return false; return false;
} }
function transferFrom(address, address, uint256) public returns (bool) { function transferFrom(address, address, uint256) public returns (bool) {
_dummy = 0;
return false; return false;
} }
function approve(address, uint256) public returns (bool) { function approve(address, uint256) public returns (bool) {
_dummy = 0;
return false; return false;
} }
function allowance(address, address) public view returns (uint256) { function allowance(address, address) public view returns (uint256) {
require(_dummy == 0);
return 0; return 0;
} }
} }
contract ERC20SucceedingMock { contract ERC20ReturnTrueMock {
uint256 private _allowance; 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) { function transfer(address, uint256) public returns (bool) {
_dummy = 0;
return true; return true;
} }
function transferFrom(address, address, uint256) public returns (bool) { function transferFrom(address, address, uint256) public returns (bool) {
_dummy = 0;
return true; return true;
} }
function approve(address, uint256) public returns (bool) { function approve(address, uint256) public returns (bool) {
_dummy = 0;
return true; return true;
} }
function setAllowance(uint256 allowance_) public { function setAllowance(uint256 allowance_) public {
_allowance = allowance_; _allowances[msg.sender] = allowance_;
} }
function allowance(address, address) public view returns (uint256) { function allowance(address owner, address) public view returns (uint256) {
return _allowance; return _allowances[owner];
} }
} }
contract SafeERC20Helper { contract ERC20NoReturnMock {
using SafeERC20 for IERC20; mapping (address => uint256) private _allowances;
IERC20 private _failing; // IERC20's functions are not pure, but these mock implementations are: to prevent Solidity from issuing warnings,
IERC20 private _succeeding; // we write to a dummy state variable.
uint256 private _dummy;
constructor () public { function transfer(address, uint256) public {
_failing = IERC20(address(new ERC20FailingMock())); _dummy = 0;
_succeeding = IERC20(address(new ERC20SucceedingMock()));
} }
function doFailingTransfer() public { function transferFrom(address, address, uint256) public {
_failing.safeTransfer(address(0), 0); _dummy = 0;
} }
function doFailingTransferFrom() public { function approve(address, uint256) public {
_failing.safeTransferFrom(address(0), address(0), 0); _dummy = 0;
} }
function doFailingApprove() public { function setAllowance(uint256 allowance_) public {
_failing.safeApprove(address(0), 0); _allowances[msg.sender] = allowance_;
} }
function doFailingIncreaseAllowance() public { function allowance(address owner, address) public view returns (uint256) {
_failing.safeIncreaseAllowance(address(0), 0); return _allowances[owner];
} }
}
contract SafeERC20Wrapper {
using SafeERC20 for IERC20;
IERC20 private _token;
function doFailingDecreaseAllowance() public { constructor (IERC20 token) public {
_failing.safeDecreaseAllowance(address(0), 0); _token = token;
} }
function doSucceedingTransfer() public { function transfer() public {
_succeeding.safeTransfer(address(0), 0); _token.safeTransfer(address(0), 0);
} }
function doSucceedingTransferFrom() public { function transferFrom() public {
_succeeding.safeTransferFrom(address(0), address(0), 0); _token.safeTransferFrom(address(0), address(0), 0);
} }
function doSucceedingApprove(uint256 amount) public { function approve(uint256 amount) public {
_succeeding.safeApprove(address(0), amount); _token.safeApprove(address(0), amount);
} }
function doSucceedingIncreaseAllowance(uint256 amount) public { function increaseAllowance(uint256 amount) public {
_succeeding.safeIncreaseAllowance(address(0), amount); _token.safeIncreaseAllowance(address(0), amount);
} }
function doSucceedingDecreaseAllowance(uint256 amount) public { function decreaseAllowance(uint256 amount) public {
_succeeding.safeDecreaseAllowance(address(0), amount); _token.safeDecreaseAllowance(address(0), amount);
} }
function setAllowance(uint256 allowance_) public { function setAllowance(uint256 allowance_) public {
ERC20SucceedingMock(address(_succeeding)).setAllowance(allowance_); ERC20ReturnTrueMock(address(_token)).setAllowance(allowance_);
} }
function allowance() public view returns (uint256) { 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"; import "../math/SafeMath.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../ownership/Secondary.sol"; import "../ownership/Secondary.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../drafts/SignatureBouncer.sol"; import "../drafts/SignatureBouncer.sol";
import "./SignerRoleMock.sol"; import "./SignerRoleMock.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../drafts/SignedSafeMath.sol"; import "../drafts/SignedSafeMath.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../access/roles/SignerRole.sol"; import "../access/roles/SignerRole.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../token/ERC20/IERC20.sol"; import "../token/ERC20/IERC20.sol";
import "../crowdsale/validation/TimedCrowdsale.sol"; import "../crowdsale/validation/TimedCrowdsale.sol";
...@@ -10,4 +10,8 @@ contract TimedCrowdsaleImpl is TimedCrowdsale { ...@@ -10,4 +10,8 @@ contract TimedCrowdsaleImpl is TimedCrowdsale {
Crowdsale.initialize(rate, wallet, token); Crowdsale.initialize(rate, wallet, token);
TimedCrowdsale.initialize(openingTime, closingTime); 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"; import "../access/roles/WhitelistAdminRole.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../token/ERC20/IERC20.sol"; import "../token/ERC20/IERC20.sol";
import "../crowdsale/validation/WhitelistCrowdsale.sol"; import "../crowdsale/validation/WhitelistCrowdsale.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../access/roles/WhitelistedRole.sol"; import "../access/roles/WhitelistedRole.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
...@@ -45,9 +45,10 @@ contract Ownable is Initializable { ...@@ -45,9 +45,10 @@ contract Ownable is Initializable {
/** /**
* @dev Allows the current owner to relinquish control of the contract. * @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` * It will not be possible to call the functions with the `onlyOwner`
* modifier anymore. * 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 { function renounceOwnership() public onlyOwner {
emit OwnershipTransferred(_owner, address(0)); emit OwnershipTransferred(_owner, address(0));
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
...@@ -21,26 +21,26 @@ contract PullPayment is Initializable { ...@@ -21,26 +21,26 @@ contract PullPayment is Initializable {
} }
/** /**
* @dev Withdraw accumulated balance. * @dev Withdraw accumulated balance.
* @param payee Whose balance will be withdrawn. * @param payee Whose balance will be withdrawn.
*/ */
function withdrawPayments(address payable payee) public { function withdrawPayments(address payable payee) public {
_escrow.withdraw(payee); _escrow.withdraw(payee);
} }
/** /**
* @dev Returns the credit owed to an address. * @dev Returns the credit owed to an address.
* @param dest The creditor's address. * @param dest The creditor's address.
*/ */
function payments(address dest) public view returns (uint256) { function payments(address dest) public view returns (uint256) {
return _escrow.depositsOf(dest); return _escrow.depositsOf(dest);
} }
/** /**
* @dev Called by the payer to store the sent amount as credit to be pulled. * @dev Called by the payer to store the sent amount as credit to be pulled.
* @param dest The destination address of the funds. * @param dest The destination address of the funds.
* @param amount The amount to transfer. * @param amount The amount to transfer.
*/ */
function _asyncTransfer(address dest, uint256 amount) internal { function _asyncTransfer(address dest, uint256 amount) internal {
_escrow.deposit.value(amount)(dest); _escrow.deposit.value(amount)(dest);
} }
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "./Escrow.sol"; import "./Escrow.sol";
...@@ -13,10 +13,10 @@ contract ConditionalEscrow is Initializable, Escrow { ...@@ -13,10 +13,10 @@ contract ConditionalEscrow is Initializable, Escrow {
} }
/** /**
* @dev Returns whether an address is allowed to withdraw their funds. To be * @dev Returns whether an address is allowed to withdraw their funds. To be
* implemented by derived contracts. * implemented by derived contracts.
* @param payee The destination address of the funds. * @param payee The destination address of the funds.
*/ */
function withdrawalAllowed(address payee) public view returns (bool); function withdrawalAllowed(address payee) public view returns (bool);
function withdraw(address payable payee) public { function withdraw(address payable payee) public {
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../../math/SafeMath.sol"; import "../../math/SafeMath.sol";
import "../../ownership/Secondary.sol"; import "../../ownership/Secondary.sol";
/** /**
* @title Escrow * @title Escrow
* @dev Base escrow contract, holds funds designated for a payee until they * @dev Base escrow contract, holds funds designated for a payee until they
* withdraw them. * withdraw them.
* @dev Intended usage: This contract (and derived escrow contracts) should be a * @dev Intended usage: This contract (and derived escrow contracts) should be a
* standalone contract, that only interacts with the contract that instantiated * standalone contract, that only interacts with the contract that instantiated
* it. That way, it is guaranteed that all Ether will be handled according to * 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 * 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 * transfers in the inheritance tree. The contract that uses the escrow as its
* payment method should be its primary, and provide public methods redirecting * payment method should be its primary, and provide public methods redirecting
* to the escrow's deposit and withdraw. * to the escrow's deposit and withdraw.
*/ */
contract Escrow is Initializable, Secondary { contract Escrow is Initializable, Secondary {
using SafeMath for uint256; using SafeMath for uint256;
...@@ -32,9 +32,9 @@ contract Escrow is Initializable, Secondary { ...@@ -32,9 +32,9 @@ contract Escrow is Initializable, Secondary {
} }
/** /**
* @dev Stores the sent amount as credit to be withdrawn. * @dev Stores the sent amount as credit to be withdrawn.
* @param payee The destination address of the funds. * @param payee The destination address of the funds.
*/ */
function deposit(address payee) public onlyPrimary payable { function deposit(address payee) public onlyPrimary payable {
uint256 amount = msg.value; uint256 amount = msg.value;
_deposits[payee] = _deposits[payee].add(amount); _deposits[payee] = _deposits[payee].add(amount);
...@@ -43,9 +43,9 @@ contract Escrow is Initializable, Secondary { ...@@ -43,9 +43,9 @@ contract Escrow is Initializable, Secondary {
} }
/** /**
* @dev Withdraw accumulated balance for a payee. * @dev Withdraw accumulated balance for a payee.
* @param payee The address whose funds will be withdrawn and transferred to. * @param payee The address whose funds will be withdrawn and transferred to.
*/ */
function withdraw(address payable payee) public onlyPrimary { function withdraw(address payable payee) public onlyPrimary {
uint256 payment = _deposits[payee]; uint256 payment = _deposits[payee];
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
...@@ -87,7 +87,7 @@ contract RefundEscrow is Initializable, ConditionalEscrow { ...@@ -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. * 'payee' argument, but we ignore it here since the condition is global, not per-payee.
*/ */
function withdrawalAllowed(address) public view returns (bool) { function withdrawalAllowed(address) public view returns (bool) {
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "./IERC20.sol"; import "./IERC20.sol";
...@@ -8,7 +8,7 @@ import "../../math/SafeMath.sol"; ...@@ -8,7 +8,7 @@ import "../../math/SafeMath.sol";
* @title Standard ERC20 token * @title Standard ERC20 token
* *
* @dev Implementation of the basic standard 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: * Originally based on code by FirstBlood:
* https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol * https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
* *
...@@ -26,17 +26,17 @@ contract ERC20 is Initializable, IERC20 { ...@@ -26,17 +26,17 @@ contract ERC20 is Initializable, IERC20 {
uint256 private _totalSupply; uint256 private _totalSupply;
/** /**
* @dev Total number of tokens in existence * @dev Total number of tokens in existence
*/ */
function totalSupply() public view returns (uint256) { function totalSupply() public view returns (uint256) {
return _totalSupply; return _totalSupply;
} }
/** /**
* @dev Gets the balance of the specified address. * @dev Gets the balance of the specified address.
* @param owner The address to query the balance of. * @param owner The address to query the balance of.
* @return An uint256 representing the amount owned by the passed address. * @return A uint256 representing the amount owned by the passed address.
*/ */
function balanceOf(address owner) public view returns (uint256) { function balanceOf(address owner) public view returns (uint256) {
return _balances[owner]; return _balances[owner];
} }
...@@ -52,10 +52,10 @@ contract ERC20 is Initializable, IERC20 { ...@@ -52,10 +52,10 @@ contract ERC20 is Initializable, IERC20 {
} }
/** /**
* @dev Transfer token for a specified address * @dev Transfer token to a specified address
* @param to The address to transfer to. * @param to The address to transfer to.
* @param value The amount to be transferred. * @param value The amount to be transferred.
*/ */
function transfer(address to, uint256 value) public returns (bool) { function transfer(address to, uint256 value) public returns (bool) {
_transfer(msg.sender, to, value); _transfer(msg.sender, to, value);
return true; return true;
...@@ -71,10 +71,7 @@ contract ERC20 is Initializable, IERC20 { ...@@ -71,10 +71,7 @@ contract ERC20 is Initializable, IERC20 {
* @param value The amount of tokens to be spent. * @param value The amount of tokens to be spent.
*/ */
function approve(address spender, uint256 value) public returns (bool) { function approve(address spender, uint256 value) public returns (bool) {
require(spender != address(0)); _approve(msg.sender, spender, value);
_allowed[msg.sender][spender] = value;
emit Approval(msg.sender, spender, value);
return true; return true;
} }
...@@ -87,15 +84,14 @@ contract ERC20 is Initializable, IERC20 { ...@@ -87,15 +84,14 @@ contract ERC20 is Initializable, IERC20 {
* @param value uint256 the amount of tokens to be transferred * @param value uint256 the amount of tokens to be transferred
*/ */
function transferFrom(address from, address to, uint256 value) public returns (bool) { 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); _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; return true;
} }
/** /**
* @dev Increase the amount of tokens that an owner allowed to a spender. * @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 * allowed value is better to use this function to avoid 2 calls (and wait until
* the first transaction is mined) * the first transaction is mined)
* From MonolithDAO Token.sol * From MonolithDAO Token.sol
...@@ -104,16 +100,13 @@ contract ERC20 is Initializable, IERC20 { ...@@ -104,16 +100,13 @@ contract ERC20 is Initializable, IERC20 {
* @param addedValue The amount of tokens to increase the allowance by. * @param addedValue The amount of tokens to increase the allowance by.
*/ */
function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
require(spender != address(0)); _approve(msg.sender, spender, _allowed[msg.sender][spender].add(addedValue));
_allowed[msg.sender][spender] = _allowed[msg.sender][spender].add(addedValue);
emit Approval(msg.sender, spender, _allowed[msg.sender][spender]);
return true; return true;
} }
/** /**
* @dev Decrease the amount of tokens that an owner allowed to a spender. * @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 * allowed value is better to use this function to avoid 2 calls (and wait until
* the first transaction is mined) * the first transaction is mined)
* From MonolithDAO Token.sol * From MonolithDAO Token.sol
...@@ -122,19 +115,16 @@ contract ERC20 is Initializable, IERC20 { ...@@ -122,19 +115,16 @@ contract ERC20 is Initializable, IERC20 {
* @param subtractedValue The amount of tokens to decrease the allowance by. * @param subtractedValue The amount of tokens to decrease the allowance by.
*/ */
function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
require(spender != address(0)); _approve(msg.sender, spender, _allowed[msg.sender][spender].sub(subtractedValue));
_allowed[msg.sender][spender] = _allowed[msg.sender][spender].sub(subtractedValue);
emit Approval(msg.sender, spender, _allowed[msg.sender][spender]);
return true; return true;
} }
/** /**
* @dev Transfer token for a specified addresses * @dev Transfer token for a specified addresses
* @param from The address to transfer from. * @param from The address to transfer from.
* @param to The address to transfer to. * @param to The address to transfer to.
* @param value The amount to be transferred. * @param value The amount to be transferred.
*/ */
function _transfer(address from, address to, uint256 value) internal { function _transfer(address from, address to, uint256 value) internal {
require(to != address(0)); require(to != address(0));
...@@ -173,6 +163,20 @@ contract ERC20 is Initializable, IERC20 { ...@@ -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 * @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 * account, deducting from the sender's allowance for said account. Uses the
* internal burn function. * internal burn function.
...@@ -181,9 +185,8 @@ contract ERC20 is Initializable, IERC20 { ...@@ -181,9 +185,8 @@ contract ERC20 is Initializable, IERC20 {
* @param value The amount that will be burnt. * @param value The amount that will be burnt.
*/ */
function _burnFrom(address account, uint256 value) internal { function _burnFrom(address account, uint256 value) internal {
_allowed[account][msg.sender] = _allowed[account][msg.sender].sub(value);
_burn(account, 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; uint256[50] private ______gap;
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "./ERC20.sol"; import "./ERC20.sol";
...@@ -18,8 +18,8 @@ contract ERC20Burnable is Initializable, ERC20 { ...@@ -18,8 +18,8 @@ contract ERC20Burnable is Initializable, ERC20 {
/** /**
* @dev Burns a specific amount of tokens from the target address and decrements allowance * @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 from address The account whose tokens will be burned.
* @param value uint256 The amount of token to be burned * @param value uint256 The amount of token to be burned.
*/ */
function burnFrom(address from, uint256 value) public { function burnFrom(address from, uint256 value) public {
_burnFrom(from, value); _burnFrom(from, value);
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "./ERC20Mintable.sol"; import "./ERC20Mintable.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "./IERC20.sol"; import "./IERC20.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "./ERC20.sol"; import "./ERC20.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "./ERC20.sol"; import "./ERC20.sol";
...@@ -7,7 +7,7 @@ import "../../lifecycle/Pausable.sol"; ...@@ -7,7 +7,7 @@ import "../../lifecycle/Pausable.sol";
/** /**
* @title Pausable token * @title Pausable token
* @dev ERC20 modified with pausable transfers. * @dev ERC20 modified with pausable transfers.
**/ */
contract ERC20Pausable is Initializable, ERC20, Pausable { contract ERC20Pausable is Initializable, ERC20, Pausable {
function initialize(address sender) public initializer { function initialize(address sender) public initializer {
Pausable.initialize(sender); Pausable.initialize(sender);
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
/** /**
* @title ERC20 interface * @title ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/20 * @dev see https://eips.ethereum.org/EIPS/eip-20
*/ */
interface IERC20 { interface IERC20 {
function transfer(address to, uint256 value) external returns (bool); function transfer(address to, uint256 value) external returns (bool);
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "./IERC20.sol"; import "./IERC20.sol";
import "../../math/SafeMath.sol"; import "../../math/SafeMath.sol";
import "../../utils/Address.sol";
/** /**
* @title SafeERC20 * @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, * 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. * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/ */
library SafeERC20 { library SafeERC20 {
using SafeMath for uint256; using SafeMath for uint256;
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal { 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 { 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 { function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance, // safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use // or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance' // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require((value == 0) || (token.allowance(msg.sender, spender) == 0)); require((value == 0) || (token.allowance(address(this), spender) == 0));
require(token.approve(spender, value)); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
} }
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).add(value); 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 { function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).sub(value); 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 "zos-lib/contracts/Initializable.sol";
import "./SafeERC20.sol"; import "./SafeERC20.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "./IERC721.sol"; import "./IERC721.sol";
import "./IERC721Receiver.sol"; import "./IERC721Receiver.sol";
import "../../math/SafeMath.sol"; import "../../math/SafeMath.sol";
import "../../utils/Address.sol"; import "../../utils/Address.sol";
import "../../drafts/Counters.sol";
import "../../introspection/ERC165.sol"; import "../../introspection/ERC165.sol";
/** /**
* @title ERC721 Non-Fungible Token Standard basic implementation * @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 { contract ERC721 is Initializable, ERC165, IERC721 {
using SafeMath for uint256; using SafeMath for uint256;
using Address for address; using Address for address;
using Counters for Counters.Counter;
// Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
// which can be also obtained as `IERC721Receiver(0).onERC721Received.selector` // which can be also obtained as `IERC721Receiver(0).onERC721Received.selector`
...@@ -26,7 +28,7 @@ contract ERC721 is Initializable, ERC165, IERC721 { ...@@ -26,7 +28,7 @@ contract ERC721 is Initializable, ERC165, IERC721 {
mapping (uint256 => address) private _tokenApprovals; mapping (uint256 => address) private _tokenApprovals;
// Mapping from owner to number of owned token // 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 from owner to operator approvals
mapping (address => mapping (address => bool)) private _operatorApprovals; mapping (address => mapping (address => bool)) private _operatorApprovals;
...@@ -63,13 +65,13 @@ contract ERC721 is Initializable, ERC165, IERC721 { ...@@ -63,13 +65,13 @@ contract ERC721 is Initializable, ERC165, IERC721 {
*/ */
function balanceOf(address owner) public view returns (uint256) { function balanceOf(address owner) public view returns (uint256) {
require(owner != address(0)); require(owner != address(0));
return _ownedTokensCount[owner]; return _ownedTokensCount[owner].current();
} }
/** /**
* @dev Gets the owner of the specified token ID * @dev Gets the owner of the specified token ID
* @param tokenId uint256 ID of the token to query the owner of * @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) { function ownerOf(uint256 tokenId) public view returns (address) {
address owner = _tokenOwner[tokenId]; address owner = _tokenOwner[tokenId];
...@@ -130,11 +132,11 @@ contract ERC721 is Initializable, ERC165, IERC721 { ...@@ -130,11 +132,11 @@ contract ERC721 is Initializable, ERC165, IERC721 {
/** /**
* @dev Transfers the ownership of a given token ID to another address * @dev Transfers the ownership of a given token ID to another address
* Usage of this method is discouraged, use `safeTransferFrom` whenever possible * 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 from current owner of the token
* @param to address to receive the ownership of the given token ID * @param to address to receive the ownership of the given token ID
* @param tokenId uint256 ID of the token to be transferred * @param tokenId uint256 ID of the token to be transferred
*/ */
function transferFrom(address from, address to, uint256 tokenId) public { function transferFrom(address from, address to, uint256 tokenId) public {
require(_isApprovedOrOwner(msg.sender, tokenId)); require(_isApprovedOrOwner(msg.sender, tokenId));
...@@ -147,12 +149,11 @@ contract ERC721 is Initializable, ERC165, IERC721 { ...@@ -147,12 +149,11 @@ contract ERC721 is Initializable, ERC165, IERC721 {
* which is called upon a safe transfer, and return the magic value * which is called upon a safe transfer, and return the magic value
* `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise, * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
* the transfer is reverted. * 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 from current owner of the token
* @param to address to receive the ownership of the given token ID * @param to address to receive the ownership of the given token ID
* @param tokenId uint256 ID of the token to be transferred * @param tokenId uint256 ID of the token to be transferred
*/ */
function safeTransferFrom(address from, address to, uint256 tokenId) public { function safeTransferFrom(address from, address to, uint256 tokenId) public {
safeTransferFrom(from, to, tokenId, ""); safeTransferFrom(from, to, tokenId, "");
} }
...@@ -163,7 +164,7 @@ contract ERC721 is Initializable, ERC165, IERC721 { ...@@ -163,7 +164,7 @@ contract ERC721 is Initializable, ERC165, IERC721 {
* which is called upon a safe transfer, and return the magic value * which is called upon a safe transfer, and return the magic value
* `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise, * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
* the transfer is reverted. * 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 from current owner of the token
* @param to address to receive the ownership of the given token ID * @param to address to receive the ownership of the given token ID
* @param tokenId uint256 ID of the token to be transferred * @param tokenId uint256 ID of the token to be transferred
...@@ -177,7 +178,7 @@ contract ERC721 is Initializable, ERC165, IERC721 { ...@@ -177,7 +178,7 @@ contract ERC721 is Initializable, ERC165, IERC721 {
/** /**
* @dev Returns whether the specified token exists * @dev Returns whether the specified token exists
* @param tokenId uint256 ID of the token to query the existence of * @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) { function _exists(uint256 tokenId) internal view returns (bool) {
address owner = _tokenOwner[tokenId]; address owner = _tokenOwner[tokenId];
...@@ -189,7 +190,7 @@ contract ERC721 is Initializable, ERC165, IERC721 { ...@@ -189,7 +190,7 @@ contract ERC721 is Initializable, ERC165, IERC721 {
* @param spender address of the spender to query * @param spender address of the spender to query
* @param tokenId uint256 ID of the token to be transferred * @param tokenId uint256 ID of the token to be transferred
* @return bool whether the msg.sender is approved for the given token ID, * @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) { function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) {
address owner = ownerOf(tokenId); address owner = ownerOf(tokenId);
...@@ -207,7 +208,7 @@ contract ERC721 is Initializable, ERC165, IERC721 { ...@@ -207,7 +208,7 @@ contract ERC721 is Initializable, ERC165, IERC721 {
require(!_exists(tokenId)); require(!_exists(tokenId));
_tokenOwner[tokenId] = to; _tokenOwner[tokenId] = to;
_ownedTokensCount[to] = _ownedTokensCount[to].add(1); _ownedTokensCount[to].increment();
emit Transfer(address(0), to, tokenId); emit Transfer(address(0), to, tokenId);
} }
...@@ -224,7 +225,7 @@ contract ERC721 is Initializable, ERC165, IERC721 { ...@@ -224,7 +225,7 @@ contract ERC721 is Initializable, ERC165, IERC721 {
_clearApproval(tokenId); _clearApproval(tokenId);
_ownedTokensCount[owner] = _ownedTokensCount[owner].sub(1); _ownedTokensCount[owner].decrement();
_tokenOwner[tokenId] = address(0); _tokenOwner[tokenId] = address(0);
emit Transfer(owner, address(0), tokenId); emit Transfer(owner, address(0), tokenId);
...@@ -245,15 +246,15 @@ contract ERC721 is Initializable, ERC165, IERC721 { ...@@ -245,15 +246,15 @@ contract ERC721 is Initializable, ERC165, IERC721 {
* @param from current owner of the token * @param from current owner of the token
* @param to address to receive the ownership of the given token ID * @param to address to receive the ownership of the given token ID
* @param tokenId uint256 ID of the token to be transferred * @param tokenId uint256 ID of the token to be transferred
*/ */
function _transferFrom(address from, address to, uint256 tokenId) internal { function _transferFrom(address from, address to, uint256 tokenId) internal {
require(ownerOf(tokenId) == from); require(ownerOf(tokenId) == from);
require(to != address(0)); require(to != address(0));
_clearApproval(tokenId); _clearApproval(tokenId);
_ownedTokensCount[from] = _ownedTokensCount[from].sub(1); _ownedTokensCount[from].decrement();
_ownedTokensCount[to] = _ownedTokensCount[to].add(1); _ownedTokensCount[to].increment();
_tokenOwner[tokenId] = to; _tokenOwner[tokenId] = to;
...@@ -267,7 +268,7 @@ contract ERC721 is Initializable, ERC165, IERC721 { ...@@ -267,7 +268,7 @@ contract ERC721 is Initializable, ERC165, IERC721 {
* @param to target address that will receive the tokens * @param to target address that will receive the tokens
* @param tokenId uint256 ID of the token to be transferred * @param tokenId uint256 ID of the token to be transferred
* @param _data bytes optional data to send along with the call * @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) function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data)
internal returns (bool) internal returns (bool)
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "./ERC721.sol"; import "./ERC721.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "./IERC721Enumerable.sol"; import "./IERC721Enumerable.sol";
...@@ -7,7 +7,7 @@ import "../../introspection/ERC165.sol"; ...@@ -7,7 +7,7 @@ import "../../introspection/ERC165.sol";
/** /**
* @title ERC-721 Non-Fungible Token with optional enumeration extension logic * @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 { contract ERC721Enumerable is Initializable, ERC165, ERC721, IERC721Enumerable {
// Mapping from owner to list of owned token IDs // Mapping from owner to list of owned token IDs
...@@ -23,7 +23,7 @@ contract ERC721Enumerable is Initializable, ERC165, ERC721, IERC721Enumerable { ...@@ -23,7 +23,7 @@ contract ERC721Enumerable is Initializable, ERC165, ERC721, IERC721Enumerable {
mapping(uint256 => uint256) private _allTokensIndex; mapping(uint256 => uint256) private _allTokensIndex;
bytes4 private constant _INTERFACE_ID_ERC721_ENUMERABLE = 0x780e9d63; bytes4 private constant _INTERFACE_ID_ERC721_ENUMERABLE = 0x780e9d63;
/** /*
* 0x780e9d63 === * 0x780e9d63 ===
* bytes4(keccak256('totalSupply()')) ^ * bytes4(keccak256('totalSupply()')) ^
* bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) ^ * bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) ^
...@@ -35,8 +35,7 @@ contract ERC721Enumerable is Initializable, ERC165, ERC721, IERC721Enumerable { ...@@ -35,8 +35,7 @@ contract ERC721Enumerable is Initializable, ERC165, ERC721, IERC721Enumerable {
*/ */
function initialize() public initializer { function initialize() public initializer {
require(ERC721._hasBeenInitialized()); require(ERC721._hasBeenInitialized());
// register the supported interface to conform to ERC721Enumerable via ERC165
// register the supported interface to conform to ERC721 via ERC165
_registerInterface(_INTERFACE_ID_ERC721_ENUMERABLE); _registerInterface(_INTERFACE_ID_ERC721_ENUMERABLE);
} }
...@@ -80,7 +79,7 @@ contract ERC721Enumerable is Initializable, ERC165, ERC721, IERC721Enumerable { ...@@ -80,7 +79,7 @@ contract ERC721Enumerable is Initializable, ERC165, ERC721, IERC721Enumerable {
* @param from current owner of the token * @param from current owner of the token
* @param to address to receive the ownership of the given token ID * @param to address to receive the ownership of the given token ID
* @param tokenId uint256 ID of the token to be transferred * @param tokenId uint256 ID of the token to be transferred
*/ */
function _transferFrom(address from, address to, uint256 tokenId) internal { function _transferFrom(address from, address to, uint256 tokenId) internal {
super._transferFrom(from, to, tokenId); super._transferFrom(from, to, tokenId);
...@@ -174,8 +173,8 @@ contract ERC721Enumerable is Initializable, ERC165, ERC721, IERC721Enumerable { ...@@ -174,8 +173,8 @@ contract ERC721Enumerable is Initializable, ERC165, ERC721, IERC721Enumerable {
// This also deletes the contents at the last position of the array // This also deletes the contents at the last position of the array
_ownedTokens[from].length--; _ownedTokens[from].length--;
// Note that _ownedTokensIndex[tokenId] hasn't been cleared: it still points to the old slot (now occcupied by // Note that _ownedTokensIndex[tokenId] hasn't been cleared: it still points to the old slot (now occupied by
// lasTokenId, or just over the end of the array if the token was the last one). // 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 "zos-lib/contracts/Initializable.sol";
import "./ERC721.sol"; import "./ERC721.sol";
...@@ -9,7 +9,7 @@ import "./ERC721Metadata.sol"; ...@@ -9,7 +9,7 @@ import "./ERC721Metadata.sol";
* @title Full ERC721 Token * @title Full ERC721 Token
* This implementation includes all the required and some optional functionality of the ERC721 standard * This implementation includes all the required and some optional functionality of the ERC721 standard
* Moreover, it includes approve all functionality using operator terminology * 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 { contract ERC721Full is Initializable, ERC721, ERC721Enumerable, ERC721Metadata {
uint256[50] private ______gap; uint256[50] private ______gap;
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "./IERC721Receiver.sol"; import "./IERC721Receiver.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "./ERC721.sol"; import "./ERC721.sol";
...@@ -16,7 +16,7 @@ contract ERC721Metadata is Initializable, ERC165, ERC721, IERC721Metadata { ...@@ -16,7 +16,7 @@ contract ERC721Metadata is Initializable, ERC165, ERC721, IERC721Metadata {
mapping(uint256 => string) private _tokenURIs; mapping(uint256 => string) private _tokenURIs;
bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f; bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f;
/** /*
* 0x5b5e139f === * 0x5b5e139f ===
* bytes4(keccak256('name()')) ^ * bytes4(keccak256('name()')) ^
* bytes4(keccak256('symbol()')) ^ * bytes4(keccak256('symbol()')) ^
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "./ERC721Metadata.sol"; import "./ERC721Metadata.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "./ERC721.sol"; import "./ERC721.sol";
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "./ERC721.sol"; import "./ERC721.sol";
...@@ -7,7 +7,7 @@ import "../../lifecycle/Pausable.sol"; ...@@ -7,7 +7,7 @@ import "../../lifecycle/Pausable.sol";
/** /**
* @title ERC721 Non-Fungible Pausable token * @title ERC721 Non-Fungible Pausable token
* @dev ERC721 modified with pausable transfers. * @dev ERC721 modified with pausable transfers.
**/ */
contract ERC721Pausable is Initializable, ERC721, Pausable { contract ERC721Pausable is Initializable, ERC721, Pausable {
function initialize(address sender) public initializer { function initialize(address sender) public initializer {
require(ERC721._hasBeenInitialized()); require(ERC721._hasBeenInitialized());
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "../../introspection/IERC165.sol"; import "../../introspection/IERC165.sol";
/** /**
* @title ERC721 Non-Fungible Token Standard basic interface * @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 { contract IERC721 is Initializable, IERC165 {
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); 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 "zos-lib/contracts/Initializable.sol";
import "./IERC721.sol"; import "./IERC721.sol";
/** /**
* @title ERC-721 Non-Fungible Token Standard, optional enumeration extension * @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 { contract IERC721Enumerable is Initializable, IERC721 {
function totalSupply() public view returns (uint256); function totalSupply() public view returns (uint256);
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "./IERC721.sol"; import "./IERC721.sol";
...@@ -7,7 +7,7 @@ import "./IERC721Metadata.sol"; ...@@ -7,7 +7,7 @@ import "./IERC721Metadata.sol";
/** /**
* @title ERC-721 Non-Fungible Token Standard, full implementation interface * @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 { contract IERC721Full is Initializable, IERC721, IERC721Enumerable, IERC721Metadata {
// solhint-disable-previous-line no-empty-blocks // solhint-disable-previous-line no-empty-blocks
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "zos-lib/contracts/Initializable.sol"; import "zos-lib/contracts/Initializable.sol";
import "./IERC721.sol"; import "./IERC721.sol";
/** /**
* @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @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 { contract IERC721Metadata is Initializable, IERC721 {
function name() external view returns (string memory); function name() external view returns (string memory);
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
/** /**
* @title ERC721 token receiver interface * @title ERC721 token receiver interface
...@@ -18,7 +18,7 @@ contract IERC721Receiver { ...@@ -18,7 +18,7 @@ contract IERC721Receiver {
* @param from The address which previously owned the token * @param from The address which previously owned the token
* @param tokenId The NFT identifier which is being transferred * @param tokenId The NFT identifier which is being transferred
* @param data Additional data with no specified format * @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) function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data)
public returns (bytes4); public returns (bytes4);
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
/** /**
* Utility library of inline functions on addresses * Utility library of inline functions on addresses
......
pragma solidity ^0.5.0; pragma solidity ^0.5.2;
import "../math/Math.sol"; import "../math/Math.sol";
...@@ -9,13 +9,13 @@ import "../math/Math.sol"; ...@@ -9,13 +9,13 @@ import "../math/Math.sol";
*/ */
library Arrays { library Arrays {
/** /**
* @dev Upper bound search function which is kind of binary search algoritm. It searches sorted * @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 it's index otherwise * 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 grater than searched value. If searched element is * 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 * 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). * values inside the array are smaller than the target). Complexity O(log n).
* @param array The array sorted in ascending order. * @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. * @return The calculated index value. Returns 0 for empty array.
*/ */
function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) { 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"; 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", "name": "openzeppelin-eth",
"version": "2.1.3", "version": "2.2.0",
"description": "Secure Smart Contract library for Solidity", "description": "Secure Smart Contract library for Solidity",
"files": [ "files": [
"build", "build",
...@@ -58,7 +58,7 @@ ...@@ -58,7 +58,7 @@
"openzeppelin-test-helpers": "^0.1.1", "openzeppelin-test-helpers": "^0.1.1",
"pify": "^4.0.1", "pify": "^4.0.1",
"solhint": "^1.5.0", "solhint": "^1.5.0",
"solidity-coverage": "^0.5.4", "solidity-coverage": "https://github.com:rotcivegaf/solidity-coverage.git#5875f5b7bc74d447f3312c9c0e9fc7814b482477",
"truffle": "^5.0.0", "truffle": "^5.0.0",
"zos": "^2.0.0", "zos": "^2.0.0",
"zos-lib": "^2.1.0" "zos-lib": "^2.1.0"
......
...@@ -54,7 +54,7 @@ contract('AllowanceCrowdsale', function ([_, investor, wallet, purchaser, tokenW ...@@ -54,7 +54,7 @@ contract('AllowanceCrowdsale', function ([_, investor, wallet, purchaser, tokenW
}); });
describe('check remaining allowance', function () { 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); const remainingAllowance = tokenAllowance.sub(expectedTokenAmount);
await this.crowdsale.buyTokens(investor, { value: value, from: purchaser }); await this.crowdsale.buyTokens(investor, { value: value, from: purchaser });
(await this.crowdsale.remainingTokens()).should.be.bignumber.equal(remainingAllowance); (await this.crowdsale.remainingTokens()).should.be.bignumber.equal(remainingAllowance);
...@@ -72,7 +72,7 @@ contract('AllowanceCrowdsale', function ([_, investor, wallet, purchaser, tokenW ...@@ -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 () { it('creation reverts', async function () {
this.token = await SimpleToken.new({ from: tokenWallet }); this.token = await SimpleToken.new({ from: tokenWallet });
await shouldFail.reverting(AllowanceCrowdsaleImpl.new(rate, wallet, this.token.address, ZERO_ADDRESS)); await shouldFail.reverting(AllowanceCrowdsaleImpl.new(rate, wallet, this.token.address, ZERO_ADDRESS));
......
...@@ -31,7 +31,7 @@ contract('IncreasingPriceCrowdsale', function ([_, investor, wallet, purchaser]) ...@@ -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( await shouldFail.reverting(IncreasingPriceCrowdsaleImpl.new(
this.startTime, this.closingTime, wallet, this.token.address, initialRate, initialRate 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 TimedCrowdsaleImpl = artifacts.require('TimedCrowdsaleImpl');
const SimpleToken = artifacts.require('SimpleTokenMock'); const SimpleToken = artifacts.require('SimpleTokenMock');
...@@ -73,5 +73,62 @@ contract('TimedCrowdsale', function ([_, investor, wallet, purchaser]) { ...@@ -73,5 +73,62 @@ contract('TimedCrowdsale', function ([_, investor, wallet, purchaser]) {
await shouldFail.reverting(this.crowdsale.buyTokens(investor, { value: value, from: 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 { constants, shouldFail } = require('openzeppelin-test-helpers');
const { signMessage, toEthSignedMessageHash } = require('../helpers/sign'); const { ZERO_ADDRESS } = constants;
const { toEthSignedMessageHash, fixSignature } = require('../helpers/sign');
const ECDSAMock = artifacts.require('ECDSAMock'); const ECDSAMock = artifacts.require('ECDSAMock');
...@@ -19,10 +20,10 @@ contract('ECDSA', function ([_, anyone]) { ...@@ -19,10 +20,10 @@ contract('ECDSA', function ([_, anyone]) {
const signatureWithoutVersion = '0x5d99b6f7f6d1f73d1a26497f2b1c89b24c0993913f86e9a2d02cd69887d9c94f3c880358579d811b21dd1b7fd9bb01c1d81d10e69f0384e675c32b39643be892'; const signatureWithoutVersion = '0x5d99b6f7f6d1f73d1a26497f2b1c89b24c0993913f86e9a2d02cd69887d9c94f3c880358579d811b21dd1b7fd9bb01c1d81d10e69f0384e675c32b39643be892';
context('with 00 as version value', function () { context('with 00 as version value', function () {
it('works', async function () { it('returns 0', async function () {
const version = '00'; const version = '00';
const signature = signatureWithoutVersion + version; 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]) { ...@@ -40,8 +41,7 @@ contract('ECDSA', function ([_, anyone]) {
// The only valid values are 0, 1, 27 and 28. // The only valid values are 0, 1, 27 and 28.
const version = '02'; const version = '02';
const signature = signatureWithoutVersion + version; const signature = signatureWithoutVersion + version;
(await this.ecdsa.recover(TEST_MESSAGE, signature)).should.equal( (await this.ecdsa.recover(TEST_MESSAGE, signature)).should.equal(ZERO_ADDRESS);
'0x0000000000000000000000000000000000000000');
}); });
}); });
}); });
...@@ -52,14 +52,14 @@ contract('ECDSA', function ([_, anyone]) { ...@@ -52,14 +52,14 @@ contract('ECDSA', function ([_, anyone]) {
const signatureWithoutVersion = '0x331fe75a821c982f9127538858900d87d3ec1f9f737338ad67cad133fa48feff48e6fa0c18abc62e42820f05943e47af3e9fbe306ce74d64094bdf1691ee53e0'; const signatureWithoutVersion = '0x331fe75a821c982f9127538858900d87d3ec1f9f737338ad67cad133fa48feff48e6fa0c18abc62e42820f05943e47af3e9fbe306ce74d64094bdf1691ee53e0';
context('with 01 as version value', function () { context('with 01 as version value', function () {
it('works', async function () { it('returns 0', async function () {
const version = '01'; const version = '01';
const signature = signatureWithoutVersion + version; 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 () { it('works', async function () {
const version = '1c'; // 28 = 1c. const version = '1c'; // 28 = 1c.
const signature = signatureWithoutVersion + version; const signature = signatureWithoutVersion + version;
...@@ -73,17 +73,26 @@ contract('ECDSA', function ([_, anyone]) { ...@@ -73,17 +73,26 @@ contract('ECDSA', function ([_, anyone]) {
// The only valid values are 0, 1, 27 and 28. // The only valid values are 0, 1, 27 and 28.
const version = '02'; const version = '02';
const signature = signatureWithoutVersion + version; const signature = signatureWithoutVersion + version;
(await this.ecdsa.recover(TEST_MESSAGE, signature)).should.equal( (await this.ecdsa.recover(TEST_MESSAGE, signature)).should.equal(ZERO_ADDRESS);
'0x0000000000000000000000000000000000000000');
}); });
}); });
}); });
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('using web3.eth.sign', function () {
context('with correct signature', function () { context('with correct signature', function () {
it('returns signer address', async function () { it('returns signer address', async function () {
// Create the signature // 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. // Recover the signer address from the generated message and signature.
(await this.ecdsa.recover( (await this.ecdsa.recover(
...@@ -96,23 +105,23 @@ contract('ECDSA', function ([_, anyone]) { ...@@ -96,23 +105,23 @@ contract('ECDSA', function ([_, anyone]) {
context('with wrong signature', function () { context('with wrong signature', function () {
it('does not return signer address', async function () { it('does not return signer address', async function () {
// Create the signature // 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. // Recover the signer address from the generated message and wrong signature.
(await this.ecdsa.recover(WRONG_MESSAGE, signature)).should.not.equal(anyone); (await this.ecdsa.recover(WRONG_MESSAGE, signature)).should.not.equal(anyone);
}); });
}); });
}); });
});
context('with small hash', function () { context('with small hash', function () {
// @TODO - remove `skip` once we upgrade to solc^0.5 // @TODO - remove `skip` once we upgrade to solc^0.5
it.skip('reverts', async function () { it.skip('reverts', async function () {
// Create the signature // Create the signature
const signature = await signMessage(anyone, TEST_MESSAGE); const signature = await web3.eth.sign(TEST_MESSAGE, anyone);
await shouldFail.reverting( await shouldFail.reverting(
this.ecdsa.recover(TEST_MESSAGE.substring(2), signature) 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'); require('openzeppelin-test-helpers');
const ERC20WithMetadataMock = artifacts.require('ERC20WithMetadataMock'); const ERC20MetadataMock = artifacts.require('ERC20MetadataMock');
const metadataURI = 'https://example.com'; const metadataURI = 'https://example.com';
describe('ERC20WithMetadata', function () { describe('ERC20Metadata', function () {
beforeEach(async function () { beforeEach(async function () {
this.token = await ERC20WithMetadataMock.new(metadataURI); this.token = await ERC20MetadataMock.new(metadataURI);
}); });
it('responds with the metadata', async function () { it('responds with the metadata', async function () {
(await this.token.tokenURI()).should.equal(metadataURI); (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]) { ...@@ -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 () { describe('once migration began', function () {
beforeEach('beginning migration', async function () { beforeEach('beginning migration', async function () {
await this.newToken.addMinter(this.migrator.address); 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 () { ...@@ -8,34 +8,43 @@ contract('SignedSafeMath', function () {
this.safeMath = await SignedSafeMathMock.new(); 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 () { 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 a = new BN('1234');
const b = new BN('5678'); 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 () { it('adds correctly if it does not overflow and the result is negative', async function () {
const a = MAX_INT256; const a = MAX_INT256;
const b = MIN_INT256; const b = MIN_INT256;
const result = await this.safeMath.add(a, b); await testCommutative(this.safeMath.add, a, b, a.add(b));
result.should.be.bignumber.equal(a.add(b));
}); });
it('reverts on positive addition overflow', async function () { it('reverts on positive addition overflow', async function () {
const a = MAX_INT256; const a = MAX_INT256;
const b = new BN('1'); 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 () { it('reverts on negative addition overflow', async function () {
const a = MIN_INT256; const a = MIN_INT256;
const b = new BN('-1'); 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 () { ...@@ -76,37 +85,28 @@ contract('SignedSafeMath', function () {
const a = new BN('5678'); const a = new BN('5678');
const b = new BN('-1234'); const b = new BN('-1234');
const result = await this.safeMath.mul(a, b); await testCommutative(this.safeMath.mul, a, b, a.mul(b));
result.should.be.bignumber.equal(a.mul(b));
}); });
it('handles a zero product correctly', async function () { it('multiplies by zero correctly', async function () {
const a = new BN('0'); const a = new BN('0');
const b = new BN('5678'); const b = new BN('5678');
const result = await this.safeMath.mul(a, b); await testCommutative(this.safeMath.mul, a, b, '0');
result.should.be.bignumber.equal(a.mul(b));
}); });
it('reverts on multiplication overflow, positive operands', async function () { it('reverts on multiplication overflow, positive operands', async function () {
const a = MAX_INT256; const a = MAX_INT256;
const b = new BN('2'); 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 () { it('reverts when minimum integer is multiplied by -1', async function () {
const a = MIN_INT256; const a = MIN_INT256;
const b = new BN('-1'); const b = new BN('-1');
await shouldFail.reverting(this.safeMath.mul(a, b)); await testFailsCommutative(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));
}); });
}); });
...@@ -119,7 +119,21 @@ contract('SignedSafeMath', function () { ...@@ -119,7 +119,21 @@ contract('SignedSafeMath', function () {
result.should.be.bignumber.equal(a.div(b)); 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 a = new BN('-5678');
const b = new BN('0'); const b = new BN('0');
......
...@@ -9,9 +9,21 @@ function toEthSignedMessageHash (messageHex) { ...@@ -9,9 +9,21 @@ function toEthSignedMessageHash (messageHex) {
return web3.utils.sha3(Buffer.concat([prefix, messageBuffer])); 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) // signs message in node (ganache auto-applies "Ethereum Signed Message" prefix)
const signMessage = (signer, messageHex = '0x') => { async function signMessage (signer, messageHex = '0x') {
return web3.eth.sign(messageHex, signer); return fixSignature(await web3.eth.sign(messageHex, signer));
}; };
/** /**
...@@ -50,5 +62,6 @@ const getSignFor = (contract, signer) => (redeemer, methodName, methodArgs = []) ...@@ -50,5 +62,6 @@ const getSignFor = (contract, signer) => (redeemer, methodName, methodArgs = [])
module.exports = { module.exports = {
signMessage, signMessage,
toEthSignedMessageHash, toEthSignedMessageHash,
fixSignature,
getSignFor, getSignFor,
}; };
...@@ -17,7 +17,7 @@ contract('Pausable', function ([_, pauser, otherPauser, anyone, ...otherAccounts ...@@ -17,7 +17,7 @@ contract('Pausable', function ([_, pauser, otherPauser, anyone, ...otherAccounts
shouldBehaveLikePublicRole(pauser, otherPauser, otherAccounts, 'pauser'); shouldBehaveLikePublicRole(pauser, otherPauser, otherAccounts, 'pauser');
}); });
context('when unapused', function () { context('when unpaused', function () {
beforeEach(async function () { beforeEach(async function () {
(await this.pausable.paused()).should.equal(false); (await this.pausable.paused()).should.equal(false);
}); });
......
...@@ -8,19 +8,29 @@ contract('SafeMath', function () { ...@@ -8,19 +8,29 @@ contract('SafeMath', function () {
this.safeMath = await SafeMathMock.new(); 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 () { describe('add', function () {
it('adds correctly', async function () { it('adds correctly', async function () {
const a = new BN('5678'); const a = new BN('5678');
const b = new BN('1234'); 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 () { it('reverts on addition overflow', async function () {
const a = MAX_UINT256; const a = MAX_UINT256;
const b = new BN('1'); 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 () { ...@@ -45,28 +55,21 @@ contract('SafeMath', function () {
const a = new BN('1234'); const a = new BN('1234');
const b = new BN('5678'); 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 a = new BN('0');
const b = new BN('5678'); 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, '0');
});
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));
}); });
it('reverts on multiplication overflow', async function () { it('reverts on multiplication overflow', async function () {
const a = MAX_UINT256; const a = MAX_UINT256;
const b = new BN('2'); 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 () { ...@@ -92,7 +95,7 @@ contract('SafeMath', function () {
(await this.safeMath.div(a, b)).should.be.bignumber.equal('1'); (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 a = new BN('5678');
const b = new BN('0'); const b = new BN('0');
......
...@@ -16,7 +16,7 @@ function shouldBehaveLikeOwnable (owner, [anyone]) { ...@@ -16,7 +16,7 @@ function shouldBehaveLikeOwnable (owner, [anyone]) {
(await this.ownable.isOwner({ from: anyone })).should.be.equal(true); (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 })); await shouldFail.reverting(this.ownable.transferOwnership(anyone, { from: anyone }));
}); });
......
...@@ -29,7 +29,7 @@ contract('Secondary', function ([_, primary, newPrimary, anyone]) { ...@@ -29,7 +29,7 @@ contract('Secondary', function ([_, primary, newPrimary, anyone]) {
(await this.secondary.primary()).should.equal(newPrimary); (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 })); await shouldFail.reverting(this.secondary.transferPrimary(ZERO_ADDRESS, { from: primary }));
}); });
......
...@@ -84,19 +84,19 @@ contract('PaymentSplitter', function ([_, owner, payee1, payee2, payee3, nonpaye ...@@ -84,19 +84,19 @@ contract('PaymentSplitter', function ([_, owner, payee1, payee2, payee3, nonpaye
const initAmount1 = await balance.current(payee1); const initAmount1 = await balance.current(payee1);
const { logs: logs1 } = await this.contract.release(payee1, { gasPrice: 0 }); const { logs: logs1 } = await this.contract.release(payee1, { gasPrice: 0 });
const profit1 = (await balance.current(payee1)).sub(initAmount1); 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 }); expectEvent.inLogs(logs1, 'PaymentReleased', { to: payee1, amount: profit1 });
const initAmount2 = await balance.current(payee2); const initAmount2 = await balance.current(payee2);
const { logs: logs2 } = await this.contract.release(payee2, { gasPrice: 0 }); const { logs: logs2 } = await this.contract.release(payee2, { gasPrice: 0 });
const profit2 = (await balance.current(payee2)).sub(initAmount2); 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 }); expectEvent.inLogs(logs2, 'PaymentReleased', { to: payee2, amount: profit2 });
const initAmount3 = await balance.current(payee3); const initAmount3 = await balance.current(payee3);
const { logs: logs3 } = await this.contract.release(payee3, { gasPrice: 0 }); const { logs: logs3 } = await this.contract.release(payee3, { gasPrice: 0 });
const profit3 = (await balance.current(payee3)).sub(initAmount3); 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 }); expectEvent.inLogs(logs3, 'PaymentReleased', { to: payee3, amount: profit3 });
// end balance should be zero // end balance should be zero
......
...@@ -73,89 +73,6 @@ contract('ERC20', function ([_, initialHolder, recipient, anotherAccount]) { ...@@ -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 () { describe('transfer from', function () {
const spender = recipient; const spender = recipient;
...@@ -546,4 +463,100 @@ contract('ERC20', function ([_, initialHolder, recipient, anotherAccount]) { ...@@ -546,4 +463,100 @@ contract('ERC20', function ([_, initialHolder, recipient, anotherAccount]) {
describeBurnFrom('for less amount than allowance', allowance.subn(1)); 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 { 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 () { shouldRevertOnAllCalls();
beforeEach(async function () {
this.helper = await SafeERC20Helper.new();
}); });
describe('with token that returns false on all calls', function () { describe('with token that returns false on all calls', function () {
it('reverts on transfer', async function () { beforeEach(async function () {
await shouldFail.reverting(this.helper.doFailingTransfer()); this.wrapper = await SafeERC20Wrapper.new((await ERC20ReturnFalseMock.new()).address);
}); });
it('reverts on transferFrom', async function () { shouldRevertOnAllCalls();
await shouldFail.reverting(this.helper.doFailingTransferFrom()); });
});
it('reverts on approve', async function () { describe('with token that returns true on all calls', function () {
await shouldFail.reverting(this.helper.doFailingApprove()); beforeEach(async function () {
this.wrapper = await SafeERC20Wrapper.new((await ERC20ReturnTrueMock.new()).address);
}); });
it('reverts on increaseAllowance', async function () { shouldOnlyRevertOnErrors();
await shouldFail.reverting(this.helper.doFailingIncreaseAllowance()); });
});
it('reverts on decreaseAllowance', async function () { describe('with token that returns no boolean values', function () {
await shouldFail.reverting(this.helper.doFailingDecreaseAllowance()); beforeEach(async function () {
this.wrapper = await SafeERC20Wrapper.new((await ERC20NoReturnMock.new()).address);
}); });
shouldOnlyRevertOnErrors();
}); });
});
describe('with token that returns true on all calls', function () { function shouldRevertOnAllCalls () {
it('doesn\'t revert on transfer', async function () { it('reverts on transfer', async function () {
await this.helper.doSucceedingTransfer(); await shouldFail.reverting(this.wrapper.transfer());
}); });
it('doesn\'t revert on transferFrom', async function () { it('reverts on transferFrom', async function () {
await this.helper.doSucceedingTransferFrom(); 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 () { it('reverts on decreaseAllowance', async function () {
context('with zero allowance', function () { await shouldFail.reverting(this.wrapper.decreaseAllowance(0));
beforeEach(async function () { });
await this.helper.setAllowance(0); }
});
it('doesn\'t revert when approving a non-zero allowance', async function () { function shouldOnlyRevertOnErrors () {
await this.helper.doSucceedingApprove(100); it('doesn\'t revert on transfer', async function () {
}); await this.wrapper.transfer();
});
it('doesn\'t revert when approving a zero allowance', async function () { it('doesn\'t revert on transferFrom', async function () {
await this.helper.doSucceedingApprove(0); await this.wrapper.transferFrom();
}); });
it('doesn\'t revert when increasing the allowance', async function () { describe('approvals', function () {
await this.helper.doSucceedingIncreaseAllowance(10); context('with zero allowance', function () {
}); beforeEach(async function () {
await this.wrapper.setAllowance(0);
});
it('reverts when decreasing the allowance', async function () { it('doesn\'t revert when approving a non-zero allowance', async function () {
await shouldFail.reverting(this.helper.doSucceedingDecreaseAllowance(10)); await this.wrapper.approve(100);
});
}); });
context('with non-zero allowance', function () { it('doesn\'t revert when approving a zero allowance', async function () {
beforeEach(async function () { await this.wrapper.approve(0);
await this.helper.setAllowance(100); });
});
it('reverts when approving a non-zero allowance', async function () { it('doesn\'t revert when increasing the allowance', async function () {
await shouldFail.reverting(this.helper.doSucceedingApprove(20)); await this.wrapper.increaseAllowance(10);
}); });
it('doesn\'t revert when approving a zero allowance', async function () { it('reverts when decreasing the allowance', async function () {
await this.helper.doSucceedingApprove(0); await shouldFail.reverting(this.wrapper.decreaseAllowance(10));
}); });
});
it('doesn\'t revert when increasing the allowance', async function () { context('with non-zero allowance', function () {
await this.helper.doSucceedingIncreaseAllowance(10); beforeEach(async function () {
}); await this.wrapper.setAllowance(100);
});
it('doesn\'t revert when decreasing the allowance to a positive value', async function () { it('reverts when approving a non-zero allowance', async function () {
await this.helper.doSucceedingDecreaseAllowance(50); 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 () { it('reverts when decreasing the allowance to a negative value', async function () {
await shouldFail.reverting(this.helper.doSucceedingDecreaseAllowance(200)); await shouldFail.reverting(this.wrapper.decreaseAllowance(200));
});
}); });
}); });
}); });
}); }
...@@ -55,7 +55,7 @@ function shouldBehaveLikeERC721PausedToken (owner, [recipient, operator]) { ...@@ -55,7 +55,7 @@ function shouldBehaveLikeERC721PausedToken (owner, [recipient, operator]) {
}); });
describe('exists', function () { 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); (await this.token.exists(firstTokenId)).should.equal(true);
}); });
}); });
......
...@@ -16,7 +16,7 @@ module.exports = { ...@@ -16,7 +16,7 @@ module.exports = {
compilers: { compilers: {
solc: { 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