Commit 6f3ff8f9 by github-actions

Transpile 477046b2

parent bcec9aaf
<!-- 0. 🎉 Thank you for submitting a PR! --> <!-- Thank you for your interest in contributing to OpenZeppelin! -->
<!-- 1. Does this close any open issues? Please list them below. --> <!-- Consider opening an issue for discussion prior to submitting a PR. -->
<!-- New features will be merged faster if they were first discussed and designed with the team. -->
<!-- Keep in mind that new features have a better chance of being merged fast if Fixes #???? <!-- Fill in with issue number -->
they were first discussed and designed with the maintainers. If there is no
corresponding issue, please consider opening one for discussion first! -->
Fixes # <!-- Describe the changes introduced in this pull request. -->
<!-- Include any context necessary for understanding the PR's purpose. -->
<!-- 2. Describe the changes introduced in this pull request. -->
<!-- Include any context necessary for understanding the PR's purpose. -->
<!-- 3. Before submitting, please make sure that you have: #### PR Checklist
- reviewed the OpenZeppelin Contributor Guidelines
(https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/CONTRIBUTING.md), <!-- Before merging the pull request all of the following must be complete. -->
- added tests where applicable to test new functionality, <!-- Feel free to submit a PR or Draft PR even if some items are pending. -->
- made sure that your contracts are well-documented, <!-- Some of the items may not apply. -->
- 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 - [ ] Tests
- updated the changelog, if applicable. - [ ] Documentation
--> - [ ] Changelog entry
...@@ -12,7 +12,7 @@ jobs: ...@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions/setup-node@v1 - uses: actions/setup-node@v2
with: with:
node-version: 10.x node-version: 10.x
- uses: actions/cache@v2 - uses: actions/cache@v2
......
...@@ -25,6 +25,13 @@ ...@@ -25,6 +25,13 @@
* `ERC20Permit`: added an implementation of the ERC20 permit extension for gasless token approvals. ([#2237](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2237)) * `ERC20Permit`: added an implementation of the ERC20 permit extension for gasless token approvals. ([#2237](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2237))
* Presets: added token presets with preminted fixed supply `ERC20PresetFixedSupply` and `ERC777PresetFixedSupply`. ([#2399](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2399)) * Presets: added token presets with preminted fixed supply `ERC20PresetFixedSupply` and `ERC777PresetFixedSupply`. ([#2399](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2399))
* `Address`: added `functionDelegateCall`, similar to the existing `functionCall`. ([#2333](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2333)) * `Address`: added `functionDelegateCall`, similar to the existing `functionCall`. ([#2333](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2333))
* `Clones`: added a library for deploying EIP 1167 minimal proxies. ([#2449](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2449))
* `Context`: moved from `contracts/GSN` to `contracts/utils`. ([#2453](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2453))
* `PaymentSplitter`: replace usage of `.transfer()` with `Address.sendValue` for improved compatibility with smart wallets. ([#2455](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2455))
* `UpgradeableProxy`: bubble revert reasons from initialization calls. ([#2454](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2454))
* `SafeMath`: fix a memory allocation issue by adding new `SafeMath.tryOp(uint,uint)→(bool,uint)` functions. `SafeMath.op(uint,uint,string)→uint` are now deprecated. ([#2462](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2462))
* `EnumerableMap`: fix a memory allocation issue by adding new `EnumerableMap.tryGet(uint)→(bool,address)` functions. `EnumerableMap.get(uint)→string` is now deprecated. ([#2462](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2462))
* `ERC165Checker`: added batch `getSupportedInterfaces`. ([#2469](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2469))
## 3.3.0 (2020-11-26) ## 3.3.0 (2020-11-26)
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0; pragma solidity >=0.6.0 <0.8.0;
import "../proxy/Initializable.sol";
/* import "../utils/ContextUpgradeable.sol";
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with GSN meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal initializer {
__Context_init_unchained();
}
function __Context_init_unchained() internal initializer {
}
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
uint256[50] private __gap;
}
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
pragma solidity >=0.6.0 <0.8.0; pragma solidity >=0.6.0 <0.8.0;
import "../utils/ContextUpgradeable.sol";
import "./IRelayRecipientUpgradeable.sol"; import "./IRelayRecipientUpgradeable.sol";
import "./IRelayHubUpgradeable.sol"; import "./IRelayHubUpgradeable.sol";
import "./ContextUpgradeable.sol";
import "../proxy/Initializable.sol"; import "../proxy/Initializable.sol";
/** /**
......
...@@ -4,7 +4,7 @@ pragma solidity >=0.6.0 <0.8.0; ...@@ -4,7 +4,7 @@ pragma solidity >=0.6.0 <0.8.0;
import "../utils/EnumerableSetUpgradeable.sol"; import "../utils/EnumerableSetUpgradeable.sol";
import "../utils/AddressUpgradeable.sol"; import "../utils/AddressUpgradeable.sol";
import "../GSN/ContextUpgradeable.sol"; import "../utils/ContextUpgradeable.sol";
import "../proxy/Initializable.sol"; import "../proxy/Initializable.sol";
/** /**
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
pragma solidity >=0.6.0 <0.8.0; pragma solidity >=0.6.0 <0.8.0;
import "../GSN/ContextUpgradeable.sol"; import "../utils/ContextUpgradeable.sol";
import "../proxy/Initializable.sol"; import "../proxy/Initializable.sol";
/** /**
* @dev Contract module which provides a basic access control mechanism, where * @dev Contract module which provides a basic access control mechanism, where
......
...@@ -19,6 +19,8 @@ import "../proxy/Initializable.sol"; ...@@ -19,6 +19,8 @@ import "../proxy/Initializable.sol";
* is in charge of proposing (resp executing) operations. A common use case is * is in charge of proposing (resp executing) operations. A common use case is
* to position this {TimelockController} as the owner of a smart contract, with * to position this {TimelockController} as the owner of a smart contract, with
* a multisig or a DAO as the sole proposer. * a multisig or a DAO as the sole proposer.
*
* _Available since v3.3._
*/ */
contract TimelockControllerUpgradeable is Initializable, AccessControlUpgradeable { contract TimelockControllerUpgradeable is Initializable, AccessControlUpgradeable {
......
...@@ -43,7 +43,7 @@ abstract contract ERC20PermitUpgradeable is Initializable, ERC20Upgradeable, IER ...@@ -43,7 +43,7 @@ abstract contract ERC20PermitUpgradeable is Initializable, ERC20Upgradeable, IER
/** /**
* @dev See {IERC20Permit-permit}. * @dev See {IERC20Permit-permit}.
*/ */
function permit(address owner, address spender, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public virtual override { function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public virtual override {
// solhint-disable-next-line not-rely-on-time // solhint-disable-next-line not-rely-on-time
require(block.timestamp <= deadline, "ERC20Permit: expired deadline"); require(block.timestamp <= deadline, "ERC20Permit: expired deadline");
...@@ -52,7 +52,7 @@ abstract contract ERC20PermitUpgradeable is Initializable, ERC20Upgradeable, IER ...@@ -52,7 +52,7 @@ abstract contract ERC20PermitUpgradeable is Initializable, ERC20Upgradeable, IER
_PERMIT_TYPEHASH, _PERMIT_TYPEHASH,
owner, owner,
spender, spender,
amount, value,
_nonces[owner].current(), _nonces[owner].current(),
deadline deadline
) )
...@@ -64,7 +64,7 @@ abstract contract ERC20PermitUpgradeable is Initializable, ERC20Upgradeable, IER ...@@ -64,7 +64,7 @@ abstract contract ERC20PermitUpgradeable is Initializable, ERC20Upgradeable, IER
require(signer == owner, "ERC20Permit: invalid signature"); require(signer == owner, "ERC20Permit: invalid signature");
_nonces[owner].increment(); _nonces[owner].increment();
_approve(owner, spender, amount); _approve(owner, spender, value);
} }
/** /**
......
...@@ -12,7 +12,7 @@ pragma solidity >=0.6.0 <0.8.0; ...@@ -12,7 +12,7 @@ pragma solidity >=0.6.0 <0.8.0;
*/ */
interface IERC20PermitUpgradeable { interface IERC20PermitUpgradeable {
/** /**
* @dev Sets `amount` as the allowance of `spender` over `owner`'s tokens, * @dev Sets `value` as the allowance of `spender` over `owner`'s tokens,
* given `owner`'s signed approval. * given `owner`'s signed approval.
* *
* IMPORTANT: The same issues {IERC20-approve} has related to transaction * IMPORTANT: The same issues {IERC20-approve} has related to transaction
...@@ -32,7 +32,7 @@ interface IERC20PermitUpgradeable { ...@@ -32,7 +32,7 @@ interface IERC20PermitUpgradeable {
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section]. * section].
*/ */
function permit(address owner, address spender, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external; function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external;
/** /**
* @dev Returns the current nonce for `owner`. This value must be * @dev Returns the current nonce for `owner`. This value must be
......
...@@ -41,6 +41,29 @@ library ERC165CheckerUpgradeable { ...@@ -41,6 +41,29 @@ library ERC165CheckerUpgradeable {
} }
/** /**
* @dev Returns a boolean array where each value corresponds to the
* interfaces passed in and whether they're supported or not. This allows
* you to batch check interfaces for a contract where your expectation
* is that some interfaces may not be supported.
*
* See {IERC165-supportsInterface}.
*/
function getSupportedInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool[] memory) {
// an array of booleans corresponding to interfaceIds and whether they're supported or not
bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);
// query support of ERC165 itself
if (supportsERC165(account)) {
// query support of each interface in interfaceIds
for (uint256 i = 0; i < interfaceIds.length; i++) {
interfaceIdsSupported[i] = _supportsERC165Interface(account, interfaceIds[i]);
}
}
return interfaceIdsSupported;
}
/**
* @dev Returns true if `account` supports all the interfaces defined in * @dev Returns true if `account` supports all the interfaces defined in
* `interfaceIds`. Support for {IERC165} itself is queried automatically. * `interfaceIds`. Support for {IERC165} itself is queried automatically.
* *
......
...@@ -17,6 +17,52 @@ pragma solidity >=0.6.0 <0.8.0; ...@@ -17,6 +17,52 @@ pragma solidity >=0.6.0 <0.8.0;
*/ */
library SafeMathUpgradeable { library SafeMathUpgradeable {
/** /**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
/**
* @dev Returns the substraction of two unsigned integers, with an overflow flag.
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b > a) return (false, 0);
return (true, a - b);
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
// 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-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a / b);
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a % b);
}
/**
* @dev Returns the addition of two unsigned integers, reverting on * @dev Returns the addition of two unsigned integers, reverting on
* overflow. * overflow.
* *
...@@ -29,7 +75,6 @@ library SafeMathUpgradeable { ...@@ -29,7 +75,6 @@ library SafeMathUpgradeable {
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, "SafeMath: addition overflow"); require(c >= a, "SafeMath: addition overflow");
return c; return c;
} }
...@@ -44,24 +89,8 @@ library SafeMathUpgradeable { ...@@ -44,24 +89,8 @@ library SafeMathUpgradeable {
* - Subtraction cannot overflow. * - Subtraction cannot overflow.
*/ */
function sub(uint256 a, uint256 b) internal pure returns (uint256) { function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow"); require(b <= a, "SafeMath: subtraction overflow");
} return a - b;
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
} }
/** /**
...@@ -75,21 +104,14 @@ library SafeMathUpgradeable { ...@@ -75,21 +104,14 @@ library SafeMathUpgradeable {
* - Multiplication cannot overflow. * - Multiplication cannot 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 if (a == 0) return 0;
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b; uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow"); require(c / a == b, "SafeMath: multiplication overflow");
return c; return c;
} }
/** /**
* @dev Returns the integer division of two unsigned integers. Reverts on * @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero. * division by zero. The result is rounded towards zero.
* *
* Counterpart to Solidity's `/` operator. Note: this function uses a * Counterpart to Solidity's `/` operator. Note: this function uses a
...@@ -101,48 +123,71 @@ library SafeMathUpgradeable { ...@@ -101,48 +123,71 @@ library SafeMathUpgradeable {
* - The divisor cannot be zero. * - The divisor cannot be zero.
*/ */
function div(uint256 a, uint256 b) internal pure returns (uint256) { function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero"); require(b > 0, "SafeMath: division by zero");
return a / b;
} }
/** /**
* @dev Returns the integer division of two unsigned integers. Reverts with custom message on * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* division by zero. The result is rounded towards zero. * reverting when dividing by zero.
* *
* Counterpart to Solidity's `/` operator. Note: this function uses a * Counterpart to Solidity's `%` operator. This function uses a `revert`
* `revert` opcode (which leaves remaining gas untouched) while Solidity * opcode (which leaves remaining gas untouched) while Solidity uses an
* uses an invalid opcode to revert (consuming all remaining gas). * invalid opcode to revert (consuming all remaining gas).
* *
* Requirements: * Requirements:
* *
* - The divisor cannot be zero. * - The divisor cannot be zero.
*/ */
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, errorMessage); require(b > 0, "SafeMath: modulo by zero");
uint256 c = a / b; return a % b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold }
return c; /**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
return a - b;
} }
/** /**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * @dev Returns the integer division of two unsigned integers, reverting with custom message on
* Reverts when dividing by zero. * division by zero. The result is rounded towards zero.
* *
* Counterpart to Solidity's `%` operator. This function uses a `revert` * CAUTION: This function is deprecated because it requires allocating memory for the error
* opcode (which leaves remaining gas untouched) while Solidity uses an * message unnecessarily. For custom revert reasons use {tryDiv}.
* invalid opcode to revert (consuming all remaining gas). *
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
* *
* Requirements: * Requirements:
* *
* - The divisor cannot be zero. * - The divisor cannot be zero.
*/ */
function mod(uint256 a, uint256 b) internal pure returns (uint256) { function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero"); require(b > 0, errorMessage);
return a / b;
} }
/** /**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts with custom message when dividing by zero. * reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
* *
* Counterpart to Solidity's `%` operator. This function uses a `revert` * Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an * opcode (which leaves remaining gas untouched) while Solidity uses an
...@@ -153,7 +198,7 @@ library SafeMathUpgradeable { ...@@ -153,7 +198,7 @@ library SafeMathUpgradeable {
* - The divisor cannot be zero. * - The divisor cannot be zero.
*/ */
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage); require(b > 0, errorMessage);
return a % b; return a % b;
} }
} }
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
import "../proxy/ClonesUpgradeable.sol";
import "../utils/AddressUpgradeable.sol";
import "../proxy/Initializable.sol";
contract ClonesMockUpgradeable is Initializable {
function __ClonesMock_init() internal initializer {
__ClonesMock_init_unchained();
}
function __ClonesMock_init_unchained() internal initializer {
}
using AddressUpgradeable for address;
using ClonesUpgradeable for address;
event NewInstance(address instance);
function clone(address master, bytes calldata initdata) public payable {
_initAndEmit(master.clone(), initdata);
}
function cloneDeterministic(address master, bytes32 salt, bytes calldata initdata) public payable {
_initAndEmit(master.cloneDeterministic(salt), initdata);
}
function predictDeterministicAddress(address master, bytes32 salt) public view returns (address predicted) {
return master.predictDeterministicAddress(salt);
}
function _initAndEmit(address instance, bytes memory initdata) private {
if (initdata.length > 0) {
instance.functionCallWithValue(initdata, msg.value);
}
emit NewInstance(instance);
}
uint256[50] private __gap;
}
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
pragma solidity >=0.6.0 <0.8.0; pragma solidity >=0.6.0 <0.8.0;
import "../GSN/ContextUpgradeable.sol"; import "../utils/ContextUpgradeable.sol";
import "../proxy/Initializable.sol"; import "../proxy/Initializable.sol";
contract ContextMockUpgradeable is Initializable, ContextUpgradeable { contract ContextMockUpgradeable is Initializable, ContextUpgradeable {
......
...@@ -25,5 +25,9 @@ contract ERC165CheckerMockUpgradeable is Initializable { ...@@ -25,5 +25,9 @@ contract ERC165CheckerMockUpgradeable is Initializable {
function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) public view returns (bool) { function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) public view returns (bool) {
return account.supportsAllInterfaces(interfaceIds); return account.supportsAllInterfaces(interfaceIds);
} }
function getSupportedInterfaces(address account, bytes4[] memory interfaceIds) public view returns (bool[] memory) {
return account.getSupportedInterfaces(interfaceIds);
}
uint256[50] private __gap; uint256[50] private __gap;
} }
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
pragma solidity >=0.6.0 <0.8.0; pragma solidity >=0.6.0 <0.8.0;
import "../GSN/ContextUpgradeable.sol"; import "../utils/ContextUpgradeable.sol";
import "../token/ERC777/ERC777Upgradeable.sol"; import "../token/ERC777/ERC777Upgradeable.sol";
import "../proxy/Initializable.sol"; import "../proxy/Initializable.sol";
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
pragma solidity >=0.6.0 <0.8.0; pragma solidity >=0.6.0 <0.8.0;
import "../GSN/ContextUpgradeable.sol"; import "../utils/ContextUpgradeable.sol";
import "../token/ERC777/IERC777Upgradeable.sol"; import "../token/ERC777/IERC777Upgradeable.sol";
import "../token/ERC777/IERC777SenderUpgradeable.sol"; import "../token/ERC777/IERC777SenderUpgradeable.sol";
import "../token/ERC777/IERC777RecipientUpgradeable.sol"; import "../token/ERC777/IERC777RecipientUpgradeable.sol";
......
...@@ -41,8 +41,16 @@ contract EnumerableMapMockUpgradeable is Initializable { ...@@ -41,8 +41,16 @@ contract EnumerableMapMockUpgradeable is Initializable {
} }
function tryGet(uint256 key) public view returns (bool, address) {
return _map.tryGet(key);
}
function get(uint256 key) public view returns (address) { function get(uint256 key) public view returns (address) {
return _map.get(key); return _map.get(key);
} }
function getWithMessage(uint256 key, string calldata errorMessage) public view returns (address) {
return _map.get(key, errorMessage);
}
uint256[48] private __gap; uint256[48] private __gap;
} }
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
pragma solidity >=0.6.0 <0.8.0; pragma solidity >=0.6.0 <0.8.0;
import "../GSN/ContextUpgradeable.sol"; import "../utils/ContextUpgradeable.sol";
import "../proxy/Initializable.sol"; import "../proxy/Initializable.sol";
contract ReentrancyAttackUpgradeable is Initializable, ContextUpgradeable { contract ReentrancyAttackUpgradeable is Initializable, ContextUpgradeable {
function __ReentrancyAttack_init() internal initializer { function __ReentrancyAttack_init() internal initializer {
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
pragma solidity >=0.6.0 <0.8.0; pragma solidity >=0.6.0 <0.8.0;
import "../GSN/ContextUpgradeable.sol"; import "../utils/ContextUpgradeable.sol";
import "../token/ERC20/IERC20Upgradeable.sol"; import "../token/ERC20/IERC20Upgradeable.sol";
import "../token/ERC20/SafeERC20Upgradeable.sol"; import "../token/ERC20/SafeERC20Upgradeable.sol";
import "../proxy/Initializable.sol"; import "../proxy/Initializable.sol";
......
...@@ -12,24 +12,102 @@ contract SafeMathMockUpgradeable is Initializable { ...@@ -12,24 +12,102 @@ contract SafeMathMockUpgradeable is Initializable {
function __SafeMathMock_init_unchained() internal initializer { function __SafeMathMock_init_unchained() internal initializer {
} }
function mul(uint256 a, uint256 b) public pure returns (uint256) { function tryAdd(uint256 a, uint256 b) public pure returns (bool flag, uint256 value) {
return SafeMathUpgradeable.mul(a, b); return SafeMathUpgradeable.tryAdd(a, b);
} }
function div(uint256 a, uint256 b) public pure returns (uint256) { function trySub(uint256 a, uint256 b) public pure returns (bool flag, uint256 value) {
return SafeMathUpgradeable.div(a, b); return SafeMathUpgradeable.trySub(a, b);
} }
function sub(uint256 a, uint256 b) public pure returns (uint256) { function tryMul(uint256 a, uint256 b) public pure returns (bool flag, uint256 value) {
return SafeMathUpgradeable.sub(a, b); return SafeMathUpgradeable.tryMul(a, b);
}
function tryDiv(uint256 a, uint256 b) public pure returns (bool flag, uint256 value) {
return SafeMathUpgradeable.tryDiv(a, b);
}
function tryMod(uint256 a, uint256 b) public pure returns (bool flag, uint256 value) {
return SafeMathUpgradeable.tryMod(a, b);
} }
function add(uint256 a, uint256 b) public pure returns (uint256) { function add(uint256 a, uint256 b) public pure returns (uint256) {
return SafeMathUpgradeable.add(a, b); return SafeMathUpgradeable.add(a, b);
} }
function sub(uint256 a, uint256 b) public pure returns (uint256) {
return SafeMathUpgradeable.sub(a, b);
}
function mul(uint256 a, uint256 b) public pure returns (uint256) {
return SafeMathUpgradeable.mul(a, b);
}
function div(uint256 a, uint256 b) public pure returns (uint256) {
return SafeMathUpgradeable.div(a, b);
}
function mod(uint256 a, uint256 b) public pure returns (uint256) { function mod(uint256 a, uint256 b) public pure returns (uint256) {
return SafeMathUpgradeable.mod(a, b); return SafeMathUpgradeable.mod(a, b);
} }
function subWithMessage(uint256 a, uint256 b, string memory errorMessage) public pure returns (uint256) {
return SafeMathUpgradeable.sub(a, b, errorMessage);
}
function divWithMessage(uint256 a, uint256 b, string memory errorMessage) public pure returns (uint256) {
return SafeMathUpgradeable.div(a, b, errorMessage);
}
function modWithMessage(uint256 a, uint256 b, string memory errorMessage) public pure returns (uint256) {
return SafeMathUpgradeable.mod(a, b, errorMessage);
}
function addMemoryCheck() public pure returns (uint256 mem) {
uint256 length = 32;
// solhint-disable-next-line no-inline-assembly
assembly { mem := mload(0x40) }
for (uint256 i = 0; i < length; ++i) { SafeMathUpgradeable.add(1, 1); }
// solhint-disable-next-line no-inline-assembly
assembly { mem := sub(mload(0x40), mem) }
}
function subMemoryCheck() public pure returns (uint256 mem) {
uint256 length = 32;
// solhint-disable-next-line no-inline-assembly
assembly { mem := mload(0x40) }
for (uint256 i = 0; i < length; ++i) { SafeMathUpgradeable.sub(1, 1); }
// solhint-disable-next-line no-inline-assembly
assembly { mem := sub(mload(0x40), mem) }
}
function mulMemoryCheck() public pure returns (uint256 mem) {
uint256 length = 32;
// solhint-disable-next-line no-inline-assembly
assembly { mem := mload(0x40) }
for (uint256 i = 0; i < length; ++i) { SafeMathUpgradeable.mul(1, 1); }
// solhint-disable-next-line no-inline-assembly
assembly { mem := sub(mload(0x40), mem) }
}
function divMemoryCheck() public pure returns (uint256 mem) {
uint256 length = 32;
// solhint-disable-next-line no-inline-assembly
assembly { mem := mload(0x40) }
for (uint256 i = 0; i < length; ++i) { SafeMathUpgradeable.div(1, 1); }
// solhint-disable-next-line no-inline-assembly
assembly { mem := sub(mload(0x40), mem) }
}
function modMemoryCheck() public pure returns (uint256 mem) {
uint256 length = 32;
// solhint-disable-next-line no-inline-assembly
assembly { mem := mload(0x40) }
for (uint256 i = 0; i < length; ++i) { SafeMathUpgradeable.mod(1, 1); }
// solhint-disable-next-line no-inline-assembly
assembly { mem := sub(mload(0x40), mem) }
}
uint256[50] private __gap; uint256[50] private __gap;
} }
...@@ -92,6 +92,13 @@ contract ClashingImplementationUpgradeableWithInit is ClashingImplementationUpgr ...@@ -92,6 +92,13 @@ contract ClashingImplementationUpgradeableWithInit is ClashingImplementationUpgr
__ClashingImplementation_init(); __ClashingImplementation_init();
} }
} }
import "./ClonesMockUpgradeable.sol";
contract ClonesMockUpgradeableWithInit is ClonesMockUpgradeable {
constructor() public payable {
__ClonesMock_init();
}
}
import "./ConditionalEscrowMockUpgradeable.sol"; import "./ConditionalEscrowMockUpgradeable.sol";
contract ConditionalEscrowMockUpgradeableWithInit is ConditionalEscrowMockUpgradeable { contract ConditionalEscrowMockUpgradeableWithInit is ConditionalEscrowMockUpgradeable {
......
...@@ -2,8 +2,9 @@ ...@@ -2,8 +2,9 @@
pragma solidity >=0.6.0 <0.8.0; pragma solidity >=0.6.0 <0.8.0;
import "../GSN/ContextUpgradeable.sol"; import "../utils/ContextUpgradeable.sol";
import "../math/SafeMathUpgradeable.sol"; import "../math/SafeMathUpgradeable.sol";
import "../utils/AddressUpgradeable.sol";
import "../proxy/Initializable.sol"; import "../proxy/Initializable.sol";
/** /**
...@@ -118,7 +119,7 @@ contract PaymentSplitterUpgradeable is Initializable, ContextUpgradeable { ...@@ -118,7 +119,7 @@ contract PaymentSplitterUpgradeable is Initializable, ContextUpgradeable {
_released[account] = _released[account].add(payment); _released[account] = _released[account].add(payment);
_totalReleased = _totalReleased.add(payment); _totalReleased = _totalReleased.add(payment);
account.transfer(payment); AddressUpgradeable.sendValue(account, payment);
emit PaymentReleased(account, payment); emit PaymentReleased(account, payment);
} }
......
...@@ -48,7 +48,7 @@ contract EscrowUpgradeable is Initializable, OwnableUpgradeable { ...@@ -48,7 +48,7 @@ contract EscrowUpgradeable is Initializable, OwnableUpgradeable {
* @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 virtual payable onlyOwner { function deposit(address payee) public payable virtual onlyOwner {
uint256 amount = msg.value; uint256 amount = msg.value;
_deposits[payee] = _deposits[payee].add(amount); _deposits[payee] = _deposits[payee].add(amount);
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
pragma solidity >=0.6.0 <0.8.0; pragma solidity >=0.6.0 <0.8.0;
import "../access/AccessControlUpgradeable.sol"; import "../access/AccessControlUpgradeable.sol";
import "../GSN/ContextUpgradeable.sol"; import "../utils/ContextUpgradeable.sol";
import "../token/ERC1155/ERC1155Upgradeable.sol"; import "../token/ERC1155/ERC1155Upgradeable.sol";
import "../token/ERC1155/ERC1155BurnableUpgradeable.sol"; import "../token/ERC1155/ERC1155BurnableUpgradeable.sol";
import "../token/ERC1155/ERC1155PausableUpgradeable.sol"; import "../token/ERC1155/ERC1155PausableUpgradeable.sol";
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
pragma solidity >=0.6.0 <0.8.0; pragma solidity >=0.6.0 <0.8.0;
import "../access/AccessControlUpgradeable.sol"; import "../access/AccessControlUpgradeable.sol";
import "../GSN/ContextUpgradeable.sol"; import "../utils/ContextUpgradeable.sol";
import "../token/ERC20/ERC20Upgradeable.sol"; import "../token/ERC20/ERC20Upgradeable.sol";
import "../token/ERC20/ERC20BurnableUpgradeable.sol"; import "../token/ERC20/ERC20BurnableUpgradeable.sol";
import "../token/ERC20/ERC20PausableUpgradeable.sol"; import "../token/ERC20/ERC20PausableUpgradeable.sol";
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
pragma solidity >=0.6.0 <0.8.0; pragma solidity >=0.6.0 <0.8.0;
import "../access/AccessControlUpgradeable.sol"; import "../access/AccessControlUpgradeable.sol";
import "../GSN/ContextUpgradeable.sol"; import "../utils/ContextUpgradeable.sol";
import "../utils/CountersUpgradeable.sol"; import "../utils/CountersUpgradeable.sol";
import "../token/ERC721/ERC721Upgradeable.sol"; import "../token/ERC721/ERC721Upgradeable.sol";
import "../token/ERC721/ERC721BurnableUpgradeable.sol"; import "../token/ERC721/ERC721BurnableUpgradeable.sol";
......
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
/**
* @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
* deploying minimal proxy contracts, also known as "clones".
*
* > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
* > a minimal bytecode implementation that delegates all calls to a known, fixed address.
*
* The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
* (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
* deterministic method.
*/
library ClonesUpgradeable {
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `master`.
*
* This function uses the create opcode, which should never revert.
*/
function clone(address master) internal returns (address instance) {
// solhint-disable-next-line no-inline-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
mstore(add(ptr, 0x14), shl(0x60, master))
mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
instance := create(0, ptr, 0x37)
}
require(instance != address(0), "ERC1167: create failed");
}
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `master`.
*
* This function uses the create2 opcode and a `salt` to deterministically deploy
* the clone. Using the same `master` and `salt` multiple time will revert, since
* the clones cannot be deployed twice at the same address.
*/
function cloneDeterministic(address master, bytes32 salt) internal returns (address instance) {
// solhint-disable-next-line no-inline-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
mstore(add(ptr, 0x14), shl(0x60, master))
mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
instance := create2(0, ptr, 0x37, salt)
}
require(instance != address(0), "ERC1167: create2 failed");
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(address master, bytes32 salt, address deployer) internal pure returns (address predicted) {
// solhint-disable-next-line no-inline-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
mstore(add(ptr, 0x14), shl(0x60, master))
mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000)
mstore(add(ptr, 0x38), shl(0x60, deployer))
mstore(add(ptr, 0x4c), salt)
mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))
predicted := keccak256(add(ptr, 0x37), 0x55)
}
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(address master, bytes32 salt) internal view returns (address predicted) {
return predictDeterministicAddress(master, salt, address(this));
}
}
...@@ -3,16 +3,17 @@ ...@@ -3,16 +3,17 @@
// solhint-disable-next-line compiler-version // solhint-disable-next-line compiler-version
pragma solidity >=0.4.24 <0.8.0; pragma solidity >=0.4.24 <0.8.0;
import "../utils/Address.sol";
/** /**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
* *
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}. * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}.
* *
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*/ */
...@@ -49,15 +50,6 @@ abstract contract Initializable { ...@@ -49,15 +50,6 @@ abstract contract Initializable {
/// @dev Returns true if and only if the function is running in the constructor /// @dev Returns true if and only if the function is running in the constructor
function _isConstructor() private view returns (bool) { function _isConstructor() private view returns (bool) {
// extcodesize checks the size of the code stored in an address, and return !Address.isContract(address(this));
// address returns the current address. Since the code is still not
// deployed when running a constructor, any checks on its code size will
// yield zero, making it an effective way to detect if a contract is
// under construction or not.
address self = address(this);
uint256 cs;
// solhint-disable-next-line no-inline-assembly
assembly { cs := extcodesize(self) }
return cs == 0;
} }
} }
...@@ -3,13 +3,15 @@ ...@@ -3,13 +3,15 @@
[.readme-notice] [.readme-notice]
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/proxy NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/proxy
This is a low-level set of contracts implementing the proxy pattern for upgradeability. For an in-depth overview of this pattern check out the xref:upgrades-plugins::proxies.adoc[Proxy Upgrade Pattern] page. This is a low-level set of contracts implementing different proxy patterns with and without upgradeability. For an in-depth overview of this pattern check out the xref:upgrades-plugins::proxies.adoc[Proxy Upgrade Pattern] page.
The abstract {Proxy} contract implements the core delegation functionality. If the concrete proxies that we provide below are not suitable, we encourage building on top of this base contract since it contains an assembly block that may be hard to get right. The abstract {Proxy} contract implements the core delegation functionality. If the concrete proxies that we provide below are not suitable, we encourage building on top of this base contract since it contains an assembly block that may be hard to get right.
Upgradeability is implemented in the {UpgradeableProxy} contract, although it provides only an internal upgrade interface. For an upgrade interface exposed externally to an admin, we provide {TransparentUpgradeableProxy}. Both of these contracts use the storage slots specified in https://eips.ethereum.org/EIPS/eip-1967[EIP1967] to avoid clashes with the storage of the implementation contract behind the proxy. Upgradeability is implemented in the {UpgradeableProxy} contract, although it provides only an internal upgrade interface. For an upgrade interface exposed externally to an admin, we provide {TransparentUpgradeableProxy}. Both of these contracts use the storage slots specified in https://eips.ethereum.org/EIPS/eip-1967[EIP1967] to avoid clashes with the storage of the implementation contract behind the proxy.
An alternative upgradeability mechanism is provided in <<UpgradeableBeacon>>. This pattern, popularized by Dharma, allows multiple proxies to be upgraded to a different implementation in a single transaction. In this pattern, the proxy contract doesn't hold the implementation address in storage like {UpgradeableProxy}, but the address of a {UpgradeableBeacon} contract, which is where the implementation address is actually stored and retrieved from. The `upgrade` operations that change the implementation contract address are then sent to the beacon instead of to the proxy contract, and all proxies that follow that beacon are automatically upgraded. An alternative upgradeability mechanism is provided in <<Beacon>>. This pattern, popularized by Dharma, allows multiple proxies to be upgraded to a different implementation in a single transaction. In this pattern, the proxy contract doesn't hold the implementation address in storage like {UpgradeableProxy}, but the address of a {UpgradeableBeacon} contract, which is where the implementation address is actually stored and retrieved from. The `upgrade` operations that change the implementation contract address are then sent to the beacon instead of to the proxy contract, and all proxies that follow that beacon are automatically upgraded.
The {Clones} library provides a way to deploy minimal non-upgradeable proxies for cheap. This can be useful for applications that require deploying many instances of the same contract (for example one per user, or one per task). These instances are designed to be both cheap to deploy, and cheap to call. The drawback being that they are not upgradeable.
CAUTION: Using upgradeable proxies correctly and securely is a difficult task that requires deep knowledge of the proxy pattern, Solidity, and the EVM. Unless you want a lot of low level control, we recommend using the xref:upgrades-plugins::index.adoc[OpenZeppelin Upgrades Plugins] for Truffle and Buidler. CAUTION: Using upgradeable proxies correctly and securely is a difficult task that requires deep knowledge of the proxy pattern, Solidity, and the EVM. Unless you want a lot of low level control, we recommend using the xref:upgrades-plugins::index.adoc[OpenZeppelin Upgrades Plugins] for Truffle and Buidler.
...@@ -21,7 +23,7 @@ CAUTION: Using upgradeable proxies correctly and securely is a difficult task th ...@@ -21,7 +23,7 @@ CAUTION: Using upgradeable proxies correctly and securely is a difficult task th
{{TransparentUpgradeableProxy}} {{TransparentUpgradeableProxy}}
== UpgradeableBeacon == Beacon
{{BeaconProxy}} {{BeaconProxy}}
...@@ -29,6 +31,10 @@ CAUTION: Using upgradeable proxies correctly and securely is a difficult task th ...@@ -29,6 +31,10 @@ CAUTION: Using upgradeable proxies correctly and securely is a difficult task th
{{UpgradeableBeacon}} {{UpgradeableBeacon}}
== Minimal Clones
{{Clones}}
== Utilities == Utilities
{{Initializable}} {{Initializable}}
......
...@@ -40,7 +40,9 @@ abstract contract ERC1155PausableUpgradeable is Initializable, ERC1155Upgradeabl ...@@ -40,7 +40,9 @@ abstract contract ERC1155PausableUpgradeable is Initializable, ERC1155Upgradeabl
uint256[] memory amounts, uint256[] memory amounts,
bytes memory data bytes memory data
) )
internal virtual override internal
virtual
override
{ {
super._beforeTokenTransfer(operator, from, to, ids, amounts, data); super._beforeTokenTransfer(operator, from, to, ids, amounts, data);
......
...@@ -5,7 +5,7 @@ pragma solidity >=0.6.0 <0.8.0; ...@@ -5,7 +5,7 @@ pragma solidity >=0.6.0 <0.8.0;
import "./IERC1155Upgradeable.sol"; import "./IERC1155Upgradeable.sol";
import "./IERC1155MetadataURIUpgradeable.sol"; import "./IERC1155MetadataURIUpgradeable.sol";
import "./IERC1155ReceiverUpgradeable.sol"; import "./IERC1155ReceiverUpgradeable.sol";
import "../../GSN/ContextUpgradeable.sol"; import "../../utils/ContextUpgradeable.sol";
import "../../introspection/ERC165Upgradeable.sol"; import "../../introspection/ERC165Upgradeable.sol";
import "../../math/SafeMathUpgradeable.sol"; import "../../math/SafeMathUpgradeable.sol";
import "../../utils/AddressUpgradeable.sol"; import "../../utils/AddressUpgradeable.sol";
...@@ -362,7 +362,8 @@ contract ERC1155Upgradeable is Initializable, ContextUpgradeable, ERC165Upgradea ...@@ -362,7 +362,8 @@ contract ERC1155Upgradeable is Initializable, ContextUpgradeable, ERC165Upgradea
uint256[] memory amounts, uint256[] memory amounts,
bytes memory data bytes memory data
) )
internal virtual internal
virtual
{ } { }
function _doSafeTransferAcceptanceCheck( function _doSafeTransferAcceptanceCheck(
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
pragma solidity >=0.6.0 <0.8.0; pragma solidity >=0.6.0 <0.8.0;
import "../../GSN/ContextUpgradeable.sol"; import "../../utils/ContextUpgradeable.sol";
import "./ERC20Upgradeable.sol"; import "./ERC20Upgradeable.sol";
import "../../proxy/Initializable.sol"; import "../../proxy/Initializable.sol";
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
pragma solidity >=0.6.0 <0.8.0; pragma solidity >=0.6.0 <0.8.0;
import "../../GSN/ContextUpgradeable.sol"; import "../../utils/ContextUpgradeable.sol";
import "./IERC20Upgradeable.sol"; import "./IERC20Upgradeable.sol";
import "../../math/SafeMathUpgradeable.sol"; import "../../math/SafeMathUpgradeable.sol";
import "../../proxy/Initializable.sol"; import "../../proxy/Initializable.sol";
...@@ -290,7 +290,7 @@ contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeabl ...@@ -290,7 +290,7 @@ contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeabl
* applications that interact with token contracts will not expect * applications that interact with token contracts will not expect
* {decimals} to ever change, and may work incorrectly if it does. * {decimals} to ever change, and may work incorrectly if it does.
*/ */
function _setupDecimals(uint8 decimals_) internal { function _setupDecimals(uint8 decimals_) internal virtual {
_decimals = decimals_; _decimals = decimals_;
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
pragma solidity >=0.6.0 <0.8.0; pragma solidity >=0.6.0 <0.8.0;
import "../../GSN/ContextUpgradeable.sol"; import "../../utils/ContextUpgradeable.sol";
import "./ERC721Upgradeable.sol"; import "./ERC721Upgradeable.sol";
import "../../proxy/Initializable.sol"; import "../../proxy/Initializable.sol";
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
pragma solidity >=0.6.0 <0.8.0; pragma solidity >=0.6.0 <0.8.0;
import "../../GSN/ContextUpgradeable.sol"; import "../../utils/ContextUpgradeable.sol";
import "./IERC721Upgradeable.sol"; import "./IERC721Upgradeable.sol";
import "./IERC721MetadataUpgradeable.sol"; import "./IERC721MetadataUpgradeable.sol";
import "./IERC721EnumerableUpgradeable.sol"; import "./IERC721EnumerableUpgradeable.sol";
......
...@@ -117,8 +117,8 @@ interface IERC721Upgradeable is IERC165Upgradeable { ...@@ -117,8 +117,8 @@ interface IERC721Upgradeable is IERC165Upgradeable {
* *
* Requirements: * Requirements:
* *
* - `from` cannot be the zero address. * - `from` cannot be the zero address.
* - `to` cannot be the zero address. * - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`. * - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
pragma solidity >=0.6.0 <0.8.0; pragma solidity >=0.6.0 <0.8.0;
import "../../GSN/ContextUpgradeable.sol"; import "../../utils/ContextUpgradeable.sol";
import "./IERC777Upgradeable.sol"; import "./IERC777Upgradeable.sol";
import "./IERC777RecipientUpgradeable.sol"; import "./IERC777RecipientUpgradeable.sol";
import "./IERC777SenderUpgradeable.sol"; import "./IERC777SenderUpgradeable.sol";
...@@ -146,7 +146,7 @@ contract ERC777Upgradeable is Initializable, ContextUpgradeable, IERC777Upgradea ...@@ -146,7 +146,7 @@ contract ERC777Upgradeable is Initializable, ContextUpgradeable, IERC777Upgradea
* *
* Also emits a {IERC20-Transfer} event for ERC20 compatibility. * Also emits a {IERC20-Transfer} event for ERC20 compatibility.
*/ */
function send(address recipient, uint256 amount, bytes memory data) public override { function send(address recipient, uint256 amount, bytes memory data) public virtual override {
_send(_msgSender(), recipient, amount, data, "", true); _send(_msgSender(), recipient, amount, data, "", true);
} }
...@@ -158,7 +158,7 @@ contract ERC777Upgradeable is Initializable, ContextUpgradeable, IERC777Upgradea ...@@ -158,7 +158,7 @@ contract ERC777Upgradeable is Initializable, ContextUpgradeable, IERC777Upgradea
* *
* Also emits a {Sent} event. * Also emits a {Sent} event.
*/ */
function transfer(address recipient, uint256 amount) public override returns (bool) { function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
require(recipient != address(0), "ERC777: transfer to the zero address"); require(recipient != address(0), "ERC777: transfer to the zero address");
address from = _msgSender(); address from = _msgSender();
...@@ -177,17 +177,14 @@ contract ERC777Upgradeable is Initializable, ContextUpgradeable, IERC777Upgradea ...@@ -177,17 +177,14 @@ contract ERC777Upgradeable is Initializable, ContextUpgradeable, IERC777Upgradea
* *
* Also emits a {IERC20-Transfer} event for ERC20 compatibility. * Also emits a {IERC20-Transfer} event for ERC20 compatibility.
*/ */
function burn(uint256 amount, bytes memory data) public override { function burn(uint256 amount, bytes memory data) public virtual override {
_burn(_msgSender(), amount, data, ""); _burn(_msgSender(), amount, data, "");
} }
/** /**
* @dev See {IERC777-isOperatorFor}. * @dev See {IERC777-isOperatorFor}.
*/ */
function isOperatorFor( function isOperatorFor(address operator, address tokenHolder) public view override returns (bool) {
address operator,
address tokenHolder
) public view override returns (bool) {
return operator == tokenHolder || return operator == tokenHolder ||
(_defaultOperators[operator] && !_revokedDefaultOperators[tokenHolder][operator]) || (_defaultOperators[operator] && !_revokedDefaultOperators[tokenHolder][operator]) ||
_operators[tokenHolder][operator]; _operators[tokenHolder][operator];
...@@ -196,7 +193,7 @@ contract ERC777Upgradeable is Initializable, ContextUpgradeable, IERC777Upgradea ...@@ -196,7 +193,7 @@ contract ERC777Upgradeable is Initializable, ContextUpgradeable, IERC777Upgradea
/** /**
* @dev See {IERC777-authorizeOperator}. * @dev See {IERC777-authorizeOperator}.
*/ */
function authorizeOperator(address operator) public override { function authorizeOperator(address operator) public virtual override {
require(_msgSender() != operator, "ERC777: authorizing self as operator"); require(_msgSender() != operator, "ERC777: authorizing self as operator");
if (_defaultOperators[operator]) { if (_defaultOperators[operator]) {
...@@ -211,7 +208,7 @@ contract ERC777Upgradeable is Initializable, ContextUpgradeable, IERC777Upgradea ...@@ -211,7 +208,7 @@ contract ERC777Upgradeable is Initializable, ContextUpgradeable, IERC777Upgradea
/** /**
* @dev See {IERC777-revokeOperator}. * @dev See {IERC777-revokeOperator}.
*/ */
function revokeOperator(address operator) public override { function revokeOperator(address operator) public virtual override {
require(operator != _msgSender(), "ERC777: revoking self as operator"); require(operator != _msgSender(), "ERC777: revoking self as operator");
if (_defaultOperators[operator]) { if (_defaultOperators[operator]) {
...@@ -242,7 +239,9 @@ contract ERC777Upgradeable is Initializable, ContextUpgradeable, IERC777Upgradea ...@@ -242,7 +239,9 @@ contract ERC777Upgradeable is Initializable, ContextUpgradeable, IERC777Upgradea
bytes memory data, bytes memory data,
bytes memory operatorData bytes memory operatorData
) )
public override public
virtual
override
{ {
require(isOperatorFor(_msgSender(), sender), "ERC777: caller is not an operator for holder"); require(isOperatorFor(_msgSender(), sender), "ERC777: caller is not an operator for holder");
_send(sender, recipient, amount, data, operatorData, true); _send(sender, recipient, amount, data, operatorData, true);
...@@ -253,7 +252,7 @@ contract ERC777Upgradeable is Initializable, ContextUpgradeable, IERC777Upgradea ...@@ -253,7 +252,7 @@ contract ERC777Upgradeable is Initializable, ContextUpgradeable, IERC777Upgradea
* *
* Emits {Burned} and {IERC20-Transfer} events. * Emits {Burned} and {IERC20-Transfer} events.
*/ */
function operatorBurn(address account, uint256 amount, bytes memory data, bytes memory operatorData) public override { function operatorBurn(address account, uint256 amount, bytes memory data, bytes memory operatorData) public virtual override {
require(isOperatorFor(_msgSender(), account), "ERC777: caller is not an operator for holder"); require(isOperatorFor(_msgSender(), account), "ERC777: caller is not an operator for holder");
_burn(account, amount, data, operatorData); _burn(account, amount, data, operatorData);
} }
...@@ -274,7 +273,7 @@ contract ERC777Upgradeable is Initializable, ContextUpgradeable, IERC777Upgradea ...@@ -274,7 +273,7 @@ contract ERC777Upgradeable is Initializable, ContextUpgradeable, IERC777Upgradea
* *
* Note that accounts cannot have allowance issued by their operators. * Note that accounts cannot have allowance issued by their operators.
*/ */
function approve(address spender, uint256 value) public override returns (bool) { function approve(address spender, uint256 value) public virtual override returns (bool) {
address holder = _msgSender(); address holder = _msgSender();
_approve(holder, spender, value); _approve(holder, spender, value);
return true; return true;
...@@ -289,7 +288,7 @@ contract ERC777Upgradeable is Initializable, ContextUpgradeable, IERC777Upgradea ...@@ -289,7 +288,7 @@ contract ERC777Upgradeable is Initializable, ContextUpgradeable, IERC777Upgradea
* *
* Emits {Sent}, {IERC20-Transfer} and {IERC20-Approval} events. * Emits {Sent}, {IERC20-Transfer} and {IERC20-Approval} events.
*/ */
function transferFrom(address holder, address recipient, uint256 amount) public override returns (bool) { function transferFrom(address holder, address recipient, uint256 amount) public virtual override returns (bool) {
require(recipient != address(0), "ERC777: transfer to the zero address"); require(recipient != address(0), "ERC777: transfer to the zero address");
require(holder != address(0), "ERC777: transfer from the zero address"); require(holder != address(0), "ERC777: transfer from the zero address");
...@@ -328,7 +327,8 @@ contract ERC777Upgradeable is Initializable, ContextUpgradeable, IERC777Upgradea ...@@ -328,7 +327,8 @@ contract ERC777Upgradeable is Initializable, ContextUpgradeable, IERC777Upgradea
bytes memory userData, bytes memory userData,
bytes memory operatorData bytes memory operatorData
) )
internal virtual internal
virtual
{ {
require(account != address(0), "ERC777: mint to the zero address"); require(account != address(0), "ERC777: mint to the zero address");
...@@ -364,6 +364,7 @@ contract ERC777Upgradeable is Initializable, ContextUpgradeable, IERC777Upgradea ...@@ -364,6 +364,7 @@ contract ERC777Upgradeable is Initializable, ContextUpgradeable, IERC777Upgradea
bool requireReceptionAck bool requireReceptionAck
) )
internal internal
virtual
{ {
require(from != address(0), "ERC777: send from the zero address"); require(from != address(0), "ERC777: send from the zero address");
require(to != address(0), "ERC777: send to the zero address"); require(to != address(0), "ERC777: send to the zero address");
...@@ -390,7 +391,8 @@ contract ERC777Upgradeable is Initializable, ContextUpgradeable, IERC777Upgradea ...@@ -390,7 +391,8 @@ contract ERC777Upgradeable is Initializable, ContextUpgradeable, IERC777Upgradea
bytes memory data, bytes memory data,
bytes memory operatorData bytes memory operatorData
) )
internal virtual internal
virtual
{ {
require(from != address(0), "ERC777: burn from the zero address"); require(from != address(0), "ERC777: burn from the zero address");
......
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
import "../proxy/Initializable.sol";
/*
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with GSN meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal initializer {
__Context_init_unchained();
}
function __Context_init_unchained() internal initializer {
}
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
uint256[50] private __gap;
}
...@@ -144,6 +144,16 @@ library EnumerableMapUpgradeable { ...@@ -144,6 +144,16 @@ library EnumerableMapUpgradeable {
} }
/** /**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function _tryGet(Map storage map, bytes32 key) private view returns (bool, bytes32) {
uint256 keyIndex = map._indexes[key];
if (keyIndex == 0) return (false, 0); // Equivalent to contains(map, key)
return (true, map._entries[keyIndex - 1]._value); // All indexes are 1-based
}
/**
* @dev Returns the value associated with `key`. O(1). * @dev Returns the value associated with `key`. O(1).
* *
* Requirements: * Requirements:
...@@ -151,11 +161,16 @@ library EnumerableMapUpgradeable { ...@@ -151,11 +161,16 @@ library EnumerableMapUpgradeable {
* - `key` must be in the map. * - `key` must be in the map.
*/ */
function _get(Map storage map, bytes32 key) private view returns (bytes32) { function _get(Map storage map, bytes32 key) private view returns (bytes32) {
return _get(map, key, "EnumerableMap: nonexistent key"); uint256 keyIndex = map._indexes[key];
require(keyIndex != 0, "EnumerableMap: nonexistent key"); // Equivalent to contains(map, key)
return map._entries[keyIndex - 1]._value; // All indexes are 1-based
} }
/** /**
* @dev Same as {_get}, with a custom error message when `key` is not in the map. * @dev Same as {_get}, with a custom error message when `key` is not in the map.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {_tryGet}.
*/ */
function _get(Map storage map, bytes32 key, string memory errorMessage) private view returns (bytes32) { function _get(Map storage map, bytes32 key, string memory errorMessage) private view returns (bytes32) {
uint256 keyIndex = map._indexes[key]; uint256 keyIndex = map._indexes[key];
...@@ -218,6 +233,15 @@ library EnumerableMapUpgradeable { ...@@ -218,6 +233,15 @@ library EnumerableMapUpgradeable {
} }
/** /**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) {
(bool success, bytes32 value) = _tryGet(map._inner, bytes32(key));
return (success, address(uint160(uint256(value))));
}
/**
* @dev Returns the value associated with `key`. O(1). * @dev Returns the value associated with `key`. O(1).
* *
* Requirements: * Requirements:
...@@ -230,6 +254,9 @@ library EnumerableMapUpgradeable { ...@@ -230,6 +254,9 @@ library EnumerableMapUpgradeable {
/** /**
* @dev Same as {get}, with a custom error message when `key` is not in the map. * @dev Same as {get}, with a custom error message when `key` is not in the map.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryGet}.
*/ */
function get(UintToAddressMap storage map, uint256 key, string memory errorMessage) internal view returns (address) { function get(UintToAddressMap storage map, uint256 key, string memory errorMessage) internal view returns (address) {
return address(uint160(uint256(_get(map._inner, bytes32(key), errorMessage)))); return address(uint160(uint256(_get(map._inner, bytes32(key), errorMessage))));
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
pragma solidity >=0.6.0 <0.8.0; pragma solidity >=0.6.0 <0.8.0;
import "../GSN/ContextUpgradeable.sol"; import "./ContextUpgradeable.sol";
import "../proxy/Initializable.sol"; import "../proxy/Initializable.sol";
/** /**
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -15,6 +15,6 @@ solidity-docgen \ ...@@ -15,6 +15,6 @@ solidity-docgen \
-o "$OUTDIR" \ -o "$OUTDIR" \
-e contracts/mocks,contracts/examples \ -e contracts/mocks,contracts/examples \
--output-structure readmes \ --output-structure readmes \
--solc-module scripts/prepare-docs-solc.js --solc-module ./scripts/prepare-docs-solc.js
node scripts/gen-nav.js "$OUTDIR" > "$OUTDIR/../nav.adoc" node scripts/gen-nav.js "$OUTDIR" > "$OUTDIR/../nav.adoc"
...@@ -6,9 +6,10 @@ npm run compile ...@@ -6,9 +6,10 @@ npm run compile
# -D: delete original and excluded files # -D: delete original and excluded files
# -i: use included Initializable # -i: use included Initializable
# -x: exclude all proxy contracts # -x: exclude all proxy contracts except Clones library
# -p: emit public initializer # -p: emit public initializer
npx @openzeppelin/upgrade-safe-transpiler -D \ npx @openzeppelin/upgrade-safe-transpiler -D \
-i contracts/proxy/Initializable.sol \ -i contracts/proxy/Initializable.sol \
-x 'contracts/proxy/**/*' \ -x 'contracts/proxy/**/*' \
-x '!contracts/proxy/Clones.sol' \
-p 'contracts/presets/**/*' -p 'contracts/presets/**/*'
...@@ -37,6 +37,12 @@ contract('ERC165Checker', function (accounts) { ...@@ -37,6 +37,12 @@ contract('ERC165Checker', function (accounts) {
const supported = await this.mock.supportsAllInterfaces(this.target.address, [DUMMY_ID]); const supported = await this.mock.supportsAllInterfaces(this.target.address, [DUMMY_ID]);
expect(supported).to.equal(false); expect(supported).to.equal(false);
}); });
it('does not support mock interface via getSupportedInterfaces', async function () {
const supported = await this.mock.getSupportedInterfaces(this.target.address, [DUMMY_ID]);
expect(supported.length).to.equal(1);
expect(supported[0]).to.equal(false);
});
}); });
context('ERC165 supported', function () { context('ERC165 supported', function () {
...@@ -58,6 +64,12 @@ contract('ERC165Checker', function (accounts) { ...@@ -58,6 +64,12 @@ contract('ERC165Checker', function (accounts) {
const supported = await this.mock.supportsAllInterfaces(this.target.address, [DUMMY_ID]); const supported = await this.mock.supportsAllInterfaces(this.target.address, [DUMMY_ID]);
expect(supported).to.equal(false); expect(supported).to.equal(false);
}); });
it('does not support mock interface via getSupportedInterfaces', async function () {
const supported = await this.mock.getSupportedInterfaces(this.target.address, [DUMMY_ID]);
expect(supported.length).to.equal(1);
expect(supported[0]).to.equal(false);
});
}); });
context('ERC165 and single interface supported', function () { context('ERC165 and single interface supported', function () {
...@@ -79,6 +91,12 @@ contract('ERC165Checker', function (accounts) { ...@@ -79,6 +91,12 @@ contract('ERC165Checker', function (accounts) {
const supported = await this.mock.supportsAllInterfaces(this.target.address, [DUMMY_ID]); const supported = await this.mock.supportsAllInterfaces(this.target.address, [DUMMY_ID]);
expect(supported).to.equal(true); expect(supported).to.equal(true);
}); });
it('supports mock interface via getSupportedInterfaces', async function () {
const supported = await this.mock.getSupportedInterfaces(this.target.address, [DUMMY_ID]);
expect(supported.length).to.equal(1);
expect(supported[0]).to.equal(true);
});
}); });
context('ERC165 and many interfaces supported', function () { context('ERC165 and many interfaces supported', function () {
...@@ -117,6 +135,34 @@ contract('ERC165Checker', function (accounts) { ...@@ -117,6 +135,34 @@ contract('ERC165Checker', function (accounts) {
const supported = await this.mock.supportsAllInterfaces(this.target.address, interfaceIdsToTest); const supported = await this.mock.supportsAllInterfaces(this.target.address, interfaceIdsToTest);
expect(supported).to.equal(false); expect(supported).to.equal(false);
}); });
it('supports all interfaceIds via getSupportedInterfaces', async function () {
const supported = await this.mock.getSupportedInterfaces(this.target.address, this.supportedInterfaces);
expect(supported.length).to.equal(3);
expect(supported[0]).to.equal(true);
expect(supported[1]).to.equal(true);
expect(supported[2]).to.equal(true);
});
it('supports none of the interfaces queried via getSupportedInterfaces', async function () {
const interfaceIdsToTest = [DUMMY_UNSUPPORTED_ID, DUMMY_UNSUPPORTED_ID_2];
const supported = await this.mock.getSupportedInterfaces(this.target.address, interfaceIdsToTest);
expect(supported.length).to.equal(2);
expect(supported[0]).to.equal(false);
expect(supported[1]).to.equal(false);
});
it('supports not all of the interfaces queried via getSupportedInterfaces', async function () {
const interfaceIdsToTest = [...this.supportedInterfaces, DUMMY_UNSUPPORTED_ID];
const supported = await this.mock.getSupportedInterfaces(this.target.address, interfaceIdsToTest);
expect(supported.length).to.equal(4);
expect(supported[0]).to.equal(true);
expect(supported[1]).to.equal(true);
expect(supported[2]).to.equal(true);
expect(supported[3]).to.equal(false);
});
}); });
context('account address does not support ERC165', function () { context('account address does not support ERC165', function () {
...@@ -134,5 +180,11 @@ contract('ERC165Checker', function (accounts) { ...@@ -134,5 +180,11 @@ contract('ERC165Checker', function (accounts) {
const supported = await this.mock.supportsAllInterfaces(DUMMY_ACCOUNT, [DUMMY_ID]); const supported = await this.mock.supportsAllInterfaces(DUMMY_ACCOUNT, [DUMMY_ID]);
expect(supported).to.equal(false); expect(supported).to.equal(false);
}); });
it('does not support mock interface via getSupportedInterfaces', async function () {
const supported = await this.mock.getSupportedInterfaces(DUMMY_ACCOUNT, [DUMMY_ID]);
expect(supported.length).to.equal(1);
expect(supported[0]).to.equal(false);
});
}); });
}); });
const { expectRevert } = require('@openzeppelin/test-helpers');
const { expect } = require('chai');
const DummyImplementation = artifacts.require('DummyImplementation');
module.exports = function shouldBehaveLikeClone (createClone) {
before('deploy implementation', async function () {
this.implementation = web3.utils.toChecksumAddress((await DummyImplementation.new()).address);
});
const assertProxyInitialization = function ({ value, balance }) {
it('initializes the proxy', async function () {
const dummy = new DummyImplementation(this.proxy);
expect(await dummy.value()).to.be.bignumber.equal(value.toString());
});
it('has expected balance', async function () {
expect(await web3.eth.getBalance(this.proxy)).to.be.bignumber.equal(balance.toString());
});
};
describe('initialization without parameters', function () {
describe('non payable', function () {
const expectedInitializedValue = 10;
const initializeData = new DummyImplementation('').contract.methods['initializeNonPayable()']().encodeABI();
describe('when not sending balance', function () {
beforeEach('creating proxy', async function () {
this.proxy = (
await createClone(this.implementation, initializeData)
).address;
});
assertProxyInitialization({
value: expectedInitializedValue,
balance: 0,
});
});
describe('when sending some balance', function () {
const value = 10e5;
it('reverts', async function () {
await expectRevert.unspecified(
createClone(this.implementation, initializeData, { value }),
);
});
});
});
describe('payable', function () {
const expectedInitializedValue = 100;
const initializeData = new DummyImplementation('').contract.methods['initializePayable()']().encodeABI();
describe('when not sending balance', function () {
beforeEach('creating proxy', async function () {
this.proxy = (
await createClone(this.implementation, initializeData)
).address;
});
assertProxyInitialization({
value: expectedInitializedValue,
balance: 0,
});
});
describe('when sending some balance', function () {
const value = 10e5;
beforeEach('creating proxy', async function () {
this.proxy = (
await createClone(this.implementation, initializeData, { value })
).address;
});
assertProxyInitialization({
value: expectedInitializedValue,
balance: value,
});
});
});
});
describe('initialization with parameters', function () {
describe('non payable', function () {
const expectedInitializedValue = 10;
const initializeData = new DummyImplementation('').contract
.methods.initializeNonPayableWithValue(expectedInitializedValue).encodeABI();
describe('when not sending balance', function () {
beforeEach('creating proxy', async function () {
this.proxy = (
await createClone(this.implementation, initializeData)
).address;
});
assertProxyInitialization({
value: expectedInitializedValue,
balance: 0,
});
});
describe('when sending some balance', function () {
const value = 10e5;
it('reverts', async function () {
await expectRevert.unspecified(
createClone(this.implementation, initializeData, { value }),
);
});
});
});
describe('payable', function () {
const expectedInitializedValue = 42;
const initializeData = new DummyImplementation('').contract
.methods.initializePayableWithValue(expectedInitializedValue).encodeABI();
describe('when not sending balance', function () {
beforeEach('creating proxy', async function () {
this.proxy = (
await createClone(this.implementation, initializeData)
).address;
});
assertProxyInitialization({
value: expectedInitializedValue,
balance: 0,
});
});
describe('when sending some balance', function () {
const value = 10e5;
beforeEach('creating proxy', async function () {
this.proxy = (
await createClone(this.implementation, initializeData, { value })
).address;
});
assertProxyInitialization({
value: expectedInitializedValue,
balance: value,
});
});
});
});
};
const { expectEvent, expectRevert } = require('@openzeppelin/test-helpers');
const shouldBehaveLikeClone = require('./Clones.behaviour');
const ClonesMock = artifacts.require('ClonesMock');
contract('Clones', function (accounts) {
describe('clone', function () {
shouldBehaveLikeClone(async (implementation, initData, opts = {}) => {
const factory = await ClonesMock.new();
const receipt = await factory.clone(implementation, initData, { value: opts.value });
const address = receipt.logs.find(({ event }) => event === 'NewInstance').args.instance;
return { address };
});
});
describe('cloneDeterministic', function () {
shouldBehaveLikeClone(async (implementation, initData, opts = {}) => {
const salt = web3.utils.randomHex(32);
const factory = await ClonesMock.new();
const receipt = await factory.cloneDeterministic(implementation, salt, initData, { value: opts.value });
const address = receipt.logs.find(({ event }) => event === 'NewInstance').args.instance;
return { address };
});
it('address already used', async function () {
const implementation = web3.utils.randomHex(20);
const salt = web3.utils.randomHex(32);
const factory = await ClonesMock.new();
// deploy once
expectEvent(
await factory.cloneDeterministic(implementation, salt, '0x'),
'NewInstance',
);
// deploy twice
await expectRevert(
factory.cloneDeterministic(implementation, salt, '0x'),
'ERC1167: create2 failed',
);
});
it('address prediction', async function () {
const implementation = web3.utils.randomHex(20);
const salt = web3.utils.randomHex(32);
const factory = await ClonesMock.new();
const predicted = await factory.predictDeterministicAddress(implementation, salt);
expectEvent(
await factory.cloneDeterministic(implementation, salt, '0x'),
'NewInstance',
{ instance: predicted },
);
});
});
});
const { BN, expectRevert, expectEvent, constants } = require('@openzeppelin/test-helpers'); const { BN, expectRevert, expectEvent, constants } = require('@openzeppelin/test-helpers');
const { ZERO_ADDRESS } = constants; const { ZERO_ADDRESS } = constants;
const { toChecksumAddress, keccak256 } = require('ethereumjs-util'); const ethereumjsUtil = require('ethereumjs-util');
const { expect } = require('chai'); const { expect } = require('chai');
...@@ -19,6 +19,10 @@ const ClashingImplementation = artifacts.require('ClashingImplementation'); ...@@ -19,6 +19,10 @@ const ClashingImplementation = artifacts.require('ClashingImplementation');
const IMPLEMENTATION_LABEL = 'eip1967.proxy.implementation'; const IMPLEMENTATION_LABEL = 'eip1967.proxy.implementation';
const ADMIN_LABEL = 'eip1967.proxy.admin'; const ADMIN_LABEL = 'eip1967.proxy.admin';
function toChecksumAddress (address) {
return ethereumjsUtil.toChecksumAddress('0x' + address.replace(/^0x/, '').padStart(40, '0'));
}
module.exports = function shouldBehaveLikeTransparentUpgradeableProxy (createProxy, accounts) { module.exports = function shouldBehaveLikeTransparentUpgradeableProxy (createProxy, accounts) {
const [proxyAdminAddress, proxyAdminOwner, anotherAccount] = accounts; const [proxyAdminAddress, proxyAdminOwner, anotherAccount] = accounts;
...@@ -308,13 +312,13 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy (createPro ...@@ -308,13 +312,13 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy (createPro
describe('storage', function () { describe('storage', function () {
it('should store the implementation address in specified location', async function () { it('should store the implementation address in specified location', async function () {
const slot = '0x' + new BN(keccak256(Buffer.from(IMPLEMENTATION_LABEL))).subn(1).toString(16); const slot = '0x' + new BN(ethereumjsUtil.keccak256(Buffer.from(IMPLEMENTATION_LABEL))).subn(1).toString(16);
const implementation = toChecksumAddress(await web3.eth.getStorageAt(this.proxyAddress, slot)); const implementation = toChecksumAddress(await web3.eth.getStorageAt(this.proxyAddress, slot));
expect(implementation).to.be.equal(this.implementationV0); expect(implementation).to.be.equal(this.implementationV0);
}); });
it('should store the admin proxy in specified location', async function () { it('should store the admin proxy in specified location', async function () {
const slot = '0x' + new BN(keccak256(Buffer.from(ADMIN_LABEL))).subn(1).toString(16); const slot = '0x' + new BN(ethereumjsUtil.keccak256(Buffer.from(ADMIN_LABEL))).subn(1).toString(16);
const proxyAdmin = toChecksumAddress(await web3.eth.getStorageAt(this.proxyAddress, slot)); const proxyAdmin = toChecksumAddress(await web3.eth.getStorageAt(this.proxyAddress, slot));
expect(proxyAdmin).to.be.equal(proxyAdminAddress); expect(proxyAdmin).to.be.equal(proxyAdminAddress);
}); });
......
const { BN, expectRevert } = require('@openzeppelin/test-helpers'); const { BN, expectRevert } = require('@openzeppelin/test-helpers');
const { toChecksumAddress, keccak256 } = require('ethereumjs-util'); const ethereumjsUtil = require('ethereumjs-util');
const { expect } = require('chai'); const { expect } = require('chai');
...@@ -7,6 +7,10 @@ const DummyImplementation = artifacts.require('DummyImplementation'); ...@@ -7,6 +7,10 @@ const DummyImplementation = artifacts.require('DummyImplementation');
const IMPLEMENTATION_LABEL = 'eip1967.proxy.implementation'; const IMPLEMENTATION_LABEL = 'eip1967.proxy.implementation';
function toChecksumAddress (address) {
return ethereumjsUtil.toChecksumAddress('0x' + address.replace(/^0x/, '').padStart(40, '0'));
}
module.exports = function shouldBehaveLikeUpgradeableProxy (createProxy, proxyAdminAddress, proxyCreator) { module.exports = function shouldBehaveLikeUpgradeableProxy (createProxy, proxyAdminAddress, proxyCreator) {
it('cannot be initialized with a non-contract address', async function () { it('cannot be initialized with a non-contract address', async function () {
const nonContractAddress = proxyCreator; const nonContractAddress = proxyCreator;
...@@ -24,7 +28,7 @@ module.exports = function shouldBehaveLikeUpgradeableProxy (createProxy, proxyAd ...@@ -24,7 +28,7 @@ module.exports = function shouldBehaveLikeUpgradeableProxy (createProxy, proxyAd
const assertProxyInitialization = function ({ value, balance }) { const assertProxyInitialization = function ({ value, balance }) {
it('sets the implementation address', async function () { it('sets the implementation address', async function () {
const slot = '0x' + new BN(keccak256(Buffer.from(IMPLEMENTATION_LABEL))).subn(1).toString(16); const slot = '0x' + new BN(ethereumjsUtil.keccak256(Buffer.from(IMPLEMENTATION_LABEL))).subn(1).toString(16);
const implementation = toChecksumAddress(await web3.eth.getStorageAt(this.proxy, slot)); const implementation = toChecksumAddress(await web3.eth.getStorageAt(this.proxy, slot));
expect(implementation).to.be.equal(this.implementation); expect(implementation).to.be.equal(this.implementation);
}); });
...@@ -210,5 +214,17 @@ module.exports = function shouldBehaveLikeUpgradeableProxy (createProxy, proxyAd ...@@ -210,5 +214,17 @@ module.exports = function shouldBehaveLikeUpgradeableProxy (createProxy, proxyAd
}); });
}); });
}); });
describe('reverting initialization', function () {
const initializeData = new DummyImplementation('').contract
.methods.reverts().encodeABI();
it('reverts', async function () {
await expectRevert(
createProxy(this.implementation, proxyAdminAddress, initializeData, { from: proxyCreator }),
'DummyImplementation reverted',
);
});
});
}); });
}; };
const { BN, expectEvent } = require('@openzeppelin/test-helpers'); const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers');
const { expect } = require('chai'); const { expect } = require('chai');
const zip = require('lodash.zip'); const zip = require('lodash.zip');
...@@ -139,4 +139,43 @@ contract('EnumerableMap', function (accounts) { ...@@ -139,4 +139,43 @@ contract('EnumerableMap', function (accounts) {
expect(await this.map.contains(keyB)).to.equal(false); expect(await this.map.contains(keyB)).to.equal(false);
}); });
}); });
describe('read', function () {
beforeEach(async function () {
await this.map.set(keyA, accountA);
});
describe('get', function () {
it('existing value', async function () {
expect(await this.map.get(keyA)).to.be.equal(accountA);
});
it('missing value', async function () {
await expectRevert(this.map.get(keyB), 'EnumerableMap: nonexistent key');
});
});
describe('get with message', function () {
it('existing value', async function () {
expect(await this.map.getWithMessage(keyA, 'custom error string')).to.be.equal(accountA);
});
it('missing value', async function () {
await expectRevert(this.map.getWithMessage(keyB, 'custom error string'), 'custom error string');
});
});
describe('tryGet', function () {
it('existing value', async function () {
expect(await this.map.tryGet(keyA)).to.be.deep.equal({
0: true,
1: accountA,
});
});
it('missing value', async function () {
expect(await this.map.tryGet(keyB)).to.be.deep.equal({
0: false,
1: constants.ZERO_ADDRESS,
});
});
});
});
}); });
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