Compare commits

..

7 Commits

Author SHA1 Message Date
1c3d6c97f7 3.4.1-solc-0.7-2 2021-03-03 20:53:33 -03:00
1f9c970929 Make ERC721._approve internal
(cherry picked from commit df8acac20a)
2021-03-03 20:51:08 -03:00
5b42f7aee6 3.4.1-solc-0.7 2021-03-03 16:55:23 -03:00
890352e63c Add a changelog entry
(cherry picked from commit 352970ef56)
2021-03-03 16:52:39 -03:00
5c8746f56b 3.4.0-solc-0.7 2021-02-02 13:50:09 -03:00
18856cf2de Remove SafeMathMock compilation warnings (#2497)
(cherry picked from commit f4e57fd529)
2021-02-02 12:16:00 -03:00
97199cc755 Add "available since" comments in documentation
(cherry picked from commit 63a0343dda)
2021-02-02 12:15:54 -03:00
274 changed files with 8283 additions and 28635 deletions

View File

@ -26,18 +26,11 @@ jobs:
if: steps.cache.outputs.cache-hit != 'true'
- run: npm run lint
- run: npm run test
env:
FORCE_COLOR: 1
ENABLE_GAS_REPORT: 1
- name: Print gas report
run: cat gas-report.txt
coverage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 2
- uses: actions/setup-node@v2
with:
node-version: 10.x
@ -50,6 +43,4 @@ jobs:
- run: npm ci
if: steps.cache.outputs.cache-hit != 'true'
- run: npm run coverage
env:
NODE_OPTIONS: --max_old_space_size=4096
- uses: codecov/codecov-action@v1

2
.gitignore vendored
View File

@ -54,6 +54,6 @@ allFiredEvents
.coverage_cache
.coverage_contracts
# hardhat
# buidler
cache
artifacts

View File

@ -1,43 +1,8 @@
# Changelog
## 4.0.0
## 3.4.1-solc-0.7 (2021-03-03)
* Now targeting the 0.8.x line of Solidity compilers. For 0.6.x (resp 0.7.x) support, use version 3.4.0 (resp 3.4.0-solc-0.7) of OpenZeppelin.
* `Context`: making `_msgData` return `bytes calldata` instead of `bytes memory` ([#2492](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2492))
* `ERC20`: removed the `_setDecimals` function and the storage slot associated to decimals. ([#2502](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2502))
* `Strings`: addition of a `toHexString` function. ([#2504](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2504))
* `EnumerableMap`: change implementation to optimize for `key → value` lookups instead of enumeration. ([#2518](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2518))
* `GSN`: deprecate GSNv1 support in favor of upcoming support for GSNv2. ([#2521](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2521))
* `ERC165`: remove uses of storage in the base ERC165 implementation. ERC165 based contracts now use storage-less virtual functions. Old behavior remains available in the `ERC165Storage` extension. ([#2505](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2505))
* `Initializable`: make initializer check stricter during construction. ([#2531](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2531))
* `ERC721`: remove enumerability of tokens from the base implementation. This feature is now provided separately through the `ERC721Enumerable` extension. ([#2511](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2511))
* `AccessControl`: removed enumerability by default for a more lightweight contract. It is now opt-in through `AccessControlEnumerable`. ([#2512](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2512))
* Meta Transactions: add `ERC2771Context` and a `MinimalForwarder` for meta-transactions. ([#2508](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2508))
* Overall reorganization of the contract folder to improve clarity and discoverability. ([#2503](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2503))
* `ERC20Capped`: optimize gas usage by enforcing the check directly in `_mint`. ([#2524](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2524))
* Rename `UpgradeableProxy` to `ERC1967Proxy`. ([#2547](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2547))
* `ERC777`: optimize the gas costs of the constructor. ([#2551](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2551))
* `ERC721URIStorage`: add a new extension that implements the `_setTokenURI` behavior as it was available in 3.4.0. ([#2555](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2555))
* `AccessControl`: added ERC165 interface detection. ([#2562](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2562))
* `ERC1155`: make `uri` public so overloading function can call it using super. ([#2576](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2576))
### Bug fixes for beta releases
* `AccessControlEnumerable`: Fixed `renounceRole` not updating enumerable set of addresses for a role. ([#2572](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2572))
### How to upgrade from 3.x
Since this version has moved a few contracts to different directories, users upgrading from a previous version will need to adjust their import statements. To make this easier, the package includes a script that will migrate import statements automatically. After upgrading to the latest version of the package, run:
```
npx openzeppelin-contracts-migrate-imports
```
Make sure you're using git or another version control system to be able to recover from any potential error in our script.
### How to upgrade from 4.0-beta.x
Some further changes have been done between the different beta iterations. Transitions made during this period are configured in the `migrate-imports` script. Consequently, you can upgrade from any previous 4.0-beta.x version using the same script as described in the *How to upgrade from 3.x* section.
* `ERC721`: made `_approve` an internal function (was private).
## 3.4.0 (2021-02-02)

View File

@ -27,7 +27,7 @@ OpenZeppelin Contracts features a [stable API](https://docs.openzeppelin.com/con
Once installed, you can use the contracts in the library by importing them:
```solidity
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";

20
buidler.config.js Normal file
View File

@ -0,0 +1,20 @@
const fs = require('fs');
const path = require('path');
usePlugin('solidity-coverage');
usePlugin('@nomiclabs/buidler-truffle5');
for (const f of fs.readdirSync(path.join(__dirname, 'buidler'))) {
require(path.join(__dirname, 'buidler', f));
}
module.exports = {
networks: {
buidlerevm: {
blockGasLimit: 10000000,
},
},
solc: {
version: '0.7.4',
},
};

View File

@ -0,0 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "../utils/Context.sol";

View File

@ -0,0 +1,230 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "../utils/Context.sol";
import "./IRelayRecipient.sol";
import "./IRelayHub.sol";
/**
* @dev Base GSN recipient contract: includes the {IRelayRecipient} interface
* and enables GSN support on all contracts in the inheritance tree.
*
* TIP: This contract is abstract. The functions {IRelayRecipient-acceptRelayedCall},
* {_preRelayedCall}, and {_postRelayedCall} are not implemented and must be
* provided by derived contracts. See the
* xref:ROOT:gsn-strategies.adoc#gsn-strategies[GSN strategies] for more
* information on how to use the pre-built {GSNRecipientSignature} and
* {GSNRecipientERC20Fee}, or how to write your own.
*/
abstract contract GSNRecipient is IRelayRecipient, Context {
// Default RelayHub address, deployed on mainnet and all testnets at the same address
address private _relayHub = 0xD216153c06E857cD7f72665E0aF1d7D82172F494;
uint256 constant private _RELAYED_CALL_ACCEPTED = 0;
uint256 constant private _RELAYED_CALL_REJECTED = 11;
// How much gas is forwarded to postRelayedCall
uint256 constant internal _POST_RELAYED_CALL_MAX_GAS = 100000;
/**
* @dev Emitted when a contract changes its {IRelayHub} contract to a new one.
*/
event RelayHubChanged(address indexed oldRelayHub, address indexed newRelayHub);
/**
* @dev Returns the address of the {IRelayHub} contract for this recipient.
*/
function getHubAddr() public view virtual override returns (address) {
return _relayHub;
}
/**
* @dev Switches to a new {IRelayHub} instance. This method is added for future-proofing: there's no reason to not
* use the default instance.
*
* IMPORTANT: After upgrading, the {GSNRecipient} will no longer be able to receive relayed calls from the old
* {IRelayHub} instance. Additionally, all funds should be previously withdrawn via {_withdrawDeposits}.
*/
function _upgradeRelayHub(address newRelayHub) internal virtual {
address currentRelayHub = _relayHub;
require(newRelayHub != address(0), "GSNRecipient: new RelayHub is the zero address");
require(newRelayHub != currentRelayHub, "GSNRecipient: new RelayHub is the current one");
emit RelayHubChanged(currentRelayHub, newRelayHub);
_relayHub = newRelayHub;
}
/**
* @dev Returns the version string of the {IRelayHub} for which this recipient implementation was built. If
* {_upgradeRelayHub} is used, the new {IRelayHub} instance should be compatible with this version.
*/
// This function is view for future-proofing, it may require reading from
// storage in the future.
function relayHubVersion() public view virtual returns (string memory) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return "1.0.0";
}
/**
* @dev Withdraws the recipient's deposits in `RelayHub`.
*
* Derived contracts should expose this in an external interface with proper access control.
*/
function _withdrawDeposits(uint256 amount, address payable payee) internal virtual {
IRelayHub(getHubAddr()).withdraw(amount, payee);
}
// Overrides for Context's functions: when called from RelayHub, sender and
// data require some pre-processing: the actual sender is stored at the end
// of the call data, which in turns means it needs to be removed from it
// when handling said data.
/**
* @dev Replacement for msg.sender. Returns the actual sender of a transaction: msg.sender for regular transactions,
* and the end-user for GSN relayed calls (where msg.sender is actually `RelayHub`).
*
* IMPORTANT: Contracts derived from {GSNRecipient} should never use `msg.sender`, and use {_msgSender} instead.
*/
function _msgSender() internal view virtual override returns (address payable) {
if (msg.sender != getHubAddr()) {
return msg.sender;
} else {
return _getRelayedCallSender();
}
}
/**
* @dev Replacement for msg.data. Returns the actual calldata of a transaction: msg.data for regular transactions,
* and a reduced version for GSN relayed calls (where msg.data contains additional information).
*
* IMPORTANT: Contracts derived from {GSNRecipient} should never use `msg.data`, and use {_msgData} instead.
*/
function _msgData() internal view virtual override returns (bytes memory) {
if (msg.sender != getHubAddr()) {
return msg.data;
} else {
return _getRelayedCallData();
}
}
// Base implementations for pre and post relayedCall: only RelayHub can invoke them, and data is forwarded to the
// internal hook.
/**
* @dev See `IRelayRecipient.preRelayedCall`.
*
* This function should not be overridden directly, use `_preRelayedCall` instead.
*
* * Requirements:
*
* - the caller must be the `RelayHub` contract.
*/
function preRelayedCall(bytes memory context) public virtual override returns (bytes32) {
require(msg.sender == getHubAddr(), "GSNRecipient: caller is not RelayHub");
return _preRelayedCall(context);
}
/**
* @dev See `IRelayRecipient.preRelayedCall`.
*
* Called by `GSNRecipient.preRelayedCall`, which asserts the caller is the `RelayHub` contract. Derived contracts
* must implement this function with any relayed-call preprocessing they may wish to do.
*
*/
function _preRelayedCall(bytes memory context) internal virtual returns (bytes32);
/**
* @dev See `IRelayRecipient.postRelayedCall`.
*
* This function should not be overridden directly, use `_postRelayedCall` instead.
*
* * Requirements:
*
* - the caller must be the `RelayHub` contract.
*/
function postRelayedCall(bytes memory context, bool success, uint256 actualCharge, bytes32 preRetVal) public virtual override {
require(msg.sender == getHubAddr(), "GSNRecipient: caller is not RelayHub");
_postRelayedCall(context, success, actualCharge, preRetVal);
}
/**
* @dev See `IRelayRecipient.postRelayedCall`.
*
* Called by `GSNRecipient.postRelayedCall`, which asserts the caller is the `RelayHub` contract. Derived contracts
* must implement this function with any relayed-call postprocessing they may wish to do.
*
*/
function _postRelayedCall(bytes memory context, bool success, uint256 actualCharge, bytes32 preRetVal) internal virtual;
/**
* @dev Return this in acceptRelayedCall to proceed with the execution of a relayed call. Note that this contract
* will be charged a fee by RelayHub
*/
function _approveRelayedCall() internal pure virtual returns (uint256, bytes memory) {
return _approveRelayedCall("");
}
/**
* @dev See `GSNRecipient._approveRelayedCall`.
*
* This overload forwards `context` to _preRelayedCall and _postRelayedCall.
*/
function _approveRelayedCall(bytes memory context) internal pure virtual returns (uint256, bytes memory) {
return (_RELAYED_CALL_ACCEPTED, context);
}
/**
* @dev Return this in acceptRelayedCall to impede execution of a relayed call. No fees will be charged.
*/
function _rejectRelayedCall(uint256 errorCode) internal pure virtual returns (uint256, bytes memory) {
return (_RELAYED_CALL_REJECTED + errorCode, "");
}
/*
* @dev Calculates how much RelayHub will charge a recipient for using `gas` at a `gasPrice`, given a relayer's
* `serviceFee`.
*/
function _computeCharge(uint256 gas, uint256 gasPrice, uint256 serviceFee) internal pure virtual returns (uint256) {
// The fee is expressed as a percentage. E.g. a value of 40 stands for a 40% fee, so the recipient will be
// charged for 1.4 times the spent amount.
return (gas * gasPrice * (100 + serviceFee)) / 100;
}
function _getRelayedCallSender() private pure returns (address payable result) {
// We need to read 20 bytes (an address) located at array index msg.data.length - 20. In memory, the array
// is prefixed with a 32-byte length value, so we first add 32 to get the memory read index. However, doing
// so would leave the address in the upper 20 bytes of the 32-byte word, which is inconvenient and would
// require bit shifting. We therefore subtract 12 from the read index so the address lands on the lower 20
// bytes. This can always be done due to the 32-byte prefix.
// The final memory read index is msg.data.length - 20 + 32 - 12 = msg.data.length. Using inline assembly is the
// easiest/most-efficient way to perform this operation.
// These fields are not accessible from assembly
bytes memory array = msg.data;
uint256 index = msg.data.length;
// solhint-disable-next-line no-inline-assembly
assembly {
// Load the 32 bytes word from memory with the address on the lower 20 bytes, and mask those.
result := and(mload(add(array, index)), 0xffffffffffffffffffffffffffffffffffffffff)
}
return result;
}
function _getRelayedCallData() private pure returns (bytes memory) {
// RelayHub appends the sender address at the end of the calldata, so in order to retrieve the actual msg.data,
// we must strip the last 20 bytes (length of an address type) from it.
uint256 actualDataLength = msg.data.length - 20;
bytes memory actualData = new bytes(actualDataLength);
for (uint256 i = 0; i < actualDataLength; ++i) {
actualData[i] = msg.data[i];
}
return actualData;
}
}

View File

@ -0,0 +1,154 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "./GSNRecipient.sol";
import "../math/SafeMath.sol";
import "../access/Ownable.sol";
import "../token/ERC20/SafeERC20.sol";
import "../token/ERC20/ERC20.sol";
/**
* @dev A xref:ROOT:gsn-strategies.adoc#gsn-strategies[GSN strategy] that charges transaction fees in a special purpose ERC20
* token, which we refer to as the gas payment token. The amount charged is exactly the amount of Ether charged to the
* recipient. This means that the token is essentially pegged to the value of Ether.
*
* The distribution strategy of the gas payment token to users is not defined by this contract. It's a mintable token
* whose only minter is the recipient, so the strategy must be implemented in a derived contract, making use of the
* internal {_mint} function.
*/
contract GSNRecipientERC20Fee is GSNRecipient {
using SafeERC20 for __unstable__ERC20Owned;
using SafeMath for uint256;
enum GSNRecipientERC20FeeErrorCodes {
INSUFFICIENT_BALANCE
}
__unstable__ERC20Owned private _token;
/**
* @dev The arguments to the constructor are the details that the gas payment token will have: `name` and `symbol`. `decimals` is hard-coded to 18.
*/
constructor(string memory name, string memory symbol) {
_token = new __unstable__ERC20Owned(name, symbol);
}
/**
* @dev Returns the gas payment token.
*/
function token() public view virtual returns (__unstable__ERC20Owned) {
return _token;
}
/**
* @dev Internal function that mints the gas payment token. Derived contracts should expose this function in their public API, with proper access control mechanisms.
*/
function _mint(address account, uint256 amount) internal virtual {
token().mint(account, amount);
}
/**
* @dev Ensures that only users with enough gas payment token balance can have transactions relayed through the GSN.
*/
function acceptRelayedCall(
address,
address from,
bytes memory,
uint256 transactionFee,
uint256 gasPrice,
uint256,
uint256,
bytes memory,
uint256 maxPossibleCharge
)
public
view
virtual
override
returns (uint256, bytes memory)
{
if (token().balanceOf(from) < maxPossibleCharge) {
return _rejectRelayedCall(uint256(GSNRecipientERC20FeeErrorCodes.INSUFFICIENT_BALANCE));
}
return _approveRelayedCall(abi.encode(from, maxPossibleCharge, transactionFee, gasPrice));
}
/**
* @dev Implements the precharge to the user. The maximum possible charge (depending on gas limit, gas price, and
* fee) will be deducted from the user balance of gas payment token. Note that this is an overestimation of the
* actual charge, necessary because we cannot predict how much gas the execution will actually need. The remainder
* is returned to the user in {_postRelayedCall}.
*/
function _preRelayedCall(bytes memory context) internal virtual override returns (bytes32) {
(address from, uint256 maxPossibleCharge) = abi.decode(context, (address, uint256));
// The maximum token charge is pre-charged from the user
token().safeTransferFrom(from, address(this), maxPossibleCharge);
return 0;
}
/**
* @dev Returns to the user the extra amount that was previously charged, once the actual execution cost is known.
*/
function _postRelayedCall(bytes memory context, bool, uint256 actualCharge, bytes32) internal virtual override {
(address from, uint256 maxPossibleCharge, uint256 transactionFee, uint256 gasPrice) =
abi.decode(context, (address, uint256, uint256, uint256));
// actualCharge is an _estimated_ charge, which assumes postRelayedCall will use all available gas.
// This implementation's gas cost can be roughly estimated as 10k gas, for the two SSTORE operations in an
// ERC20 transfer.
uint256 overestimation = _computeCharge(_POST_RELAYED_CALL_MAX_GAS.sub(10000), gasPrice, transactionFee);
actualCharge = actualCharge.sub(overestimation);
// After the relayed call has been executed and the actual charge estimated, the excess pre-charge is returned
token().safeTransfer(from, maxPossibleCharge.sub(actualCharge));
}
}
/**
* @title __unstable__ERC20Owned
* @dev An ERC20 token owned by another contract, which has minting permissions and can use transferFrom to receive
* anyone's tokens. This contract is an internal helper for GSNRecipientERC20Fee, and should not be used
* outside of this context.
*/
// solhint-disable-next-line contract-name-camelcase
contract __unstable__ERC20Owned is ERC20, Ownable {
uint256 private constant _UINT256_MAX = 2**256 - 1;
constructor(string memory name, string memory symbol) ERC20(name, symbol) { }
// The owner (GSNRecipientERC20Fee) can mint tokens
function mint(address account, uint256 amount) public virtual onlyOwner {
_mint(account, amount);
}
// The owner has 'infinite' allowance for all token holders
function allowance(address tokenOwner, address spender) public view virtual override returns (uint256) {
if (spender == owner()) {
return _UINT256_MAX;
} else {
return super.allowance(tokenOwner, spender);
}
}
// Allowance for the owner cannot be changed (it is always 'infinite')
function _approve(address tokenOwner, address spender, uint256 value) internal virtual override {
if (spender == owner()) {
return;
} else {
super._approve(tokenOwner, spender, value);
}
}
function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
if (recipient == owner()) {
_transfer(sender, recipient, amount);
return true;
} else {
return super.transferFrom(sender, recipient, amount);
}
}
}

View File

@ -0,0 +1,72 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "./GSNRecipient.sol";
import "../cryptography/ECDSA.sol";
/**
* @dev A xref:ROOT:gsn-strategies.adoc#gsn-strategies[GSN strategy] that allows relayed transactions through when they are
* accompanied by the signature of a trusted signer. The intent is for this signature to be generated by a server that
* performs validations off-chain. Note that nothing is charged to the user in this scheme. Thus, the server should make
* sure to account for this in their economic and threat model.
*/
contract GSNRecipientSignature is GSNRecipient {
using ECDSA for bytes32;
address private _trustedSigner;
enum GSNRecipientSignatureErrorCodes {
INVALID_SIGNER
}
/**
* @dev Sets the trusted signer that is going to be producing signatures to approve relayed calls.
*/
constructor(address trustedSigner) {
require(trustedSigner != address(0), "GSNRecipientSignature: trusted signer is the zero address");
_trustedSigner = trustedSigner;
}
/**
* @dev Ensures that only transactions with a trusted signature can be relayed through the GSN.
*/
function acceptRelayedCall(
address relay,
address from,
bytes memory encodedFunction,
uint256 transactionFee,
uint256 gasPrice,
uint256 gasLimit,
uint256 nonce,
bytes memory approvalData,
uint256
)
public
view
virtual
override
returns (uint256, bytes memory)
{
bytes memory blob = abi.encodePacked(
relay,
from,
encodedFunction,
transactionFee,
gasPrice,
gasLimit,
nonce, // Prevents replays on RelayHub
getHubAddr(), // Prevents replays in multiple RelayHubs
address(this) // Prevents replays in multiple recipients
);
if (keccak256(blob).toEthSignedMessageHash().recover(approvalData) == _trustedSigner) {
return _approveRelayedCall();
} else {
return _rejectRelayedCall(uint256(GSNRecipientSignatureErrorCodes.INVALID_SIGNER));
}
}
function _preRelayedCall(bytes memory) internal virtual override returns (bytes32) { }
function _postRelayedCall(bytes memory, bool, uint256, bytes32) internal virtual override { }
}

269
contracts/GSN/IRelayHub.sol Normal file
View File

@ -0,0 +1,269 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**
* @dev Interface for `RelayHub`, the core contract of the GSN. Users should not need to interact with this contract
* directly.
*
* See the https://github.com/OpenZeppelin/openzeppelin-gsn-helpers[OpenZeppelin GSN helpers] for more information on
* how to deploy an instance of `RelayHub` on your local test network.
*/
interface IRelayHub {
// Relay management
/**
* @dev Adds stake to a relay and sets its `unstakeDelay`. If the relay does not exist, it is created, and the caller
* of this function becomes its owner. If the relay already exists, only the owner can call this function. A relay
* cannot be its own owner.
*
* All Ether in this function call will be added to the relay's stake.
* Its unstake delay will be assigned to `unstakeDelay`, but the new value must be greater or equal to the current one.
*
* Emits a {Staked} event.
*/
function stake(address relayaddr, uint256 unstakeDelay) external payable;
/**
* @dev Emitted when a relay's stake or unstakeDelay are increased
*/
event Staked(address indexed relay, uint256 stake, uint256 unstakeDelay);
/**
* @dev Registers the caller as a relay.
* The relay must be staked for, and not be a contract (i.e. this function must be called directly from an EOA).
*
* This function can be called multiple times, emitting new {RelayAdded} events. Note that the received
* `transactionFee` is not enforced by {relayCall}.
*
* Emits a {RelayAdded} event.
*/
function registerRelay(uint256 transactionFee, string calldata url) external;
/**
* @dev Emitted when a relay is registered or re-registered. Looking at these events (and filtering out
* {RelayRemoved} events) lets a client discover the list of available relays.
*/
event RelayAdded(address indexed relay, address indexed owner, uint256 transactionFee, uint256 stake, uint256 unstakeDelay, string url);
/**
* @dev Removes (deregisters) a relay. Unregistered (but staked for) relays can also be removed.
*
* Can only be called by the owner of the relay. After the relay's `unstakeDelay` has elapsed, {unstake} will be
* callable.
*
* Emits a {RelayRemoved} event.
*/
function removeRelayByOwner(address relay) external;
/**
* @dev Emitted when a relay is removed (deregistered). `unstakeTime` is the time when unstake will be callable.
*/
event RelayRemoved(address indexed relay, uint256 unstakeTime);
/** Deletes the relay from the system, and gives back its stake to the owner.
*
* Can only be called by the relay owner, after `unstakeDelay` has elapsed since {removeRelayByOwner} was called.
*
* Emits an {Unstaked} event.
*/
function unstake(address relay) external;
/**
* @dev Emitted when a relay is unstaked for, including the returned stake.
*/
event Unstaked(address indexed relay, uint256 stake);
// States a relay can be in
enum RelayState {
Unknown, // The relay is unknown to the system: it has never been staked for
Staked, // The relay has been staked for, but it is not yet active
Registered, // The relay has registered itself, and is active (can relay calls)
Removed // The relay has been removed by its owner and can no longer relay calls. It must wait for its unstakeDelay to elapse before it can unstake
}
/**
* @dev Returns a relay's status. Note that relays can be deleted when unstaked or penalized, causing this function
* to return an empty entry.
*/
function getRelay(address relay) external view returns (uint256 totalStake, uint256 unstakeDelay, uint256 unstakeTime, address payable owner, RelayState state);
// Balance management
/**
* @dev Deposits Ether for a contract, so that it can receive (and pay for) relayed transactions.
*
* Unused balance can only be withdrawn by the contract itself, by calling {withdraw}.
*
* Emits a {Deposited} event.
*/
function depositFor(address target) external payable;
/**
* @dev Emitted when {depositFor} is called, including the amount and account that was funded.
*/
event Deposited(address indexed recipient, address indexed from, uint256 amount);
/**
* @dev Returns an account's deposits. These can be either a contract's funds, or a relay owner's revenue.
*/
function balanceOf(address target) external view returns (uint256);
/**
* Withdraws from an account's balance, sending it back to it. Relay owners call this to retrieve their revenue, and
* contracts can use it to reduce their funding.
*
* Emits a {Withdrawn} event.
*/
function withdraw(uint256 amount, address payable dest) external;
/**
* @dev Emitted when an account withdraws funds from `RelayHub`.
*/
event Withdrawn(address indexed account, address indexed dest, uint256 amount);
// Relaying
/**
* @dev Checks if the `RelayHub` will accept a relayed operation.
* Multiple things must be true for this to happen:
* - all arguments must be signed for by the sender (`from`)
* - the sender's nonce must be the current one
* - the recipient must accept this transaction (via {acceptRelayedCall})
*
* Returns a `PreconditionCheck` value (`OK` when the transaction can be relayed), or a recipient-specific error
* code if it returns one in {acceptRelayedCall}.
*/
function canRelay(
address relay,
address from,
address to,
bytes calldata encodedFunction,
uint256 transactionFee,
uint256 gasPrice,
uint256 gasLimit,
uint256 nonce,
bytes calldata signature,
bytes calldata approvalData
) external view returns (uint256 status, bytes memory recipientContext);
// Preconditions for relaying, checked by canRelay and returned as the corresponding numeric values.
enum PreconditionCheck {
OK, // All checks passed, the call can be relayed
WrongSignature, // The transaction to relay is not signed by requested sender
WrongNonce, // The provided nonce has already been used by the sender
AcceptRelayedCallReverted, // The recipient rejected this call via acceptRelayedCall
InvalidRecipientStatusCode // The recipient returned an invalid (reserved) status code
}
/**
* @dev Relays a transaction.
*
* For this to succeed, multiple conditions must be met:
* - {canRelay} must `return PreconditionCheck.OK`
* - the sender must be a registered relay
* - the transaction's gas price must be larger or equal to the one that was requested by the sender
* - the transaction must have enough gas to not run out of gas if all internal transactions (calls to the
* recipient) use all gas available to them
* - the recipient must have enough balance to pay the relay for the worst-case scenario (i.e. when all gas is
* spent)
*
* If all conditions are met, the call will be relayed and the recipient charged. {preRelayedCall}, the encoded
* function and {postRelayedCall} will be called in that order.
*
* Parameters:
* - `from`: the client originating the request
* - `to`: the target {IRelayRecipient} contract
* - `encodedFunction`: the function call to relay, including data
* - `transactionFee`: fee (%) the relay takes over actual gas cost
* - `gasPrice`: gas price the client is willing to pay
* - `gasLimit`: gas to forward when calling the encoded function
* - `nonce`: client's nonce
* - `signature`: client's signature over all previous params, plus the relay and RelayHub addresses
* - `approvalData`: dapp-specific data forwarded to {acceptRelayedCall}. This value is *not* verified by the
* `RelayHub`, but it still can be used for e.g. a signature.
*
* Emits a {TransactionRelayed} event.
*/
function relayCall(
address from,
address to,
bytes calldata encodedFunction,
uint256 transactionFee,
uint256 gasPrice,
uint256 gasLimit,
uint256 nonce,
bytes calldata signature,
bytes calldata approvalData
) external;
/**
* @dev Emitted when an attempt to relay a call failed.
*
* This can happen due to incorrect {relayCall} arguments, or the recipient not accepting the relayed call. The
* actual relayed call was not executed, and the recipient not charged.
*
* The `reason` parameter contains an error code: values 1-10 correspond to `PreconditionCheck` entries, and values
* over 10 are custom recipient error codes returned from {acceptRelayedCall}.
*/
event CanRelayFailed(address indexed relay, address indexed from, address indexed to, bytes4 selector, uint256 reason);
/**
* @dev Emitted when a transaction is relayed.
* Useful when monitoring a relay's operation and relayed calls to a contract
*
* Note that the actual encoded function might be reverted: this is indicated in the `status` parameter.
*
* `charge` is the Ether value deducted from the recipient's balance, paid to the relay's owner.
*/
event TransactionRelayed(address indexed relay, address indexed from, address indexed to, bytes4 selector, RelayCallStatus status, uint256 charge);
// Reason error codes for the TransactionRelayed event
enum RelayCallStatus {
OK, // The transaction was successfully relayed and execution successful - never included in the event
RelayedCallFailed, // The transaction was relayed, but the relayed call failed
PreRelayedFailed, // The transaction was not relayed due to preRelatedCall reverting
PostRelayedFailed, // The transaction was relayed and reverted due to postRelatedCall reverting
RecipientBalanceChanged // The transaction was relayed and reverted due to the recipient's balance changing
}
/**
* @dev Returns how much gas should be forwarded to a call to {relayCall}, in order to relay a transaction that will
* spend up to `relayedCallStipend` gas.
*/
function requiredGas(uint256 relayedCallStipend) external view returns (uint256);
/**
* @dev Returns the maximum recipient charge, given the amount of gas forwarded, gas price and relay fee.
*/
function maxPossibleCharge(uint256 relayedCallStipend, uint256 gasPrice, uint256 transactionFee) external view returns (uint256);
// Relay penalization.
// Any account can penalize relays, removing them from the system immediately, and rewarding the
// reporter with half of the relay's stake. The other half is burned so that, even if the relay penalizes itself, it
// still loses half of its stake.
/**
* @dev Penalize a relay that signed two transactions using the same nonce (making only the first one valid) and
* different data (gas price, gas limit, etc. may be different).
*
* The (unsigned) transaction data and signature for both transactions must be provided.
*/
function penalizeRepeatedNonce(bytes calldata unsignedTx1, bytes calldata signature1, bytes calldata unsignedTx2, bytes calldata signature2) external;
/**
* @dev Penalize a relay that sent a transaction that didn't target ``RelayHub``'s {registerRelay} or {relayCall}.
*/
function penalizeIllegalTransaction(bytes calldata unsignedTx, bytes calldata signature) external;
/**
* @dev Emitted when a relay is penalized.
*/
event Penalized(address indexed relay, address sender, uint256 amount);
/**
* @dev Returns an account's nonce in `RelayHub`.
*/
function getNonce(address from) external view returns (uint256);
}

View File

@ -0,0 +1,76 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**
* @dev Base interface for a contract that will be called via the GSN from {IRelayHub}.
*
* TIP: You don't need to write an implementation yourself! Inherit from {GSNRecipient} instead.
*/
interface IRelayRecipient {
/**
* @dev Returns the address of the {IRelayHub} instance this recipient interacts with.
*/
function getHubAddr() external view returns (address);
/**
* @dev Called by {IRelayHub} to validate if this recipient accepts being charged for a relayed call. Note that the
* recipient will be charged regardless of the execution result of the relayed call (i.e. if it reverts or not).
*
* The relay request was originated by `from` and will be served by `relay`. `encodedFunction` is the relayed call
* calldata, so its first four bytes are the function selector. The relayed call will be forwarded `gasLimit` gas,
* and the transaction executed with a gas price of at least `gasPrice`. ``relay``'s fee is `transactionFee`, and the
* recipient will be charged at most `maxPossibleCharge` (in wei). `nonce` is the sender's (`from`) nonce for
* replay attack protection in {IRelayHub}, and `approvalData` is a optional parameter that can be used to hold a signature
* over all or some of the previous values.
*
* Returns a tuple, where the first value is used to indicate approval (0) or rejection (custom non-zero error code,
* values 1 to 10 are reserved) and the second one is data to be passed to the other {IRelayRecipient} functions.
*
* {acceptRelayedCall} is called with 50k gas: if it runs out during execution, the request will be considered
* rejected. A regular revert will also trigger a rejection.
*/
function acceptRelayedCall(
address relay,
address from,
bytes calldata encodedFunction,
uint256 transactionFee,
uint256 gasPrice,
uint256 gasLimit,
uint256 nonce,
bytes calldata approvalData,
uint256 maxPossibleCharge
)
external
view
returns (uint256, bytes memory);
/**
* @dev Called by {IRelayHub} on approved relay call requests, before the relayed call is executed. This allows to e.g.
* pre-charge the sender of the transaction.
*
* `context` is the second value returned in the tuple by {acceptRelayedCall}.
*
* Returns a value to be passed to {postRelayedCall}.
*
* {preRelayedCall} is called with 100k gas: if it runs out during execution or otherwise reverts, the relayed call
* will not be executed, but the recipient will still be charged for the transaction's cost.
*/
function preRelayedCall(bytes calldata context) external returns (bytes32);
/**
* @dev Called by {IRelayHub} on approved relay call requests, after the relayed call is executed. This allows to e.g.
* charge the user for the relayed call costs, return any overcharges from {preRelayedCall}, or perform
* contract-specific bookkeeping.
*
* `context` is the second value returned in the tuple by {acceptRelayedCall}. `success` is the execution status of
* the relayed call. `actualCharge` is an estimate of how much the recipient will be charged for the transaction,
* not including any gas used by {postRelayedCall} itself. `preRetVal` is {preRelayedCall}'s return value.
*
*
* {postRelayedCall} is called with 100k gas: if it runs out during execution or otherwise reverts, the relayed call
* and the call to {preRelayedCall} will be reverted retroactively, but the recipient will still be charged for the
* transaction's cost.
*/
function postRelayedCall(bytes calldata context, bool success, uint256 actualCharge, bytes32 preRetVal) external;
}

31
contracts/GSN/README.adoc Normal file
View File

@ -0,0 +1,31 @@
= Gas Station Network (GSN)
[.readme-notice]
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/gsn
This set of contracts provide all the tools required to make a contract callable via the https://gsn.openzeppelin.com[Gas Station Network].
TIP: If you're new to the GSN, head over to our xref:learn::sending-gasless-transactions.adoc[overview of the system] and basic guide to xref:ROOT:gsn.adoc[creating a GSN-capable contract].
The core contract a recipient must inherit from is {GSNRecipient}: it includes all necessary interfaces, as well as some helper methods to make interacting with the GSN easier.
Utilities to make writing xref:ROOT:gsn-strategies.adoc[GSN strategies] easy are available in {GSNRecipient}, or you can simply use one of our pre-made strategies:
* {GSNRecipientERC20Fee} charges the end user for gas costs in an application-specific xref:ROOT:tokens.adoc#ERC20[ERC20 token]
* {GSNRecipientSignature} accepts all relayed calls that have been signed by a trusted third party (e.g. a private key in a backend)
You can also take a look at the two contract interfaces that make up the GSN protocol: {IRelayRecipient} and {IRelayHub}, but you won't need to use those directly.
== Recipient
{{GSNRecipient}}
== Strategies
{{GSNRecipientSignature}}
{{GSNRecipientERC20Fee}}
== Protocol
{{IRelayRecipient}}
{{IRelayHub}}

View File

@ -1,27 +1,14 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../utils/EnumerableSet.sol";
import "../utils/Address.sol";
import "../utils/Context.sol";
import "../utils/introspection/ERC165.sol";
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
function hasRole(bytes32 role, address account) external view returns (bool);
function getRoleAdmin(bytes32 role) external view returns (bytes32);
function grantRole(bytes32 role, address account) external;
function revokeRole(bytes32 role, address account) external;
function renounceRole(bytes32 role, address account) external;
}
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
* control mechanisms.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
@ -54,9 +41,12 @@ interface IAccessControl {
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
abstract contract AccessControl is Context {
using EnumerableSet for EnumerableSet.AddressSet;
using Address for address;
struct RoleData {
mapping (address => bool) members;
EnumerableSet.AddressSet members;
bytes32 adminRole;
}
@ -92,18 +82,34 @@ abstract contract AccessControl is Context, IAccessControl, ERC165 {
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev See {IERC165-supportsInterface}.
* @dev Returns `true` if `account` has been granted `role`.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId
|| super.supportsInterface(interfaceId);
function hasRole(bytes32 role, address account) public view returns (bool) {
return _roles[role].members.contains(account);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
* @dev Returns the number of accounts that have `role`. Can be used
* together with {getRoleMember} to enumerate all bearers of a role.
*/
function hasRole(bytes32 role, address account) public view override returns (bool) {
return _roles[role].members[account];
function getRoleMemberCount(bytes32 role) public view returns (uint256) {
return _roles[role].members.length();
}
/**
* @dev Returns one of the accounts that have `role`. `index` must be a
* value between 0 and {getRoleMemberCount}, non-inclusive.
*
* Role bearers are not sorted in any particular way, and their ordering may
* change at any point.
*
* WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
* you perform all queries on the same block. See the following
* https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
* for more information.
*/
function getRoleMember(bytes32 role, uint256 index) public view returns (address) {
return _roles[role].members.at(index);
}
/**
@ -112,7 +118,7 @@ abstract contract AccessControl is Context, IAccessControl, ERC165 {
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view override returns (bytes32) {
function getRoleAdmin(bytes32 role) public view returns (bytes32) {
return _roles[role].adminRole;
}
@ -126,8 +132,8 @@ abstract contract AccessControl is Context, IAccessControl, ERC165 {
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) public virtual override {
require(hasRole(getRoleAdmin(role), _msgSender()), "AccessControl: sender must be an admin to grant");
function grantRole(bytes32 role, address account) public virtual {
require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to grant");
_grantRole(role, account);
}
@ -141,8 +147,8 @@ abstract contract AccessControl is Context, IAccessControl, ERC165 {
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) public virtual override {
require(hasRole(getRoleAdmin(role), _msgSender()), "AccessControl: sender must be an admin to revoke");
function revokeRole(bytes32 role, address account) public virtual {
require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to revoke");
_revokeRole(role, account);
}
@ -161,7 +167,7 @@ abstract contract AccessControl is Context, IAccessControl, ERC165 {
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) public virtual override {
function renounceRole(bytes32 role, address account) public virtual {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
@ -193,20 +199,18 @@ abstract contract AccessControl is Context, IAccessControl, ERC165 {
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
emit RoleAdminChanged(role, getRoleAdmin(role), adminRole);
emit RoleAdminChanged(role, _roles[role].adminRole, adminRole);
_roles[role].adminRole = adminRole;
}
function _grantRole(bytes32 role, address account) private {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
if (_roles[role].members.add(account)) {
emit RoleGranted(role, account, _msgSender());
}
}
function _revokeRole(bytes32 role, address account) private {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
if (_roles[role].members.remove(account)) {
emit RoleRevoked(role, account, _msgSender());
}
}

View File

@ -1,87 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./AccessControl.sol";
import "../utils/structs/EnumerableSet.sol";
/**
* @dev External interface of AccessControlEnumerable declared to support ERC165 detection.
*/
interface IAccessControlEnumerable {
function getRoleMember(bytes32 role, uint256 index) external view returns (address);
function getRoleMemberCount(bytes32 role) external view returns (uint256);
}
/**
* @dev Extension of {AccessControl} that allows enumerating the members of each role.
*/
abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {
using EnumerableSet for EnumerableSet.AddressSet;
mapping (bytes32 => EnumerableSet.AddressSet) private _roleMembers;
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControlEnumerable).interfaceId
|| super.supportsInterface(interfaceId);
}
/**
* @dev Returns one of the accounts that have `role`. `index` must be a
* value between 0 and {getRoleMemberCount}, non-inclusive.
*
* Role bearers are not sorted in any particular way, and their ordering may
* change at any point.
*
* WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
* you perform all queries on the same block. See the following
* https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
* for more information.
*/
function getRoleMember(bytes32 role, uint256 index) public view override returns (address) {
return _roleMembers[role].at(index);
}
/**
* @dev Returns the number of accounts that have `role`. Can be used
* together with {getRoleMember} to enumerate all bearers of a role.
*/
function getRoleMemberCount(bytes32 role) public view override returns (uint256) {
return _roleMembers[role].length();
}
/**
* @dev Overload {grantRole} to track enumerable memberships
*/
function grantRole(bytes32 role, address account) public virtual override {
super.grantRole(role, account);
_roleMembers[role].add(account);
}
/**
* @dev Overload {revokeRole} to track enumerable memberships
*/
function revokeRole(bytes32 role, address account) public virtual override {
super.revokeRole(role, account);
_roleMembers[role].remove(account);
}
/**
* @dev Overload {renounceRole} to track enumerable memberships
*/
function renounceRole(bytes32 role, address account) public virtual override {
super.renounceRole(role, account);
_roleMembers[role].remove(account);
}
/**
* @dev Overload {_setupRole} to track enumerable memberships
*/
function _setupRole(bytes32 role, address account) internal virtual override {
super._setupRole(role, account);
_roleMembers[role].add(account);
}
}

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../utils/Context.sol";
/**

View File

@ -7,6 +7,7 @@ This directory provides ways to restrict who can access the functions of a contr
- {AccessControl} provides a general role based access control mechanism. Multiple hierarchical roles can be created and assigned each to multiple accounts.
- {Ownable} is a simpler mechanism with a single owner "role" that can be assigned to a single account. This simpler mechanism can be useful for quick tests but projects with production concerns are likely to outgrow it.
- {TimelockController} is used in combination with one of the above two mechanisms. By assigning a role to an instance of the `TimelockController` contract, the access to the functions controlled by that role will be delayed by some amount of time.
== Authorization
@ -14,4 +15,87 @@ This directory provides ways to restrict who can access the functions of a contr
{{AccessControl}}
{{AccessControlEnumerable}}
== Timelock
{{TimelockController}}
[[timelock-terminology]]
==== Terminology
* *Operation:* A transaction (or a set of transactions) that is the subject of the timelock. It has to be scheduled by a proposer and executed by an executor. The timelock enforces a minimum delay between the proposition and the execution (see xref:access-control.adoc#operation_lifecycle[operation lifecycle]). If the operation contains multiple transactions (batch mode), they are executed atomically. Operations are identified by the hash of their content.
* *Operation status:*
** *Unset:* An operation that is not part of the timelock mechanism.
** *Pending:* An operation that has been scheduled, before the timer expires.
** *Ready:* An operation that has been scheduled, after the timer expires.
** *Done:* An operation that has been executed.
* *Predecessor*: An (optional) dependency between operations. An operation can depend on another operation (its predecessor), forcing the execution order of these two operations.
* *Role*:
** *Proposer:* An address (smart contract or EOA) that is in charge of scheduling (and cancelling) operations.
** *Executor:* An address (smart contract or EOA) that is in charge of executing operations.
[[timelock-operation]]
==== Operation structure
Operation executed by the xref:api:access.adoc#TimelockController[`TimelockControler`] can contain one or multiple subsequent calls. Depending on whether you need to multiple calls to be executed atomically, you can either use simple or batched operations.
Both operations contain:
* *Target*, the address of the smart contract that the timelock should operate on.
* *Value*, in wei, that should be sent with the transaction. Most of the time this will be 0. Ether can be deposited before-end or passed along when executing the transaction.
* *Data*, containing the encoded function selector and parameters of the call. This can be produced using a number of tools. For example, a maintenance operation granting role `ROLE` to `ACCOUNT` can be encode using web3js as follows:
```javascript
const data = timelock.contract.methods.grantRole(ROLE, ACCOUNT).encodeABI()
```
* *Predecessor*, that specifies a dependency between operations. This dependency is optional. Use `bytes32(0)` if the operation does not have any dependency.
* *Salt*, used to disambiguate two otherwise identical operations. This can be any random value.
In the case of batched operations, `target`, `value` and `data` are specified as arrays, which must be of the same length.
[[timelock-operation-lifecycle]]
==== Operation lifecycle
Timelocked operations are identified by a unique id (their hash) and follow a specific lifecycle:
`Unset` -> `Pending` -> `Pending` + `Ready` -> `Done`
* By calling xref:api:access.adoc#TimelockController-schedule-address-uint256-bytes-bytes32-bytes32-uint256-[`schedule`] (or xref:api:access.adoc#TimelockController-scheduleBatch-address---uint256---bytes---bytes32-bytes32-uint256-[`scheduleBatch`]), a proposer moves the operation from the `Unset` to the `Pending` state. This starts a timer that must be longer than the minimum delay. The timer expires at a timestamp accessible through the xref:api:access.adoc#TimelockController-getTimestamp-bytes32-[`getTimestamp`] method.
* Once the timer expires, the operation automatically gets the `Ready` state. At this point, it can be executed.
* By calling xref:api:access.adoc#TimelockController-TimelockController-execute-address-uint256-bytes-bytes32-bytes32-[`execute`] (or xref:api:access.adoc#TimelockController-executeBatch-address---uint256---bytes---bytes32-bytes32-[`executeBatch`]), an executor triggers the operation's underlying transactions and moves it to the `Done` state. If the operation has a predecessor, it has to be in the `Done` state for this transition to succeed.
* xref:api:access.adoc#TimelockController-TimelockController-cancel-bytes32-[`cancel`] allows proposers to cancel any `Pending` operation. This resets the operation to the `Unset` state. It is thus possible for a proposer to re-schedule an operation that has been cancelled. In this case, the timer restarts when the operation is re-scheduled.
Operations status can be queried using the functions:
* xref:api:access.adoc#TimelockController-isOperationPending-bytes32-[`isOperationPending(bytes32)`]
* xref:api:access.adoc#TimelockController-isOperationReady-bytes32-[`isOperationReady(bytes32)`]
* xref:api:access.adoc#TimelockController-isOperationDone-bytes32-[`isOperationDone(bytes32)`]
[[timelock-roles]]
==== Roles
[[timelock-admin]]
===== Admin
The admins are in charge of managing proposers and executors. For the timelock to be self-governed, this role should only be given to the timelock itself. Upon deployment, both the timelock and the deployer have this role. After further configuration and testing, the deployer can renounce this role such that all further maintenance operations have to go through the timelock process.
This role is identified by the *TIMELOCK_ADMIN_ROLE* value: `0x5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca5`
[[timelock-proposer]]
===== Proposer
The proposers are in charge of scheduling (and cancelling) operations. This is a critical role, that should be given to governing entities. This could be an EOA, a multisig, or a DAO.
WARNING: *Proposer fight:* Having multiple proposers, while providing redundancy in case one becomes unavailable, can be dangerous. As proposer have their say on all operations, they could cancel operations they disagree with, including operations to remove them for the proposers.
This role is identified by the *PROPOSER_ROLE* value: `0xb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc1`
[[timelock-executor]]
===== Executor
The executors are in charge of executing the operations scheduled by the proposers once the timelock expires. Logic dictates that multisig or DAO that are proposers should also be executors in order to guarantee operations that have been scheduled will eventually be executed. However, having additional executor can reduce the cost (the executing transaction does not require validation by the multisig or DAO that proposed it), while ensuring whoever is in charge of execution cannot trigger actions that have not been scheduled by the proposers.
This role is identified by the *EXECUTOR_ROLE* value: `0xd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e63`
WARNING: A live contract without at least one proposer and one executor is locked. Make sure these roles are filled by reliable entities before the deployer renounces its administrative rights in favour of the timelock contract itself. See the {AccessControl} documentation to learn more about role management.

View File

@ -1,8 +1,10 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
import "../access/AccessControl.sol";
import "./../math/SafeMath.sol";
import "./AccessControl.sol";
/**
* @dev Contract module which acts as a timelocked controller. When set as the
@ -20,6 +22,7 @@ import "../access/AccessControl.sol";
* _Available since v3.3._
*/
contract TimelockController is AccessControl {
bytes32 public constant TIMELOCK_ADMIN_ROLE = keccak256("TIMELOCK_ADMIN_ROLE");
bytes32 public constant PROPOSER_ROLE = keccak256("PROPOSER_ROLE");
bytes32 public constant EXECUTOR_ROLE = keccak256("EXECUTOR_ROLE");
@ -196,7 +199,7 @@ contract TimelockController is AccessControl {
require(!isOperation(id), "TimelockController: operation already scheduled");
require(delay >= getMinDelay(), "TimelockController: insufficient delay");
// solhint-disable-next-line not-rely-on-time
_timestamps[id] = block.timestamp + delay;
_timestamps[id] = SafeMath.add(block.timestamp, delay);
}
/**

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
@ -47,7 +47,7 @@ library ECDSA {
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* @dev Overload of {ECDSA-recover-bytes32-bytes-} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
@ -72,9 +72,9 @@ library ECDSA {
/**
* @dev Returns an Ethereum Signed Message, created from a `hash`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
* replicates the behavior of the
* https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign[`eth_sign`]
* JSON-RPC method.
*
* See {recover}.
*/
@ -83,17 +83,4 @@ library ECDSA {
// enforced by the type signature above
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
}
/**
* @dev Returns an Ethereum Signed Typed Data, created from a
* `domainSeparator` and a `structHash`. This produces hash corresponding
* to the one signed with the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
* JSON-RPC method as part of EIP-712.
*
* See {recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
}
}

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
/**
* @dev These functions deal with verification of Merkle trees (hash trees),

View File

@ -0,0 +1,16 @@
= Cryptography
[.readme-notice]
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/cryptography
This collection of libraries provides simple and safe ways to use different cryptographic primitives.
The following related EIPs are in draft status and can be found in the drafts directory.
- {EIP712}
== Libraries
{{ECDSA}}
{{MerkleProof}}

View File

@ -1,8 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./ECDSA.sol";
pragma solidity >=0.6.0 <0.8.0;
/**
* @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
@ -53,7 +51,7 @@ abstract contract EIP712 {
bytes32 typeHash = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
_HASHED_NAME = hashedName;
_HASHED_VERSION = hashedVersion;
_CACHED_CHAIN_ID = block.chainid;
_CACHED_CHAIN_ID = _getChainId();
_CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);
_TYPE_HASH = typeHash;
}
@ -61,8 +59,8 @@ abstract contract EIP712 {
/**
* @dev Returns the domain separator for the current chain.
*/
function _domainSeparatorV4() internal view returns (bytes32) {
if (block.chainid == _CACHED_CHAIN_ID) {
function _domainSeparatorV4() internal view virtual returns (bytes32) {
if (_getChainId() == _CACHED_CHAIN_ID) {
return _CACHED_DOMAIN_SEPARATOR;
} else {
return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);
@ -75,7 +73,7 @@ abstract contract EIP712 {
typeHash,
name,
version,
block.chainid,
_getChainId(),
address(this)
)
);
@ -97,6 +95,14 @@ abstract contract EIP712 {
* ```
*/
function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
return keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), structHash));
}
function _getChainId() private view returns (uint256 chainId) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
// solhint-disable-next-line no-inline-assembly
assembly {
chainId := chainid()
}
}
}

View File

@ -1,12 +1,12 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity >=0.6.5 <0.8.0;
import "./draft-IERC20Permit.sol";
import "../ERC20.sol";
import "../../../utils/cryptography/draft-EIP712.sol";
import "../../../utils/cryptography/ECDSA.sol";
import "../../../utils/Counters.sol";
import "../token/ERC20/ERC20.sol";
import "./IERC20Permit.sol";
import "../cryptography/ECDSA.sol";
import "../utils/Counters.sol";
import "./EIP712.sol";
/**
* @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity >=0.6.0 <0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in

View File

@ -0,0 +1,15 @@
= Draft EIPs
This directory contains implementations of EIPs that are still in Draft status.
Due to their nature as drafts, the details of these contracts may change and we cannot guarantee their xref:ROOT:releases-stability.adoc[stability]. Minor releases of OpenZeppelin Contracts may contain breaking changes for the contracts in this directory, which will be duly announced in the https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/CHANGELOG.md[changelog]. The EIPs included here are used by projects in production and this may make them less likely to change significantly.
== Cryptography
{{EIP712}}
== ERC 20
{{IERC20Permit}}
{{ERC20Permit}}

View File

@ -1,10 +0,0 @@
= Finance
[.readme-notice]
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/finance
This directory includes primitives for financial systems. We currently only offer the {PaymentSplitter} contract, but we want to grow this directory so we welcome ideas.
== PaymentSplitter
{{PaymentSplitter}}

View File

@ -1,91 +0,0 @@
= Governance
[.readme-notice]
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/governance
This directory includes primitives for on-chain governance. We currently only offer the {TimelockController} contract, that can be used as a component in a governance systems to introduce a delay between a proposal and its execution.
== Timelock
{{TimelockController}}
[[timelock-terminology]]
==== Terminology
* *Operation:* A transaction (or a set of transactions) that is the subject of the timelock. It has to be scheduled by a proposer and executed by an executor. The timelock enforces a minimum delay between the proposition and the execution (see xref:access-control.adoc#operation_lifecycle[operation lifecycle]). If the operation contains multiple transactions (batch mode), they are executed atomically. Operations are identified by the hash of their content.
* *Operation status:*
** *Unset:* An operation that is not part of the timelock mechanism.
** *Pending:* An operation that has been scheduled, before the timer expires.
** *Ready:* An operation that has been scheduled, after the timer expires.
** *Done:* An operation that has been executed.
* *Predecessor*: An (optional) dependency between operations. An operation can depend on another operation (its predecessor), forcing the execution order of these two operations.
* *Role*:
** *Proposer:* An address (smart contract or EOA) that is in charge of scheduling (and cancelling) operations.
** *Executor:* An address (smart contract or EOA) that is in charge of executing operations.
[[timelock-operation]]
==== Operation structure
Operation executed by the xref:api:governance.adoc#TimelockController[`TimelockControler`] can contain one or multiple subsequent calls. Depending on whether you need to multiple calls to be executed atomically, you can either use simple or batched operations.
Both operations contain:
* *Target*, the address of the smart contract that the timelock should operate on.
* *Value*, in wei, that should be sent with the transaction. Most of the time this will be 0. Ether can be deposited before-end or passed along when executing the transaction.
* *Data*, containing the encoded function selector and parameters of the call. This can be produced using a number of tools. For example, a maintenance operation granting role `ROLE` to `ACCOUNT` can be encode using web3js as follows:
```javascript
const data = timelock.contract.methods.grantRole(ROLE, ACCOUNT).encodeABI()
```
* *Predecessor*, that specifies a dependency between operations. This dependency is optional. Use `bytes32(0)` if the operation does not have any dependency.
* *Salt*, used to disambiguate two otherwise identical operations. This can be any random value.
In the case of batched operations, `target`, `value` and `data` are specified as arrays, which must be of the same length.
[[timelock-operation-lifecycle]]
==== Operation lifecycle
Timelocked operations are identified by a unique id (their hash) and follow a specific lifecycle:
`Unset` -> `Pending` -> `Pending` + `Ready` -> `Done`
* By calling xref:api:governance.adoc#TimelockController-schedule-address-uint256-bytes-bytes32-bytes32-uint256-[`schedule`] (or xref:api:governance.adoc#TimelockController-scheduleBatch-address---uint256---bytes---bytes32-bytes32-uint256-[`scheduleBatch`]), a proposer moves the operation from the `Unset` to the `Pending` state. This starts a timer that must be longer than the minimum delay. The timer expires at a timestamp accessible through the xref:api:governance.adoc#TimelockController-getTimestamp-bytes32-[`getTimestamp`] method.
* Once the timer expires, the operation automatically gets the `Ready` state. At this point, it can be executed.
* By calling xref:api:governance.adoc#TimelockController-TimelockController-execute-address-uint256-bytes-bytes32-bytes32-[`execute`] (or xref:api:governance.adoc#TimelockController-executeBatch-address---uint256---bytes---bytes32-bytes32-[`executeBatch`]), an executor triggers the operation's underlying transactions and moves it to the `Done` state. If the operation has a predecessor, it has to be in the `Done` state for this transition to succeed.
* xref:api:governance.adoc#TimelockController-TimelockController-cancel-bytes32-[`cancel`] allows proposers to cancel any `Pending` operation. This resets the operation to the `Unset` state. It is thus possible for a proposer to re-schedule an operation that has been cancelled. In this case, the timer restarts when the operation is re-scheduled.
Operations status can be queried using the functions:
* xref:api:governance.adoc#TimelockController-isOperationPending-bytes32-[`isOperationPending(bytes32)`]
* xref:api:governance.adoc#TimelockController-isOperationReady-bytes32-[`isOperationReady(bytes32)`]
* xref:api:governance.adoc#TimelockController-isOperationDone-bytes32-[`isOperationDone(bytes32)`]
[[timelock-roles]]
==== Roles
[[timelock-admin]]
===== Admin
The admins are in charge of managing proposers and executors. For the timelock to be self-governed, this role should only be given to the timelock itself. Upon deployment, both the timelock and the deployer have this role. After further configuration and testing, the deployer can renounce this role such that all further maintenance operations have to go through the timelock process.
This role is identified by the *TIMELOCK_ADMIN_ROLE* value: `0x5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca5`
[[timelock-proposer]]
===== Proposer
The proposers are in charge of scheduling (and cancelling) operations. This is a critical role, that should be given to governing entities. This could be an EOA, a multisig, or a DAO.
WARNING: *Proposer fight:* Having multiple proposers, while providing redundancy in case one becomes unavailable, can be dangerous. As proposer have their say on all operations, they could cancel operations they disagree with, including operations to remove them for the proposers.
This role is identified by the *PROPOSER_ROLE* value: `0xb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc1`
[[timelock-executor]]
===== Executor
The executors are in charge of executing the operations scheduled by the proposers once the timelock expires. Logic dictates that multisig or DAO that are proposers should also be executors in order to guarantee operations that have been scheduled will eventually be executed. However, having additional executor can reduce the cost (the executing transaction does not require validation by the multisig or DAO that proposed it), while ensuring whoever is in charge of execution cannot trigger actions that have not been scheduled by the proposers.
This role is identified by the *EXECUTOR_ROLE* value: `0xd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e63`
WARNING: A live contract without at least one proposer and one executor is locked. Make sure these roles are filled by reliable entities before the deployer renounces its administrative rights in favour of the timelock contract itself. See the {AccessControl} documentation to learn more about role management.

View File

@ -1,26 +1,39 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "./ERC165.sol";
import "./IERC165.sol";
/**
* @dev Storage based implementation of the {IERC165} interface.
* @dev Implementation of the {IERC165} interface.
*
* Contracts may inherit from this and call {_registerInterface} to declare
* their support of an interface.
*/
abstract contract ERC165Storage is ERC165 {
abstract contract ERC165 is IERC165 {
/*
* bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
*/
bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
/**
* @dev Mapping of interface ids to whether or not it's supported.
*/
mapping(bytes4 => bool) private _supportedInterfaces;
constructor () {
// Derived contracts need only register support for their own interfaces,
// we register support for ERC165 itself here
_registerInterface(_INTERFACE_ID_ERC165);
}
/**
* @dev See {IERC165-supportsInterface}.
*
* Time complexity O(1), guaranteed to always use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return super.supportsInterface(interfaceId) || _supportedInterfaces[interfaceId];
return _supportedInterfaces[interfaceId];
}
/**

View File

@ -1,8 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IERC165.sol";
pragma solidity ^0.7.0;
/**
* @dev Library used to query support of an interface declared via {IERC165}.
@ -15,13 +13,18 @@ library ERC165Checker {
// As per the EIP-165 spec, no interface should ever match 0xffffffff
bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;
/*
* bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
*/
bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
/**
* @dev Returns true if `account` supports the {IERC165} interface,
*/
function supportsERC165(address account) internal view returns (bool) {
// Any contract that implements ERC165 must explicitly indicate support of
// InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid
return _supportsERC165Interface(account, type(IERC165).interfaceId) &&
return _supportsERC165Interface(account, _INTERFACE_ID_ERC165) &&
!_supportsERC165Interface(account, _INTERFACE_ID_INVALID);
}
@ -100,9 +103,29 @@ library ERC165Checker {
* Interface identification is specified in ERC-165.
*/
function _supportsERC165Interface(address account, bytes4 interfaceId) private view returns (bool) {
bytes memory encodedParams = abi.encodeWithSelector(IERC165(account).supportsInterface.selector, interfaceId);
// success determines whether the staticcall succeeded and result determines
// whether the contract at account indicates support of _interfaceId
(bool success, bool result) = _callERC165SupportsInterface(account, interfaceId);
return (success && result);
}
/**
* @notice Calls the function with selector 0x01ffc9a7 (ERC165) and suppresses throw
* @param account The address of the contract to query for support of an interface
* @param interfaceId The interface identifier, as specified in ERC-165
* @return success true if the STATICCALL succeeded, false otherwise
* @return result true if the STATICCALL succeeded and the contract at account
* indicates support of the interface with identifier interfaceId, false otherwise
*/
function _callERC165SupportsInterface(address account, bytes4 interfaceId)
private
view
returns (bool, bool)
{
bytes memory encodedParams = abi.encodeWithSelector(_INTERFACE_ID_ERC165, interfaceId);
(bool success, bytes memory result) = account.staticcall{ gas: 30000 }(encodedParams);
if (result.length < 32) return false;
return success && abi.decode(result, (bool));
if (result.length < 32) return (false, false);
return (success, abi.decode(result, (bool)));
}
}

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "./IERC1820Implementer.sol";
@ -13,7 +13,7 @@ import "./IERC1820Implementer.sol";
* registration to be complete.
*/
contract ERC1820Implementer is IERC1820Implementer {
bytes32 private constant _ERC1820_ACCEPT_MAGIC = keccak256("ERC1820_ACCEPT_MAGIC");
bytes32 constant private _ERC1820_ACCEPT_MAGIC = keccak256(abi.encodePacked("ERC1820_ACCEPT_MAGIC"));
mapping(bytes32 => mapping(address => bool)) private _supportedInterfaces;

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
/**
* @dev Interface of the ERC165 standard, as defined in the

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
/**
* @dev Interface for an ERC1820 implementer, as defined in the

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
/**
* @dev Interface of the global ERC1820 Registry, as defined in the

View File

@ -0,0 +1,31 @@
= Introspection
[.readme-notice]
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/introspection
This set of interfaces and contracts deal with https://en.wikipedia.org/wiki/Type_introspection[type introspection] of contracts, that is, examining which functions can be called on them. This is usually referred to as a contract's _interface_.
Ethereum contracts have no native concept of an interface, so applications must usually simply trust they are not making an incorrect call. For trusted setups this is a non-issue, but often unknown and untrusted third-party addresses need to be interacted with. There may even not be any direct calls to them! (e.g. `ERC20` tokens may be sent to a contract that lacks a way to transfer them out of it, locking them forever). In these cases, a contract _declaring_ its interface can be very helpful in preventing errors.
There are two main ways to approach this.
* Locally, where a contract implements `IERC165` and declares an interface, and a second one queries it directly via `ERC165Checker`.
* Globally, where a global and unique registry (`IERC1820Registry`) is used to register implementers of a certain interface (`IERC1820Implementer`). It is then the registry that is queried, which allows for more complex setups, like contracts implementing interfaces for externally-owned accounts.
Note that, in all cases, accounts simply _declare_ their interfaces, but they are not required to actually implement them. This mechanism can therefore be used to both prevent errors and allow for complex interactions (see `ERC777`), but it must not be relied on for security.
== Local
{{IERC165}}
{{ERC165}}
{{ERC165Checker}}
== Global
{{IERC1820Registry}}
{{IERC1820Implementer}}
{{ERC1820Implementer}}

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
/**
* @dev Standard math utilities missing in the Solidity language.

View File

@ -0,0 +1,14 @@
= Math
[.readme-notice]
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/math
These are math-related utilities.
== Libraries
{{SafeMath}}
{{SignedSafeMath}}
{{Math}}

View File

@ -1,16 +1,19 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.
pragma solidity ^0.7.0;
/**
* @dev Wrappers over Solidity's arithmetic operations.
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* NOTE: `SafeMath` is no longer needed starting with Solidity 0.8. The compiler
* now has built in overflow checking.
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
@ -19,11 +22,9 @@ library SafeMath {
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
/**
@ -32,10 +33,8 @@ library SafeMath {
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
if (b > a) return (false, 0);
return (true, a - b);
}
/**
@ -44,15 +43,13 @@ library SafeMath {
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// 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);
}
// 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);
}
/**
@ -61,10 +58,8 @@ library SafeMath {
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
if (b == 0) return (false, 0);
return (true, a / b);
}
/**
@ -73,10 +68,8 @@ library SafeMath {
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
if (b == 0) return (false, 0);
return (true, a % b);
}
/**
@ -90,7 +83,9 @@ library SafeMath {
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
return a + b;
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
@ -104,6 +99,7 @@ library SafeMath {
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
return a - b;
}
@ -118,20 +114,26 @@ library SafeMath {
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
return a * b;
if (a == 0) return 0;
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator.
* 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:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: division by zero");
return a / b;
}
@ -148,6 +150,7 @@ library SafeMath {
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: modulo by zero");
return a % b;
}
@ -165,19 +168,16 @@ library SafeMath {
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b <= a, errorMessage);
return a - b;
}
require(b <= a, errorMessage);
return a - b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryDiv}.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
@ -188,10 +188,8 @@ library SafeMath {
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a / b;
}
require(b > 0, errorMessage);
return a / b;
}
/**
@ -210,9 +208,7 @@ library SafeMath {
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a % b;
}
require(b > 0, errorMessage);
return a % b;
}
}

View File

@ -0,0 +1,92 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**
* @title SignedSafeMath
* @dev Signed math operations with safety checks that revert on error.
*/
library SignedSafeMath {
int256 constant private _INT256_MIN = -2**255;
/**
* @dev Returns the multiplication of two signed integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot 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-contracts/pull/522
if (a == 0) {
return 0;
}
require(!(a == -1 && b == _INT256_MIN), "SignedSafeMath: multiplication overflow");
int256 c = a * b;
require(c / a == b, "SignedSafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two signed integers. Reverts on
* division by zero. The result is rounded towards zero.
*
* 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:
*
* - The divisor cannot be zero.
*/
function div(int256 a, int256 b) internal pure returns (int256) {
require(b != 0, "SignedSafeMath: division by zero");
require(!(b == -1 && a == _INT256_MIN), "SignedSafeMath: division overflow");
int256 c = a / b;
return c;
}
/**
* @dev Returns the subtraction of two signed integers, reverting on
* overflow.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(int256 a, int256 b) internal pure returns (int256) {
int256 c = a - b;
require((b >= 0 && c <= a) || (b < 0 && c > a), "SignedSafeMath: subtraction overflow");
return c;
}
/**
* @dev Returns the addition of two signed integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(int256 a, int256 b) internal pure returns (int256) {
int256 c = a + b;
require((b >= 0 && c >= a) || (b < 0 && c < a), "SignedSafeMath: addition overflow");
return c;
}
}

View File

@ -1,37 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/*
* @dev Context variant with ERC2771 support.
*/
abstract contract ERC2771Context is Context {
address immutable _trustedForwarder;
constructor(address trustedForwarder) {
_trustedForwarder = trustedForwarder;
}
function isTrustedForwarder(address forwarder) public view virtual returns(bool) {
return forwarder == _trustedForwarder;
}
function _msgSender() internal view virtual override returns (address sender) {
if (isTrustedForwarder(msg.sender)) {
// The assembly code is more direct than the Solidity version using `abi.decode`.
assembly { sender := shr(96, calldataload(sub(calldatasize(), 20))) }
} else {
return super._msgSender();
}
}
function _msgData() internal view virtual override returns (bytes calldata) {
if (isTrustedForwarder(msg.sender)) {
return msg.data[:msg.data.length-20];
} else {
return super._msgData();
}
}
}

View File

@ -1,58 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../utils/cryptography/ECDSA.sol";
import "../utils/cryptography/draft-EIP712.sol";
/*
* @dev Simple minimal forwarder to be used together with an ERC2771 compatible contract. See {ERC2771Context}.
*/
contract MinimalForwarder is EIP712 {
using ECDSA for bytes32;
struct ForwardRequest {
address from;
address to;
uint256 value;
uint256 gas;
uint256 nonce;
bytes data;
}
bytes32 private constant TYPEHASH = keccak256("ForwardRequest(address from,address to,uint256 value,uint256 gas,uint256 nonce,bytes data)");
mapping(address => uint256) private _nonces;
constructor() EIP712("MinimalForwarder", "0.0.1") {}
function getNonce(address from) public view returns (uint256) {
return _nonces[from];
}
function verify(ForwardRequest calldata req, bytes calldata signature) public view returns (bool) {
address signer = _hashTypedDataV4(keccak256(abi.encode(
TYPEHASH,
req.from,
req.to,
req.value,
req.gas,
req.nonce,
keccak256(req.data)
))).recover(signature);
return _nonces[req.from] == req.nonce && signer == req.from;
}
function execute(ForwardRequest calldata req, bytes calldata signature) public payable returns (bool, bytes memory) {
require(verify(req, signature), "MinimalForwarder: signature does not match request");
_nonces[req.from] = req.nonce + 1;
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = req.to.call{gas: req.gas, value: req.value}(abi.encodePacked(req.data, req.from));
// Validate that the relayer has sent enough gas for the call.
// See https://ronan.eth.link/blog/ethereum-gas-dangers/
assert(gasleft() > req.gas / 63);
return (success, returndata);
}
}

View File

@ -1,12 +0,0 @@
= Meta Transactions
[.readme-notice]
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/metatx
== Core
{{ERC2771Context}}
== Utils
{{MinimalForwarder}}

View File

@ -1,15 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../access/AccessControlEnumerable.sol";
contract AccessControlEnumerableMock is AccessControlEnumerable {
constructor() {
_setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
}
function setRoleAdmin(bytes32 roleId, bytes32 adminRoleId) public {
_setRoleAdmin(roleId, adminRoleId);
}
}

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../access/AccessControl.sol";

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../utils/Address.sol";

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../utils/Arrays.sol";

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity >=0.6.0 <0.8.0;
contract BadBeaconNoImpl {
}

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
contract CallReceiverMock {
string public sharedAnswer;

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
/**

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity >=0.6.0 <0.8.0;
import "../proxy/Clones.sol";
import "../utils/Address.sol";
@ -11,16 +11,16 @@ contract ClonesMock {
event NewInstance(address instance);
function clone(address implementation, bytes calldata initdata) public payable {
_initAndEmit(implementation.clone(), initdata);
function clone(address master, bytes calldata initdata) public payable {
_initAndEmit(master.clone(), initdata);
}
function cloneDeterministic(address implementation, bytes32 salt, bytes calldata initdata) public payable {
_initAndEmit(implementation.cloneDeterministic(salt), initdata);
function cloneDeterministic(address master, bytes32 salt, bytes calldata initdata) public payable {
_initAndEmit(master.cloneDeterministic(salt), initdata);
}
function predictDeterministicAddress(address implementation, bytes32 salt) public view returns (address predicted) {
return implementation.predictDeterministicAddress(salt);
function predictDeterministicAddress(address master, bytes32 salt) public view returns (address predicted) {
return master.predictDeterministicAddress(salt);
}
function _initAndEmit(address instance, bytes memory initdata) private {

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../utils/escrow/ConditionalEscrow.sol";
import "../payment/escrow/ConditionalEscrow.sol";
// mock class using ConditionalEscrow
contract ConditionalEscrowMock is ConditionalEscrow {

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../utils/Context.sol";

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../utils/Counters.sol";

View File

@ -1,9 +1,9 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../utils/Create2.sol";
import "../utils/introspection/ERC1820Implementer.sol";
import "../introspection/ERC1820Implementer.sol";
contract Create2Impl {
function deploy(uint256 value, bytes32 salt, bytes memory code) public {

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
abstract contract Impl {
function version() public pure virtual returns (string memory);

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../utils/cryptography/ECDSA.sol";
import "../cryptography/ECDSA.sol";
contract ECDSAMock {
using ECDSA for bytes32;

View File

@ -1,9 +1,9 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity >=0.6.0 <0.8.0;
import "../utils/cryptography/draft-EIP712.sol";
import "../utils/cryptography/ECDSA.sol";
import "../drafts/EIP712.sol";
import "../cryptography/ECDSA.sol";
contract EIP712External is EIP712 {
constructor(string memory name, string memory version) EIP712(name, version) {}
@ -22,7 +22,11 @@ contract EIP712External is EIP712 {
require(recoveredSigner == signer);
}
function getChainId() external view returns (uint256) {
return block.chainid;
function getChainId() external view returns (uint256 chainId) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
// solhint-disable-next-line no-inline-assembly
assembly {
chainId := chainid()
}
}
}

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../token/ERC1155/extensions/ERC1155Burnable.sol";
import "../token/ERC1155/ERC1155Burnable.sol";
contract ERC1155BurnableMock is ERC1155Burnable {
constructor(string memory uri) ERC1155(uri) { }

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../token/ERC1155/ERC1155.sol";

View File

@ -1,9 +1,9 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "./ERC1155Mock.sol";
import "../token/ERC1155/extensions/ERC1155Pausable.sol";
import "../token/ERC1155/ERC1155Pausable.sol";
contract ERC1155PausableMock is ERC1155Mock, ERC1155Pausable {
constructor(string memory uri) ERC1155Mock(uri) { }

View File

@ -1,11 +1,11 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../token/ERC1155/IERC1155Receiver.sol";
import "../utils/introspection/ERC165.sol";
import "./ERC165Mock.sol";
contract ERC1155ReceiverMock is IERC1155Receiver, ERC165 {
contract ERC1155ReceiverMock is IERC1155Receiver, ERC165Mock {
bytes4 private _recRetval;
bool private _recReverts;
bytes4 private _batRetval;

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../../utils/introspection/IERC165.sol";
import "../../introspection/IERC165.sol";
/**
* https://eips.ethereum.org/EIPS/eip-214#specification

View File

@ -1,7 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract ERC165MissingData {
function supportsInterface(bytes4 interfaceId) public view {} // missing return
}

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
contract ERC165NotSupported { }

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../utils/introspection/ERC165Checker.sol";
import "../introspection/ERC165Checker.sol";
contract ERC165CheckerMock {
using ERC165Checker for address;

View File

@ -1,8 +1,11 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../utils/introspection/ERC165.sol";
import "../introspection/ERC165.sol";
contract ERC165Mock is ERC165 {
function registerInterface(bytes4 interfaceId) public {
_registerInterface(interfaceId);
}
}

View File

@ -1,11 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../utils/introspection/ERC165Storage.sol";
contract ERC165StorageMock is ERC165Storage {
function registerInterface(bytes4 interfaceId) public {
_registerInterface(interfaceId);
}
}

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../utils/introspection/ERC1820Implementer.sol";
import "../introspection/ERC1820Implementer.sol";
contract ERC1820ImplementerMock is ERC1820Implementer {
function registerInterfaceForAddress(bytes32 interfaceHash, address account) public {

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../token/ERC20/extensions/ERC20Burnable.sol";
import "../token/ERC20/ERC20Burnable.sol";
contract ERC20BurnableMock is ERC20Burnable {
constructor (

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../token/ERC20/extensions/ERC20Capped.sol";
import "../token/ERC20/ERC20Capped.sol";
contract ERC20CappedMock is ERC20Capped {
constructor (string memory name, string memory symbol, uint256 cap)

View File

@ -1,17 +1,11 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../token/ERC20/ERC20.sol";
contract ERC20DecimalsMock is ERC20 {
uint8 immutable private _decimals;
constructor (string memory name_, string memory symbol_, uint8 decimals_) ERC20(name_, symbol_) {
_decimals = decimals_;
}
function decimals() public view virtual override returns (uint8) {
return _decimals;
constructor (string memory name, string memory symbol, uint8 decimals) ERC20(name, symbol) {
_setupDecimals(decimals);
}
}

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../token/ERC20/ERC20.sol";

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../token/ERC20/extensions/ERC20Pausable.sol";
import "../token/ERC20/ERC20Pausable.sol";
// mock class using ERC20Pausable
contract ERC20PausableMock is ERC20Pausable {

View File

@ -1,9 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity >=0.6.0 <0.8.0;
import "../token/ERC20/extensions/draft-ERC20Permit.sol";
import "../drafts/ERC20Permit.sol";
contract ERC20PermitMock is ERC20Permit {
constructor (
@ -15,7 +14,11 @@ contract ERC20PermitMock is ERC20Permit {
_mint(initialAccount, initialBalance);
}
function getChainId() external view returns (uint256) {
return block.chainid;
function getChainId() external view returns (uint256 chainId) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
// solhint-disable-next-line no-inline-assembly
assembly {
chainId := chainid()
}
}
}

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../token/ERC20/extensions/ERC20Snapshot.sol";
import "../token/ERC20/ERC20Snapshot.sol";
contract ERC20SnapshotMock is ERC20Snapshot {

View File

@ -1,19 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./ContextMock.sol";
import "../metatx/ERC2771Context.sol";
// By inheriting from ERC2771Context, Context's internal functions are overridden automatically
contract ERC2771ContextMock is ContextMock, ERC2771Context {
constructor(address trustedForwarder) ERC2771Context(trustedForwarder) {}
function _msgSender() internal override(Context, ERC2771Context) view virtual returns (address) {
return ERC2771Context._msgSender();
}
function _msgData() internal override(Context, ERC2771Context) view virtual returns (bytes calldata) {
return ERC2771Context._msgData();
}
}

View File

@ -1,25 +1,13 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../token/ERC721/extensions/ERC721Burnable.sol";
import "../token/ERC721/ERC721Burnable.sol";
contract ERC721BurnableMock is ERC721Burnable {
constructor(string memory name, string memory symbol) ERC721(name, symbol) { }
function exists(uint256 tokenId) public view returns (bool) {
return _exists(tokenId);
}
function mint(address to, uint256 tokenId) public {
_mint(to, tokenId);
}
function safeMint(address to, uint256 tokenId) public {
_safeMint(to, tokenId);
}
function safeMint(address to, uint256 tokenId, bytes memory _data) public {
_safeMint(to, tokenId, _data);
}
}

View File

@ -1,47 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../token/ERC721/extensions/ERC721Enumerable.sol";
/**
* @title ERC721Mock
* This mock just provides a public safeMint, mint, and burn functions for testing purposes
*/
contract ERC721EnumerableMock is ERC721Enumerable {
string private _baseTokenURI;
constructor (string memory name, string memory symbol) ERC721(name, symbol) { }
function _baseURI() internal view virtual override returns (string memory) {
return _baseTokenURI;
}
function setBaseURI(string calldata newBaseTokenURI) public {
_baseTokenURI = newBaseTokenURI;
}
function baseURI() public view returns (string memory) {
return _baseURI();
}
function exists(uint256 tokenId) public view returns (bool) {
return _exists(tokenId);
}
function mint(address to, uint256 tokenId) public {
_mint(to, tokenId);
}
function safeMint(address to, uint256 tokenId) public {
_safeMint(to, tokenId);
}
function safeMint(address to, uint256 tokenId, bytes memory _data) public {
_safeMint(to, tokenId, _data);
}
function burn(uint256 tokenId) public {
_burn(tokenId);
}
}

View File

@ -0,0 +1,30 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "../token/ERC721/ERC721.sol";
import "../GSN/GSNRecipient.sol";
import "../GSN/GSNRecipientSignature.sol";
/**
* @title ERC721GSNRecipientMock
* A simple ERC721 mock that has GSN support enabled
*/
contract ERC721GSNRecipientMock is ERC721, GSNRecipient, GSNRecipientSignature {
constructor(string memory name, string memory symbol, address trustedSigner)
ERC721(name, symbol)
GSNRecipientSignature(trustedSigner)
{ }
function mint(uint256 tokenId) public {
_mint(_msgSender(), tokenId);
}
function _msgSender() internal view override(Context, GSNRecipient) returns (address payable) {
return GSNRecipient._msgSender();
}
function _msgData() internal view override(Context, GSNRecipient) returns (bytes memory) {
return GSNRecipient._msgData();
}
}

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../token/ERC721/ERC721.sol";
@ -9,26 +9,20 @@ import "../token/ERC721/ERC721.sol";
* This mock just provides a public safeMint, mint, and burn functions for testing purposes
*/
contract ERC721Mock is ERC721 {
string private _baseTokenURI;
constructor (string memory name, string memory symbol) ERC721(name, symbol) { }
function _baseURI() internal view virtual override returns (string memory) {
return _baseTokenURI;
}
function setBaseURI(string calldata newBaseTokenURI) public {
_baseTokenURI = newBaseTokenURI;
}
function baseURI() public view returns (string memory) {
return _baseURI();
}
function exists(uint256 tokenId) public view returns (bool) {
return _exists(tokenId);
}
function setTokenURI(uint256 tokenId, string memory uri) public {
_setTokenURI(tokenId, uri);
}
function setBaseURI(string memory baseURI) public {
_setBaseURI(baseURI);
}
function mint(address to, uint256 tokenId) public {
_mint(to, tokenId);
}

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../token/ERC721/extensions/ERC721Pausable.sol";
import "../token/ERC721/ERC721Pausable.sol";
/**
* @title ERC721PausableMock
@ -11,6 +11,18 @@ import "../token/ERC721/extensions/ERC721Pausable.sol";
contract ERC721PausableMock is ERC721Pausable {
constructor (string memory name, string memory symbol) ERC721(name, symbol) { }
function mint(address to, uint256 tokenId) public {
super._mint(to, tokenId);
}
function burn(uint256 tokenId) public {
super._burn(tokenId);
}
function exists(uint256 tokenId) public view returns (bool) {
return super._exists(tokenId);
}
function pause() external {
_pause();
}
@ -18,24 +30,4 @@ contract ERC721PausableMock is ERC721Pausable {
function unpause() external {
_unpause();
}
function exists(uint256 tokenId) public view returns (bool) {
return _exists(tokenId);
}
function mint(address to, uint256 tokenId) public {
_mint(to, tokenId);
}
function safeMint(address to, uint256 tokenId) public {
_safeMint(to, tokenId);
}
function safeMint(address to, uint256 tokenId, bytes memory _data) public {
_safeMint(to, tokenId, _data);
}
function burn(uint256 tokenId) public {
_burn(tokenId);
}
}

View File

@ -1,38 +1,24 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../token/ERC721/IERC721Receiver.sol";
contract ERC721ReceiverMock is IERC721Receiver {
enum Error {
None,
RevertWithMessage,
RevertWithoutMessage,
Panic
}
bytes4 private immutable _retval;
Error private immutable _error;
bytes4 private _retval;
bool private _reverts;
event Received(address operator, address from, uint256 tokenId, bytes data, uint256 gas);
constructor (bytes4 retval, Error error) {
constructor (bytes4 retval, bool reverts) {
_retval = retval;
_error = error;
_reverts = reverts;
}
function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data)
public override returns (bytes4)
{
if (_error == Error.RevertWithMessage) {
revert("ERC721ReceiverMock: reverting");
} else if (_error == Error.RevertWithoutMessage) {
revert();
} else if (_error == Error.Panic) {
uint256 a = uint256(0) / uint256(0);
a;
}
require(!_reverts, "ERC721ReceiverMock: reverting");
emit Received(operator, from, tokenId, data, gasleft());
return _retval;
}

View File

@ -1,51 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../token/ERC721/extensions/ERC721URIStorage.sol";
/**
* @title ERC721Mock
* This mock just provides a public safeMint, mint, and burn functions for testing purposes
*/
contract ERC721URIStorageMock is ERC721URIStorage {
string private _baseTokenURI;
constructor (string memory name, string memory symbol) ERC721(name, symbol) { }
function _baseURI() internal view virtual override returns (string memory) {
return _baseTokenURI;
}
function setBaseURI(string calldata newBaseTokenURI) public {
_baseTokenURI = newBaseTokenURI;
}
function baseURI() public view returns (string memory) {
return _baseURI();
}
function setTokenURI(uint256 tokenId, string memory _tokenURI) public {
_setTokenURI(tokenId, _tokenURI);
}
function exists(uint256 tokenId) public view returns (bool) {
return _exists(tokenId);
}
function mint(address to, uint256 tokenId) public {
_mint(to, tokenId);
}
function safeMint(address to, uint256 tokenId) public {
_safeMint(to, tokenId);
}
function safeMint(address to, uint256 tokenId, bytes memory _data) public {
_safeMint(to, tokenId, _data);
}
function burn(uint256 tokenId) public {
_burn(tokenId);
}
}

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../utils/Context.sol";
import "../token/ERC777/ERC777.sol";

View File

@ -1,13 +1,13 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../utils/Context.sol";
import "../token/ERC777/IERC777.sol";
import "../token/ERC777/IERC777Sender.sol";
import "../token/ERC777/IERC777Recipient.sol";
import "../utils/Context.sol";
import "../utils/introspection/IERC1820Registry.sol";
import "../utils/introspection/ERC1820Implementer.sol";
import "../introspection/IERC1820Registry.sol";
import "../introspection/ERC1820Implementer.sol";
contract ERC777SenderRecipientMock is Context, IERC777Sender, IERC777Recipient, ERC1820Implementer {
event TokensToSendCalled(
@ -150,3 +150,4 @@ contract ERC777SenderRecipientMock is Context, IERC777Sender, IERC777Recipient,
token.burn(amount, data);
}
}

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../utils/structs/EnumerableMap.sol";
import "../utils/EnumerableMap.sol";
contract EnumerableMapMock {
using EnumerableMap for EnumerableMap.UintToAddressMap;

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../utils/structs/EnumerableSet.sol";
import "../utils/EnumerableSet.sol";
// Bytes32Set
contract EnumerableBytes32SetMock {

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
contract EtherReceiverMock {
bool private _acceptEther;

View File

@ -0,0 +1,20 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "../GSN/GSNRecipient.sol";
import "../GSN/GSNRecipientERC20Fee.sol";
contract GSNRecipientERC20FeeMock is GSNRecipient, GSNRecipientERC20Fee {
constructor(string memory name, string memory symbol) GSNRecipientERC20Fee(name, symbol) { }
function mint(address account, uint256 amount) public {
_mint(account, amount);
}
event MockFunctionCalled(uint256 senderBalance);
function mockFunction() public {
emit MockFunctionCalled(token().balanceOf(_msgSender()));
}
}

View File

@ -0,0 +1,38 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "./ContextMock.sol";
import "../GSN/GSNRecipient.sol";
// By inheriting from GSNRecipient, Context's internal functions are overridden automatically
contract GSNRecipientMock is ContextMock, GSNRecipient {
function withdrawDeposits(uint256 amount, address payable payee) public {
_withdrawDeposits(amount, payee);
}
function acceptRelayedCall(address, address, bytes calldata, uint256, uint256, uint256, uint256, bytes calldata, uint256)
external
pure
override
returns (uint256, bytes memory)
{
return (0, "");
}
function _preRelayedCall(bytes memory) internal override returns (bytes32) { }
function _postRelayedCall(bytes memory, bool, uint256, bytes32) internal override { }
function upgradeRelayHub(address newRelayHub) public {
return _upgradeRelayHub(newRelayHub);
}
function _msgSender() internal override(Context, GSNRecipient) view virtual returns (address payable) {
return GSNRecipient._msgSender();
}
function _msgData() internal override(Context, GSNRecipient) view virtual returns (bytes memory) {
return GSNRecipient._msgData();
}
}

View File

@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "../GSN/GSNRecipient.sol";
import "../GSN/GSNRecipientSignature.sol";
contract GSNRecipientSignatureMock is GSNRecipient, GSNRecipientSignature {
constructor(address trustedSigner) GSNRecipientSignature(trustedSigner) { }
event MockFunctionCalled();
function mockFunction() public {
emit MockFunctionCalled();
}
}

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../proxy/utils/Initializable.sol";
import "../proxy/Initializable.sol";
/**
* @title InitializableMock

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../utils/math/Math.sol";
import "../math/Math.sol";
contract MathMock {
function max(uint256 a, uint256 b) public pure returns (uint256) {

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../utils/cryptography/MerkleProof.sol";
import { MerkleProof } from "../cryptography/MerkleProof.sol";
contract MerkleProofWrapper {
function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) public pure returns (bool) {

View File

@ -1,12 +1,12 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../proxy/utils/Initializable.sol";
import "../proxy/Initializable.sol";
// Sample contracts showing upgradeability with multiple inheritance.
// Child contract inherits from Father and Mother contracts, and Father extends from Gramps.
//
//
// Human
// / \
// | Gramps

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../access/Ownable.sol";

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../security/Pausable.sol";
import "../utils/Pausable.sol";
contract PausableMock is Pausable {
bool public drasticMeasureTaken;

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../security/PullPayment.sol";
import "../payment/PullPayment.sol";
// mock class using PullPayment
contract PullPaymentMock is PullPayment {

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../utils/Context.sol";
contract ReentrancyAttack is Context {

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../security/ReentrancyGuard.sol";
import "../utils/ReentrancyGuard.sol";
import "./ReentrancyAttack.sol";
contract ReentrancyMock is ReentrancyGuard {

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.7.0;
import "../proxy/utils/Initializable.sol";
import "../proxy/Initializable.sol";
contract Implementation1 is Initializable {
uint internal _value;

Some files were not shown because too many files have changed in this diff Show More