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

v2.1.1
This commit is contained in:
Francisco Giordano
2019-01-18 15:33:51 -03:00
237 changed files with 8562 additions and 4937 deletions

View File

@ -1,5 +1,4 @@
pragma solidity ^0.4.24;
pragma solidity ^0.5.0;
/**
* @title Counter
@ -14,15 +13,11 @@ pragma solidity ^0.4.24;
* 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)
{
function next(Counter storage index) internal returns (uint256) {
index.current += 1;
return index.current;
}

View File

@ -1,33 +1,27 @@
pragma solidity ^0.4.24;
pragma solidity ^0.5.0;
import "zos-lib/contracts/Initializable.sol";
import "../../token/ERC20/IERC20.sol";
/**
* @title ERC-1047 Token Metadata
* @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 TODO - update https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/token/ERC721/IERC721.sol#L17 when 1046 is finalized
*/
contract ERC20TokenMetadata is Initializable, IERC20 {
function tokenURI() external view returns (string);
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 tokenURI)
public
initializer
{
function initialize(string memory tokenURI) public {
_tokenURI = tokenURI;
}
function tokenURI() external view returns (string) {
function tokenURI() external view returns (string memory) {
return _tokenURI;
}

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.24;
pragma solidity ^0.5.0;
import "zos-lib/contracts/Initializable.sol";
import "../token/ERC20/IERC20.sol";
@ -6,7 +6,6 @@ import "../token/ERC20/ERC20Mintable.sol";
import "../token/ERC20/SafeERC20.sol";
import "../math/Math.sol";
/**
* @title ERC20Migrator
* @dev This contract can be used to migrate an ERC20 token from one
@ -46,7 +45,7 @@ contract ERC20Migrator is Initializable {
* @param legacyToken address of the old token contract
*/
function initialize(IERC20 legacyToken) public initializer {
require(legacyToken != address(0));
require(address(legacyToken) != address(0));
_legacyToken = legacyToken;
}
@ -70,9 +69,9 @@ contract ERC20Migrator is Initializable {
* @param newToken the token that will be minted
*/
function beginMigration(ERC20Mintable newToken) public {
require(_newToken == address(0));
require(newToken != address(0));
require(newToken.isMinter(this));
require(address(_newToken) == address(0));
require(address(newToken) != address(0));
require(newToken.isMinter(address(this)));
_newToken = newToken;
}
@ -84,7 +83,7 @@ contract ERC20Migrator is Initializable {
* @param amount amount of tokens to be migrated
*/
function migrate(address account, uint256 amount) public {
_legacyToken.safeTransferFrom(account, this, amount);
_legacyToken.safeTransferFrom(account, address(this), amount);
_newToken.mint(account, amount);
}
@ -95,7 +94,7 @@ contract ERC20Migrator is Initializable {
*/
function migrateAll(address account) public {
uint256 balance = _legacyToken.balanceOf(account);
uint256 allowance = _legacyToken.allowance(account, this);
uint256 allowance = _legacyToken.allowance(account, address(this));
uint256 amount = Math.min(balance, allowance);
migrate(account, amount);
}

View File

@ -1,33 +1,39 @@
pragma solidity ^0.4.24;
pragma solidity ^0.5.0;
import "zos-lib/contracts/Initializable.sol";
import "../access/roles/SignerRole.sol";
import "../cryptography/ECDSA.sol";
/**
* @title SignatureBouncer
* @author PhABC, Shrugs and aflesher
* @dev SignatureBouncer allows users to submit a signature as a permission to do an action.
* If the signature is from one of the authorized signer addresses, the signature
* is valid.
* @dev SignatureBouncer allows users to submit a signature as a permission to
* do an action.
* If the signature is from one of the authorized signer addresses, the
* signature is valid.
* Note that SignatureBouncer offers no protection against replay attacks, users
* must add this themselves!
*
* Signer addresses can be individual servers signing grants or different
* users within a decentralized club that have permission to invite other members.
* This technique is useful for whitelists and airdrops; instead of putting all
* valid addresses on-chain, simply sign a grant of the form
* keccak256(abi.encodePacked(`:contractAddress` + `:granteeAddress`)) using a valid signer address.
* users within a decentralized club that have permission to invite other
* members. This technique is useful for whitelists and airdrops; instead of
* putting all valid addresses on-chain, simply sign a grant of the form
* keccak256(abi.encodePacked(`:contractAddress` + `:granteeAddress`)) using a
* valid signer address.
* Then restrict access to your crowdsale/whitelist/airdrop using the
* `onlyValidSignature` modifier (or implement your own using _isValidSignature).
* In addition to `onlyValidSignature`, `onlyValidSignatureAndMethod` and
* `onlyValidSignatureAndData` can be used to restrict access to only a given method
* or a given method with given parameters respectively.
* `onlyValidSignatureAndData` can be used to restrict access to only a given
* method or a given method with given parameters respectively.
* See the tests in SignatureBouncer.test.js for specific usage examples.
* @notice A method that uses the `onlyValidSignatureAndData` modifier must make the _signature
* parameter the "last" parameter. You cannot sign a message that has its own
* signature in it so the last 128 bytes of msg.data (which represents the
* length of the _signature data and the _signaature data itself) is ignored when validating.
* Also non fixed sized parameters make constructing the data in the signature
* much more complex. See https://ethereum.stackexchange.com/a/50616 for more details.
*
* @notice A method that uses the `onlyValidSignatureAndData` modifier must make
* the _signature parameter the "last" parameter. You cannot sign a message that
* has its own signature in it so the last 128 bytes of msg.data (which
* represents the length of the _signature data and the _signaature data itself)
* is ignored when validating. Also non fixed sized parameters make constructing
* the data in the signature much more complex.
* See https://ethereum.stackexchange.com/a/50616 for more details.
*/
contract SignatureBouncer is Initializable, SignerRole {
using ECDSA for bytes32;
@ -38,11 +44,14 @@ contract SignatureBouncer is Initializable, SignerRole {
// Signature size is 65 bytes (tightly packed v + r + s), but gets padded to 96 bytes
uint256 private constant _SIGNATURE_SIZE = 96;
function initialize(address sender) internal initializer {
SignerRole.initialize(sender);
}
/**
* @dev requires that a valid signature of a signer was provided
*/
modifier onlyValidSignature(bytes signature)
{
modifier onlyValidSignature(bytes memory signature) {
require(_isValidSignature(msg.sender, signature));
_;
}
@ -50,8 +59,7 @@ contract SignatureBouncer is Initializable, SignerRole {
/**
* @dev requires that a valid signature with a specifed method of a signer was provided
*/
modifier onlyValidSignatureAndMethod(bytes signature)
{
modifier onlyValidSignatureAndMethod(bytes memory signature) {
require(_isValidSignatureAndMethod(msg.sender, signature));
_;
}
@ -59,48 +67,29 @@ contract SignatureBouncer is Initializable, SignerRole {
/**
* @dev requires that a valid signature with a specifed method and params of a signer was provided
*/
modifier onlyValidSignatureAndData(bytes signature)
{
modifier onlyValidSignatureAndData(bytes memory signature) {
require(_isValidSignatureAndData(msg.sender, signature));
_;
}
function initialize(address sender) public initializer {
SignerRole.initialize(sender);
}
/**
* @dev is the signature of `this + sender` from a signer?
* @return bool
*/
function _isValidSignature(address account, bytes signature)
internal
view
returns (bool)
{
return _isValidDataHash(
keccak256(abi.encodePacked(address(this), account)),
signature
);
function _isValidSignature(address account, bytes memory signature) internal view returns (bool) {
return _isValidDataHash(keccak256(abi.encodePacked(address(this), account)), signature);
}
/**
* @dev is the signature of `this + sender + methodId` from a signer?
* @return bool
*/
function _isValidSignatureAndMethod(address account, bytes signature)
internal
view
returns (bool)
{
function _isValidSignatureAndMethod(address account, bytes memory signature) internal view returns (bool) {
bytes memory data = new bytes(_METHOD_ID_SIZE);
for (uint i = 0; i < data.length; i++) {
data[i] = msg.data[i];
}
return _isValidDataHash(
keccak256(abi.encodePacked(address(this), account, data)),
signature
);
return _isValidDataHash(keccak256(abi.encodePacked(address(this), account, data)), signature);
}
/**
@ -108,20 +97,15 @@ contract SignatureBouncer is Initializable, SignerRole {
* @notice the signature parameter of the method being validated must be the "last" parameter
* @return bool
*/
function _isValidSignatureAndData(address account, bytes signature)
internal
view
returns (bool)
{
function _isValidSignatureAndData(address account, bytes memory signature) internal view returns (bool) {
require(msg.data.length > _SIGNATURE_SIZE);
bytes memory data = new bytes(msg.data.length - _SIGNATURE_SIZE);
for (uint i = 0; i < data.length; i++) {
data[i] = msg.data[i];
}
return _isValidDataHash(
keccak256(abi.encodePacked(address(this), account, data)),
signature
);
return _isValidDataHash(keccak256(abi.encodePacked(address(this), account, data)), signature);
}
/**
@ -129,14 +113,8 @@ contract SignatureBouncer is Initializable, SignerRole {
* and then recover the signature and check it against the signer role
* @return bool
*/
function _isValidDataHash(bytes32 hash, bytes signature)
internal
view
returns (bool)
{
address signer = hash
.toEthSignedMessageHash()
.recover(signature);
function _isValidDataHash(bytes32 hash, bytes memory signature) internal view returns (bool) {
address signer = hash.toEthSignedMessageHash().recover(signature);
return signer != address(0) && isSigner(signer);
}

View File

@ -0,0 +1,60 @@
pragma solidity ^0.5.0;
/**
* @title SignedSafeMath
* @dev Signed math operations with safety checks that revert on error
*/
library SignedSafeMath {
int256 constant private INT256_MIN = -2**255;
/**
* @dev Multiplies two signed integers, reverts on overflow.
*/
function mul(int256 a, int256 b) internal pure returns (int256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
if (a == 0) {
return 0;
}
require(!(a == -1 && b == INT256_MIN)); // This is the only case of overflow not detected by the check below
int256 c = a * b;
require(c / a == b);
return c;
}
/**
* @dev Integer division of two signed integers truncating the quotient, reverts on division by zero.
*/
function div(int256 a, int256 b) internal pure returns (int256) {
require(b != 0); // Solidity only automatically asserts when dividing by 0
require(!(b == -1 && a == INT256_MIN)); // This is the only case of overflow
int256 c = a / b;
return c;
}
/**
* @dev Subtracts two signed integers, reverts on overflow.
*/
function sub(int256 a, int256 b) internal pure returns (int256) {
int256 c = a - b;
require((b >= 0 && c <= a) || (b < 0 && c > a));
return c;
}
/**
* @dev Adds two signed integers, reverts on overflow.
*/
function add(int256 a, int256 b) internal pure returns (int256) {
int256 c = a + b;
require((b >= 0 && c >= a) || (b < 0 && c < a));
return c;
}
}

View File

@ -1,13 +1,10 @@
/* solium-disable security/no-block-members */
pragma solidity ^0.4.24;
pragma solidity ^0.5.0;
import "zos-lib/contracts/Initializable.sol";
import "../token/ERC20/SafeERC20.sol";
import "../ownership/Ownable.sol";
import "../math/SafeMath.sol";
/**
* @title TokenVesting
* @dev A token holder contract that can release its token balance gradually like a
@ -15,15 +12,22 @@ import "../math/SafeMath.sol";
* owner.
*/
contract TokenVesting is Initializable, Ownable {
// The vesting schedule is time-based (i.e. using block timestamps as opposed to e.g. block numbers), and is
// therefore sensitive to timestamp manipulation (which is something miners can do, to a certain degree). Therefore,
// it is recommended to avoid using short time durations (less than a minute). Typical vesting schemes, with a cliff
// period of a year and a duration of four years, are safe to use.
// solhint-disable not-rely-on-time
using SafeMath for uint256;
using SafeERC20 for IERC20;
event Released(uint256 amount);
event Revoked();
event TokensReleased(address token, uint256 amount);
event TokenVestingRevoked(address token);
// beneficiary of tokens after they are released
address private _beneficiary;
// Durations and timestamps are expressed in UNIX time, the same units as block.timestamp.
uint256 private _cliff;
uint256 private _start;
uint256 private _duration;
@ -43,21 +47,13 @@ contract TokenVesting is Initializable, Ownable {
* @param duration duration in seconds of the period in which the tokens will vest
* @param revocable whether the vesting is revocable or not
*/
function initialize(
address beneficiary,
uint256 start,
uint256 cliffDuration,
uint256 duration,
bool revocable,
address sender
)
public
initializer
{
constructor (address beneficiary, uint256 start, uint256 cliffDuration, uint256 duration, bool revocable, address sender) public initializer {
Ownable.initialize(sender);
require(beneficiary != address(0));
require(cliffDuration <= duration);
require(duration > 0);
require(start.add(duration) > block.timestamp);
_beneficiary = beneficiary;
_revocable = revocable;
@ -69,49 +65,49 @@ contract TokenVesting is Initializable, Ownable {
/**
* @return the beneficiary of the tokens.
*/
function beneficiary() public view returns(address) {
function beneficiary() public view returns (address) {
return _beneficiary;
}
/**
* @return the cliff time of the token vesting.
*/
function cliff() public view returns(uint256) {
function cliff() public view returns (uint256) {
return _cliff;
}
/**
* @return the start time of the token vesting.
*/
function start() public view returns(uint256) {
function start() public view returns (uint256) {
return _start;
}
/**
* @return the duration of the token vesting.
*/
function duration() public view returns(uint256) {
function duration() public view returns (uint256) {
return _duration;
}
/**
* @return true if the vesting is revocable.
*/
function revocable() public view returns(bool) {
function revocable() public view returns (bool) {
return _revocable;
}
/**
* @return the amount of the token released.
*/
function released(address token) public view returns(uint256) {
function released(address token) public view returns (uint256) {
return _released[token];
}
/**
* @return true if the token is revoked.
*/
function revoked(address token) public view returns(bool) {
function revoked(address token) public view returns (bool) {
return _revoked[token];
}
@ -120,15 +116,15 @@ contract TokenVesting is Initializable, Ownable {
* @param token ERC20 token which is being vested
*/
function release(IERC20 token) public {
uint256 unreleased = releasableAmount(token);
uint256 unreleased = _releasableAmount(token);
require(unreleased > 0);
_released[token] = _released[token].add(unreleased);
_released[address(token)] = _released[address(token)].add(unreleased);
token.safeTransfer(_beneficiary, unreleased);
emit Released(unreleased);
emit TokensReleased(address(token), unreleased);
}
/**
@ -138,39 +134,39 @@ contract TokenVesting is Initializable, Ownable {
*/
function revoke(IERC20 token) public onlyOwner {
require(_revocable);
require(!_revoked[token]);
require(!_revoked[address(token)]);
uint256 balance = token.balanceOf(address(this));
uint256 unreleased = releasableAmount(token);
uint256 unreleased = _releasableAmount(token);
uint256 refund = balance.sub(unreleased);
_revoked[token] = true;
_revoked[address(token)] = true;
token.safeTransfer(owner(), refund);
emit Revoked();
emit TokenVestingRevoked(address(token));
}
/**
* @dev Calculates the amount that has already vested but hasn't been released yet.
* @param token ERC20 token which is being vested
*/
function releasableAmount(IERC20 token) public view returns (uint256) {
return vestedAmount(token).sub(_released[token]);
function _releasableAmount(IERC20 token) private view returns (uint256) {
return _vestedAmount(token).sub(_released[address(token)]);
}
/**
* @dev Calculates the amount that has already vested.
* @param token ERC20 token which is being vested
*/
function vestedAmount(IERC20 token) public view returns (uint256) {
uint256 currentBalance = token.balanceOf(this);
uint256 totalBalance = currentBalance.add(_released[token]);
function _vestedAmount(IERC20 token) private view returns (uint256) {
uint256 currentBalance = token.balanceOf(address(this));
uint256 totalBalance = currentBalance.add(_released[address(token)]);
if (block.timestamp < _cliff) {
return 0;
} else if (block.timestamp >= _start.add(_duration) || _revoked[token]) {
} else if (block.timestamp >= _start.add(_duration) || _revoked[address(token)]) {
return totalBalance;
} else {
return totalBalance.mul(block.timestamp.sub(_start)).div(_duration);