Compare commits
155 Commits
v3.3.0-rc.
...
v4.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
| 954f6110d6 | |||
| 4390b8df12 | |||
| cb88e15b33 | |||
| 136de91049 | |||
| e2bf45f262 | |||
| 93d990c653 | |||
| 3dfd02b4b4 | |||
| 7a7bd8f6d7 | |||
| 16312fcfb9 | |||
| a81a88cca0 | |||
| 5acedf5027 | |||
| 566c601d41 | |||
| 15214a53ce | |||
| d5f4862405 | |||
| 4a1985f870 | |||
| ac8279a0a5 | |||
| 7cab19a2e4 | |||
| 556cdf5f1a | |||
| c760fe9a2e | |||
| 24a0bc23cf | |||
| c3178ff942 | |||
| f8cc8b844a | |||
| e341bdc1b7 | |||
| 09734e8028 | |||
| 7d20d0e2d2 | |||
| 0059b17dfc | |||
| e733b24dfe | |||
| f7c8252611 | |||
| e66e3ca523 | |||
| 24660c3e48 | |||
| ee6348a7a0 | |||
| a44303c373 | |||
| f49e9ee41b | |||
| 1ba03b164a | |||
| 9c1e703990 | |||
| f2112be4d8 | |||
| c82895fb65 | |||
| b840341a77 | |||
| ed7623273a | |||
| 9425a7e0ab | |||
| 93438eca0b | |||
| e28615628b | |||
| fa64a1ced0 | |||
| 0f553e7f9e | |||
| f4e57fd529 | |||
| a0e2bca79a | |||
| 63a0343dda | |||
| 5db7413827 | |||
| d163aeb80d | |||
| 60205944bb | |||
| 03832c130c | |||
| 9f93e25b88 | |||
| afaebc3869 | |||
| fdf57a9788 | |||
| 5609cd4c74 | |||
| a0323d446c | |||
| 0db76e98f9 | |||
| fa33fbce75 | |||
| bcc7192af7 | |||
| 0d27b7a7ff | |||
| 6d202894b6 | |||
| ff300b10e1 | |||
| 18c7efe800 | |||
| 0931062a3f | |||
| 3b4c951838 | |||
| c2c08af16d | |||
| 9e49be41b6 | |||
| dd86c97e18 | |||
| 5a8e6bda51 | |||
| c34211417c | |||
| 974c534210 | |||
| 5a58fd2de0 | |||
| faec973e09 | |||
| 65b7e515a2 | |||
| 318c4b44ea | |||
| b6e5187973 | |||
| 1e8cb4b4a4 | |||
| 9daa0d4d2f | |||
| ceb7324657 | |||
| da00d28cb7 | |||
| c23d5e0143 | |||
| d8658dbc47 | |||
| a6a4c042f5 | |||
| 6be0b410dc | |||
| 051d340171 | |||
| 0a4233f0f6 | |||
| ecc66719bd | |||
| 03d51c5677 | |||
| 268c6ab36c | |||
| 0786f31f22 | |||
| 883116e4af | |||
| 5748034cd3 | |||
| 061e7f0da7 | |||
| a138dc3970 | |||
| fa2b204535 | |||
| 73c7af102b | |||
| 18a8ae5a8a | |||
| fa65bf89be | |||
| 60c8b0e02f | |||
| acac4a7fca | |||
| 6be5ffe54f | |||
| ba843f0ad9 | |||
| 4297be6ac1 | |||
| 7d02933da3 | |||
| d2003a6fff | |||
| ef0483b4be | |||
| 9e51b2e5df | |||
| 951e946e71 | |||
| 1fccf6fa53 | |||
| 7f8fc584de | |||
| 1d1d2ba661 | |||
| 520bf7ac61 | |||
| 85f50d3e06 | |||
| e12cb97e16 | |||
| a3a7e6fa34 | |||
| 3881175d72 | |||
| ef32c04795 | |||
| 42da4d6867 | |||
| f7bb84ce4c | |||
| 5bd1c0d063 | |||
| c67d81bae1 | |||
| a5d1ac7ed0 | |||
| b8187aa529 | |||
| 877f440331 | |||
| 58892471a3 | |||
| 90ed1af972 | |||
| 21344b91ed | |||
| 3f9673c177 | |||
| fce2513827 | |||
| 3debb8820e | |||
| d3a4e31fe2 | |||
| 3f2a2b5f62 | |||
| 4972bf4f23 | |||
| a1408a3411 | |||
| b6b1c0130b | |||
| ea305cf32e | |||
| d41102d6c3 | |||
| 0f55c18595 | |||
| 7650210ad6 | |||
| ec8efd52b4 | |||
| 9a83ced46e | |||
| 0d7bf01ac1 | |||
| f7ca35c9c6 | |||
| c08d1439dd | |||
| 870ea2a88a | |||
| 29f4a38c0d | |||
| 0ce14a078a | |||
| 628dea7a08 | |||
| 22de765f3c | |||
| c187517395 | |||
| 89e2b7424b | |||
| 48072e439d | |||
| 2acb1abb1f | |||
| 4eb8d2bb10 | |||
| 04fc35707d |
10
.codecov.yml
10
.codecov.yml
@ -1,3 +1,11 @@
|
||||
comment: off
|
||||
github_checks:
|
||||
annotations: false
|
||||
coverage:
|
||||
range: "100...100"
|
||||
status:
|
||||
patch:
|
||||
default:
|
||||
target: 95%
|
||||
project:
|
||||
default:
|
||||
threshold: 1%
|
||||
|
||||
32
.github/PULL_REQUEST_TEMPLATE.md
vendored
32
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -1,22 +1,20 @@
|
||||
<!-- 0. 🎉 Thank you for submitting a PR! -->
|
||||
<!-- Thank you for your interest in contributing to OpenZeppelin! -->
|
||||
|
||||
<!-- 1. Does this close any open issues? Please list them below. -->
|
||||
<!-- Consider opening an issue for discussion prior to submitting a PR. -->
|
||||
<!-- New features will be merged faster if they were first discussed and designed with the team. -->
|
||||
|
||||
<!-- Keep in mind that new features have a better chance of being merged fast if
|
||||
they were first discussed and designed with the maintainers. If there is no
|
||||
corresponding issue, please consider opening one for discussion first! -->
|
||||
Fixes #???? <!-- Fill in with issue number -->
|
||||
|
||||
Fixes #
|
||||
<!-- Describe the changes introduced in this pull request. -->
|
||||
<!-- Include any context necessary for understanding the PR's purpose. -->
|
||||
|
||||
<!-- 2. Describe the changes introduced in this pull request. -->
|
||||
<!-- Include any context necessary for understanding the PR's purpose. -->
|
||||
|
||||
<!-- 3. Before submitting, please make sure that you have:
|
||||
- reviewed the OpenZeppelin Contributor Guidelines
|
||||
(https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/CONTRIBUTING.md),
|
||||
- added tests where applicable to test new functionality,
|
||||
- made sure that your contracts are well-documented,
|
||||
- run the Solidity linter (`npm run lint:sol`) and fixed any issues,
|
||||
- run the JS linter and fixed any issues (`npm run lint:fix`), and
|
||||
- updated the changelog, if applicable.
|
||||
-->
|
||||
#### PR Checklist
|
||||
|
||||
<!-- Before merging the pull request all of the following must be complete. -->
|
||||
<!-- Feel free to submit a PR or Draft PR even if some items are pending. -->
|
||||
<!-- Some of the items may not apply. -->
|
||||
|
||||
- [ ] Tests
|
||||
- [ ] Documentation
|
||||
- [ ] Changelog entry
|
||||
|
||||
67
.github/stale.yml
vendored
67
.github/stale.yml
vendored
@ -1,67 +0,0 @@
|
||||
# Configuration for probot-stale - https://github.com/probot/stale
|
||||
|
||||
# Number of days of inactivity before an Issue or Pull Request becomes stale
|
||||
daysUntilStale: 15
|
||||
|
||||
# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
|
||||
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
|
||||
daysUntilClose: 15
|
||||
|
||||
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
|
||||
exemptLabels:
|
||||
- on hold
|
||||
- meta
|
||||
|
||||
# Set to true to ignore issues in a project (defaults to false)
|
||||
exemptProjects: false
|
||||
|
||||
# Set to true to ignore issues in a milestone (defaults to false)
|
||||
exemptMilestones: false
|
||||
|
||||
# Set to true to ignore issues with an assignee (defaults to false)
|
||||
exemptAssignees: false
|
||||
|
||||
# Label to use when marking as stale
|
||||
staleLabel: stale
|
||||
|
||||
# Comment to post when marking as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
Hi all!
|
||||
|
||||
This Pull Request has not had any recent activity, is it still relevant? If so, what is blocking it?
|
||||
Is there anything we can do to help move it forward?
|
||||
|
||||
Thanks!
|
||||
|
||||
|
||||
# Comment to post when removing the stale label.
|
||||
# unmarkComment: >
|
||||
# Your comment here.
|
||||
|
||||
# Comment to post when closing a stale Issue or Pull Request.
|
||||
closeComment: >
|
||||
Hi folks!
|
||||
|
||||
This Pull Request is being closed as there was no response to the previous prompt.
|
||||
However, please leave a comment whenever you're ready to resume, so it can be reopened.
|
||||
|
||||
Thanks again!
|
||||
|
||||
|
||||
# Limit the number of actions per hour, from 1-30. Default is 30
|
||||
limitPerRun: 30
|
||||
|
||||
# Limit to only `issues` or `pulls`
|
||||
only: pulls
|
||||
|
||||
# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
|
||||
# pulls:
|
||||
# daysUntilStale: 30
|
||||
# markComment: >
|
||||
# This pull request has been automatically marked as stale because it has not had
|
||||
# recent activity. It will be closed if no further activity occurs. Thank you
|
||||
# for your contributions.
|
||||
|
||||
# issues:
|
||||
# exemptLabels:
|
||||
# - confirmed
|
||||
14
.github/workflows/test.yml
vendored
14
.github/workflows/test.yml
vendored
@ -6,13 +6,14 @@ on:
|
||||
- master
|
||||
- release-v*
|
||||
pull_request: {}
|
||||
workflow_dispatch: {}
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v1
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 10.x
|
||||
- uses: actions/cache@v2
|
||||
@ -25,12 +26,19 @@ 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
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
fetch-depth: 2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 10.x
|
||||
- uses: actions/cache@v2
|
||||
@ -42,4 +50,6 @@ 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
2
.gitignore
vendored
@ -54,6 +54,6 @@ allFiredEvents
|
||||
.coverage_cache
|
||||
.coverage_contracts
|
||||
|
||||
# buidler
|
||||
# hardhat
|
||||
cache
|
||||
artifacts
|
||||
|
||||
@ -8,4 +8,8 @@ module.exports = {
|
||||
providerOptions: {
|
||||
default_balance_ether: '10000000000000000000000000',
|
||||
},
|
||||
mocha: {
|
||||
fgrep: '[skip-on-coverage]',
|
||||
invert: true,
|
||||
},
|
||||
}
|
||||
|
||||
@ -4,8 +4,9 @@
|
||||
"func-order": "off",
|
||||
"mark-callable-contracts": "off",
|
||||
"no-empty-blocks": "off",
|
||||
"compiler-version": ["error", "^0.6.0"],
|
||||
"compiler-version": "off",
|
||||
"private-vars-leading-underscore": "error",
|
||||
"reason-string": "off"
|
||||
"reason-string": "off",
|
||||
"func-visibility": ["error", { "ignoreConstructors": true }]
|
||||
}
|
||||
}
|
||||
|
||||
65
CHANGELOG.md
65
CHANGELOG.md
@ -1,11 +1,70 @@
|
||||
# Changelog
|
||||
|
||||
## 3.3.0 (2020-11-17)
|
||||
## 4.0.0
|
||||
|
||||
* `Address`: added `functionStaticCall` and `functionDelegateCall`, similar to the existing `functionCall`. ([#2333](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2333))
|
||||
* `TimelockController`: added a contract to augment access control schemes with a delay. ([#2364](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2364))
|
||||
* 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 upcomming 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 behaviour 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 reorganisation of the contract folder to improve clarity and discoverability. ([#2503](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2503))
|
||||
* `ERC20Capped`: optimize gas usage of by enforcing te 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))
|
||||
* `ERC721TokenUri`: Add a new extension ERC721TokenUri that implements the tokenURI behavior as it was available in 3.4.0. ([#2555](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2555))
|
||||
|
||||
### 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.
|
||||
|
||||
## 3.4.0 (2021-02-02)
|
||||
|
||||
* `BeaconProxy`: added new kind of proxy that allows simultaneous atomic upgrades. ([#2411](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2411))
|
||||
* `EIP712`: added helpers to verify EIP712 typed data signatures on chain. ([#2418](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2418))
|
||||
* `ERC20Permit`: added an implementation of the ERC20 permit extension for gasless token approvals. ([#2237](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2237))
|
||||
* Presets: added token presets with preminted fixed supply `ERC20PresetFixedSupply` and `ERC777PresetFixedSupply`. ([#2399](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2399))
|
||||
* `Address`: added `functionDelegateCall`, similar to the existing `functionCall`. ([#2333](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2333))
|
||||
* `Clones`: added a library for deploying EIP 1167 minimal proxies. ([#2449](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2449))
|
||||
* `Context`: moved from `contracts/GSN` to `contracts/utils`. ([#2453](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2453))
|
||||
* `PaymentSplitter`: replace usage of `.transfer()` with `Address.sendValue` for improved compatibility with smart wallets. ([#2455](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2455))
|
||||
* `UpgradeableProxy`: bubble revert reasons from initialization calls. ([#2454](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2454))
|
||||
* `SafeMath`: fix a memory allocation issue by adding new `SafeMath.tryOp(uint,uint)→(bool,uint)` functions. `SafeMath.op(uint,uint,string)→uint` are now deprecated. ([#2462](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2462))
|
||||
* `EnumerableMap`: fix a memory allocation issue by adding new `EnumerableMap.tryGet(uint)→(bool,address)` functions. `EnumerableMap.get(uint)→string` is now deprecated. ([#2462](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2462))
|
||||
* `ERC165Checker`: added batch `getSupportedInterfaces`. ([#2469](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2469))
|
||||
* `RefundEscrow`: `beneficiaryWithdraw` will forward all available gas to the beneficiary. ([#2480](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2480))
|
||||
* Many view and pure functions have been made virtual to customize them via overrides. In many cases this will not imply that other functions in the contract will automatically adapt to the overridden definitions. People who wish to override should consult the source code to understand the impact and if they need to override any additional functions to achieve the desired behavior.
|
||||
|
||||
### Security Fixes
|
||||
|
||||
* `ERC777`: fix potential reentrancy issues for custom extensions to `ERC777`. ([#2483](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2483))
|
||||
|
||||
If you're using our implementation of ERC777 from version 3.3.0 or earlier, and you define a custom `_beforeTokenTransfer` function that writes to a storage variable, you may be vulnerable to a reentrancy attack. If you're affected and would like assistance please write to security@openzeppelin.com. [Read more in the pull request.](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2483)
|
||||
|
||||
## 3.3.0 (2020-11-26)
|
||||
|
||||
* Now supports both Solidity 0.6 and 0.7. Compiling with solc 0.7 will result in warnings. Install the `solc-0.7` tag to compile without warnings.
|
||||
* `Address`: added `functionStaticCall`, similar to the existing `functionCall`. ([#2333](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2333))
|
||||
* `TimelockController`: added a contract to augment access control schemes with a delay. ([#2354](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2354))
|
||||
* `EnumerableSet`: added `Bytes32Set`, for sets of `bytes32`. ([#2395](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2395))
|
||||
|
||||
## 3.2.2-solc-0.7 (2020-10-28)
|
||||
* Resolve warnings introduced by Solidity 0.7.4. ([#2396](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2396))
|
||||
|
||||
## 3.2.1-solc-0.7 (2020-09-15)
|
||||
* `ERC777`: Remove a warning about function state visibility in Solidity 0.7. ([#2327](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2327))
|
||||
|
||||
## 3.2.0 (2020-09-10)
|
||||
|
||||
### New features
|
||||
|
||||
@ -27,12 +27,12 @@ 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.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
|
||||
|
||||
contract MyCollectible is ERC721 {
|
||||
constructor() ERC721("MyCollectible", "MCO") public {
|
||||
constructor() ERC721("MyCollectible", "MCO") {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -1,20 +0,0 @@
|
||||
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.6.12',
|
||||
},
|
||||
};
|
||||
@ -1,230 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "./IRelayRecipient.sol";
|
||||
import "./IRelayHub.sol";
|
||||
import "./Context.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 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 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(_relayHub).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 != _relayHub) {
|
||||
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 != _relayHub) {
|
||||
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 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 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 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 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;
|
||||
}
|
||||
}
|
||||
@ -1,152 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.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) public {
|
||||
_token = new __unstable__ERC20Owned(name, symbol);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the gas payment token.
|
||||
*/
|
||||
function token() public view returns (IERC20) {
|
||||
return IERC20(_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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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) public ERC20(name, symbol) { }
|
||||
|
||||
// The owner (GSNRecipientERC20Fee) can mint tokens
|
||||
function mint(address account, uint256 amount) public onlyOwner {
|
||||
_mint(account, amount);
|
||||
}
|
||||
|
||||
// The owner has 'infinite' allowance for all token holders
|
||||
function allowance(address tokenOwner, address spender) public view 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 override {
|
||||
if (spender == owner()) {
|
||||
return;
|
||||
} else {
|
||||
super._approve(tokenOwner, spender, value);
|
||||
}
|
||||
}
|
||||
|
||||
function transferFrom(address sender, address recipient, uint256 amount) public override returns (bool) {
|
||||
if (recipient == owner()) {
|
||||
_transfer(sender, recipient, amount);
|
||||
return true;
|
||||
} else {
|
||||
return super.transferFrom(sender, recipient, amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,72 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.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) public {
|
||||
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 { }
|
||||
}
|
||||
@ -1,269 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.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);
|
||||
}
|
||||
|
||||
@ -1,76 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.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;
|
||||
}
|
||||
@ -1,31 +0,0 @@
|
||||
= 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}}
|
||||
@ -1,14 +1,15 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../utils/EnumerableSet.sol";
|
||||
import "../utils/Address.sol";
|
||||
import "../GSN/Context.sol";
|
||||
import "../utils/Context.sol";
|
||||
|
||||
/**
|
||||
* @dev Contract module that allows children to implement role-based access
|
||||
* control mechanisms.
|
||||
* 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}.
|
||||
*
|
||||
* 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
|
||||
@ -42,11 +43,8 @@ import "../GSN/Context.sol";
|
||||
* accounts that have been granted it.
|
||||
*/
|
||||
abstract contract AccessControl is Context {
|
||||
using EnumerableSet for EnumerableSet.AddressSet;
|
||||
using Address for address;
|
||||
|
||||
struct RoleData {
|
||||
EnumerableSet.AddressSet members;
|
||||
mapping (address => bool) members;
|
||||
bytes32 adminRole;
|
||||
}
|
||||
|
||||
@ -85,31 +83,7 @@ abstract contract AccessControl is Context {
|
||||
* @dev Returns `true` if `account` has been granted `role`.
|
||||
*/
|
||||
function hasRole(bytes32 role, address account) public view returns (bool) {
|
||||
return _roles[role].members.contains(account);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 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);
|
||||
return _roles[role].members[account];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -133,7 +107,7 @@ abstract contract AccessControl is Context {
|
||||
* - the caller must have ``role``'s admin role.
|
||||
*/
|
||||
function grantRole(bytes32 role, address account) public virtual {
|
||||
require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to grant");
|
||||
require(hasRole(getRoleAdmin(role), _msgSender()), "AccessControl: sender must be an admin to grant");
|
||||
|
||||
_grantRole(role, account);
|
||||
}
|
||||
@ -148,7 +122,7 @@ abstract contract AccessControl is Context {
|
||||
* - the caller must have ``role``'s admin role.
|
||||
*/
|
||||
function revokeRole(bytes32 role, address account) public virtual {
|
||||
require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to revoke");
|
||||
require(hasRole(getRoleAdmin(role), _msgSender()), "AccessControl: sender must be an admin to revoke");
|
||||
|
||||
_revokeRole(role, account);
|
||||
}
|
||||
@ -199,18 +173,20 @@ abstract contract AccessControl is Context {
|
||||
* Emits a {RoleAdminChanged} event.
|
||||
*/
|
||||
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
|
||||
emit RoleAdminChanged(role, _roles[role].adminRole, adminRole);
|
||||
emit RoleAdminChanged(role, getRoleAdmin(role), adminRole);
|
||||
_roles[role].adminRole = adminRole;
|
||||
}
|
||||
|
||||
function _grantRole(bytes32 role, address account) private {
|
||||
if (_roles[role].members.add(account)) {
|
||||
if (!hasRole(role, account)) {
|
||||
_roles[role].members[account] = true;
|
||||
emit RoleGranted(role, account, _msgSender());
|
||||
}
|
||||
}
|
||||
|
||||
function _revokeRole(bytes32 role, address account) private {
|
||||
if (_roles[role].members.remove(account)) {
|
||||
if (hasRole(role, account)) {
|
||||
_roles[role].members[account] = false;
|
||||
emit RoleRevoked(role, account, _msgSender());
|
||||
}
|
||||
}
|
||||
|
||||
63
contracts/access/AccessControlEnumerable.sol
Normal file
63
contracts/access/AccessControlEnumerable.sol
Normal file
@ -0,0 +1,63 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "./AccessControl.sol";
|
||||
import "../utils/structs/EnumerableSet.sol";
|
||||
|
||||
/**
|
||||
* @dev Extension of {AccessControl} that allows enumerating the members of each role.
|
||||
*/
|
||||
abstract contract AccessControlEnumerable is AccessControl {
|
||||
using EnumerableSet for EnumerableSet.AddressSet;
|
||||
|
||||
mapping (bytes32 => EnumerableSet.AddressSet) private _roleMembers;
|
||||
|
||||
/**
|
||||
* @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 _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 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 {_setupRole} to track enumerable memberships
|
||||
*/
|
||||
function _setupRole(bytes32 role, address account) internal virtual override {
|
||||
super._setupRole(role, account);
|
||||
_roleMembers[role].add(account);
|
||||
}
|
||||
}
|
||||
@ -1,8 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../GSN/Context.sol";
|
||||
import "../utils/Context.sol";
|
||||
/**
|
||||
* @dev Contract module which provides a basic access control mechanism, where
|
||||
* there is an account (an owner) that can be granted exclusive access to
|
||||
@ -15,7 +15,7 @@ import "../GSN/Context.sol";
|
||||
* `onlyOwner`, which can be applied to your functions to restrict their use to
|
||||
* the owner.
|
||||
*/
|
||||
contract Ownable is Context {
|
||||
abstract contract Ownable is Context {
|
||||
address private _owner;
|
||||
|
||||
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
|
||||
@ -23,7 +23,7 @@ contract Ownable is Context {
|
||||
/**
|
||||
* @dev Initializes the contract setting the deployer as the initial owner.
|
||||
*/
|
||||
constructor () internal {
|
||||
constructor () {
|
||||
address msgSender = _msgSender();
|
||||
_owner = msgSender;
|
||||
emit OwnershipTransferred(address(0), msgSender);
|
||||
@ -32,7 +32,7 @@ contract Ownable is Context {
|
||||
/**
|
||||
* @dev Returns the address of the current owner.
|
||||
*/
|
||||
function owner() public view returns (address) {
|
||||
function owner() public view virtual returns (address) {
|
||||
return _owner;
|
||||
}
|
||||
|
||||
@ -40,7 +40,7 @@ contract Ownable is Context {
|
||||
* @dev Throws if called by any account other than the owner.
|
||||
*/
|
||||
modifier onlyOwner() {
|
||||
require(_owner == _msgSender(), "Ownable: caller is not the owner");
|
||||
require(owner() == _msgSender(), "Ownable: caller is not the owner");
|
||||
_;
|
||||
}
|
||||
|
||||
|
||||
@ -3,87 +3,15 @@
|
||||
[.readme-notice]
|
||||
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/access
|
||||
|
||||
Contract modules for authorization and access control mechanisms.
|
||||
This directory provides ways to restrict who can access the functions of a contract or when they can do it.
|
||||
|
||||
- {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.
|
||||
|
||||
== Authorization
|
||||
|
||||
{{Ownable}}
|
||||
|
||||
{{AccessControl}}
|
||||
|
||||
== Timelock
|
||||
|
||||
{{TimelockController}}
|
||||
|
||||
==== 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.
|
||||
|
||||
==== 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.
|
||||
|
||||
==== 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)`]
|
||||
|
||||
==== Roles
|
||||
|
||||
===== 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`
|
||||
|
||||
===== 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`
|
||||
|
||||
===== 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.
|
||||
{{AccessControlEnumerable}}
|
||||
|
||||
@ -1,12 +0,0 @@
|
||||
= 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.
|
||||
|
||||
== Libraries
|
||||
|
||||
{{ECDSA}}
|
||||
|
||||
{{MerkleProof}}
|
||||
91
contracts/governance/README.adoc
Normal file
91
contracts/governance/README.adoc
Normal file
@ -0,0 +1,91 @@
|
||||
= Governance
|
||||
|
||||
[.readme-notice]
|
||||
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/access
|
||||
|
||||
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.
|
||||
@ -1,10 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "./../math/SafeMath.sol";
|
||||
import "./AccessControl.sol";
|
||||
import "../access/AccessControl.sol";
|
||||
|
||||
/**
|
||||
* @dev Contract module which acts as a timelocked controller. When set as the
|
||||
@ -18,9 +16,10 @@ import "./AccessControl.sol";
|
||||
* is in charge of proposing (resp executing) operations. A common use case is
|
||||
* to position this {TimelockController} as the owner of a smart contract, with
|
||||
* a multisig or a DAO as the sole proposer.
|
||||
*
|
||||
* _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");
|
||||
@ -52,7 +51,7 @@ contract TimelockController is AccessControl {
|
||||
/**
|
||||
* @dev Initializes the contract with a given `minDelay`.
|
||||
*/
|
||||
constructor(uint256 minDelay, address[] memory proposers, address[] memory executors) public {
|
||||
constructor(uint256 minDelay, address[] memory proposers, address[] memory executors) {
|
||||
_setRoleAdmin(TIMELOCK_ADMIN_ROLE, TIMELOCK_ADMIN_ROLE);
|
||||
_setRoleAdmin(PROPOSER_ROLE, TIMELOCK_ADMIN_ROLE);
|
||||
_setRoleAdmin(EXECUTOR_ROLE, TIMELOCK_ADMIN_ROLE);
|
||||
@ -86,45 +85,56 @@ contract TimelockController is AccessControl {
|
||||
_;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* @dev Contract might receive/hold ETH as part of the maintenance process.
|
||||
*/
|
||||
receive() external payable {}
|
||||
|
||||
/**
|
||||
* @dev Returns whether an id correspond to a registered operation. This
|
||||
* includes both Pending, Ready and Done operations.
|
||||
*/
|
||||
function isOperation(bytes32 id) public view virtual returns (bool pending) {
|
||||
return getTimestamp(id) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns whether an operation is pending or not.
|
||||
*/
|
||||
function isOperationPending(bytes32 id) public view returns (bool pending) {
|
||||
return _timestamps[id] > _DONE_TIMESTAMP;
|
||||
function isOperationPending(bytes32 id) public view virtual returns (bool pending) {
|
||||
return getTimestamp(id) > _DONE_TIMESTAMP;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns whether an operation is ready or not.
|
||||
*/
|
||||
function isOperationReady(bytes32 id) public view returns (bool ready) {
|
||||
function isOperationReady(bytes32 id) public view virtual returns (bool ready) {
|
||||
uint256 timestamp = getTimestamp(id);
|
||||
// solhint-disable-next-line not-rely-on-time
|
||||
return _timestamps[id] > _DONE_TIMESTAMP && _timestamps[id] <= block.timestamp;
|
||||
return timestamp > _DONE_TIMESTAMP && timestamp <= block.timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns whether an operation is done or not.
|
||||
*/
|
||||
function isOperationDone(bytes32 id) public view returns (bool done) {
|
||||
return _timestamps[id] == _DONE_TIMESTAMP;
|
||||
function isOperationDone(bytes32 id) public view virtual returns (bool done) {
|
||||
return getTimestamp(id) == _DONE_TIMESTAMP;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the timestamp at with an operation becomes ready (0 for
|
||||
* unset operations, 1 for done operations).
|
||||
*/
|
||||
function getTimestamp(bytes32 id) public view returns (uint256 timestamp) {
|
||||
function getTimestamp(bytes32 id) public view virtual returns (uint256 timestamp) {
|
||||
return _timestamps[id];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the minimum delay for an operation to become valid.
|
||||
*
|
||||
* This value can be changed by executing an operation that calls `updateDelay`.
|
||||
*/
|
||||
function getMinDelay() public view returns (uint256 duration) {
|
||||
function getMinDelay() public view virtual returns (uint256 duration) {
|
||||
return _minDelay;
|
||||
}
|
||||
|
||||
@ -132,7 +142,7 @@ contract TimelockController is AccessControl {
|
||||
* @dev Returns the identifier of an operation containing a single
|
||||
* transaction.
|
||||
*/
|
||||
function hashOperation(address target, uint256 value, bytes calldata data, bytes32 predecessor, bytes32 salt) public pure returns (bytes32 hash) {
|
||||
function hashOperation(address target, uint256 value, bytes calldata data, bytes32 predecessor, bytes32 salt) public pure virtual returns (bytes32 hash) {
|
||||
return keccak256(abi.encode(target, value, data, predecessor, salt));
|
||||
}
|
||||
|
||||
@ -140,7 +150,7 @@ contract TimelockController is AccessControl {
|
||||
* @dev Returns the identifier of an operation containing a batch of
|
||||
* transactions.
|
||||
*/
|
||||
function hashOperationBatch(address[] calldata targets, uint256[] calldata values, bytes[] calldata datas, bytes32 predecessor, bytes32 salt) public pure returns (bytes32 hash) {
|
||||
function hashOperationBatch(address[] calldata targets, uint256[] calldata values, bytes[] calldata datas, bytes32 predecessor, bytes32 salt) public pure virtual returns (bytes32 hash) {
|
||||
return keccak256(abi.encode(targets, values, datas, predecessor, salt));
|
||||
}
|
||||
|
||||
@ -183,10 +193,10 @@ contract TimelockController is AccessControl {
|
||||
* @dev Schedule an operation that is to becomes valid after a given delay.
|
||||
*/
|
||||
function _schedule(bytes32 id, uint256 delay) private {
|
||||
require(_timestamps[id] == 0, "TimelockController: operation already scheduled");
|
||||
require(delay >= _minDelay, "TimelockController: insufficient delay");
|
||||
require(!isOperation(id), "TimelockController: operation already scheduled");
|
||||
require(delay >= getMinDelay(), "TimelockController: insufficient delay");
|
||||
// solhint-disable-next-line not-rely-on-time
|
||||
_timestamps[id] = SafeMath.add(block.timestamp, delay);
|
||||
_timestamps[id] = block.timestamp + delay;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -269,9 +279,14 @@ contract TimelockController is AccessControl {
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Changes the timelock duration for future operations.
|
||||
* @dev Changes the minimum timelock duration for future operations.
|
||||
*
|
||||
* Emits a {MinDelayChange} event.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - the caller must be the timelock itself. This can only be achieved by scheduling and later executing
|
||||
* an operation where the timelock is the target and the data is the ABI-encoded call to this function.
|
||||
*/
|
||||
function updateDelay(uint256 newDelay) external virtual {
|
||||
require(msg.sender == address(this), "TimelockController: caller must be timelock");
|
||||
@ -1,31 +0,0 @@
|
||||
= 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}}
|
||||
@ -1,14 +0,0 @@
|
||||
= 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}}
|
||||
@ -1,159 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
/**
|
||||
* @dev Wrappers over Solidity's arithmetic operations with added overflow
|
||||
* checks.
|
||||
*
|
||||
* 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 {
|
||||
/**
|
||||
* @dev Returns the addition of two unsigned integers, reverting on
|
||||
* overflow.
|
||||
*
|
||||
* Counterpart to Solidity's `+` operator.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - Addition cannot overflow.
|
||||
*/
|
||||
function add(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
uint256 c = a + b;
|
||||
require(c >= a, "SafeMath: addition overflow");
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the subtraction of two unsigned integers, reverting on
|
||||
* overflow (when the result is negative).
|
||||
*
|
||||
* Counterpart to Solidity's `-` operator.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - Subtraction cannot overflow.
|
||||
*/
|
||||
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
return sub(a, b, "SafeMath: subtraction overflow");
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
|
||||
* overflow (when the result is negative).
|
||||
*
|
||||
* Counterpart to Solidity's `-` operator.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - Subtraction cannot overflow.
|
||||
*/
|
||||
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
|
||||
require(b <= a, errorMessage);
|
||||
uint256 c = a - b;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the multiplication of two unsigned integers, reverting on
|
||||
* overflow.
|
||||
*
|
||||
* Counterpart to Solidity's `*` operator.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - Multiplication cannot overflow.
|
||||
*/
|
||||
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
|
||||
// benefit is lost if 'b' is also tested.
|
||||
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
|
||||
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. 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(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
return div(a, b, "SafeMath: division by zero");
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the integer division of two unsigned integers. Reverts with custom message 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(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
|
||||
require(b > 0, errorMessage);
|
||||
uint256 c = a / b;
|
||||
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
|
||||
* Reverts when dividing by 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).
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - The divisor cannot be zero.
|
||||
*/
|
||||
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
return mod(a, b, "SafeMath: modulo by zero");
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
|
||||
* Reverts with custom message when dividing by 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).
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - The divisor cannot be zero.
|
||||
*/
|
||||
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
|
||||
require(b != 0, errorMessage);
|
||||
return a % b;
|
||||
}
|
||||
}
|
||||
@ -1,92 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.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;
|
||||
}
|
||||
}
|
||||
37
contracts/metatx/ERC2771Context.sol
Normal file
37
contracts/metatx/ERC2771Context.sol
Normal file
@ -0,0 +1,37 @@
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
58
contracts/metatx/MinimalForwarder.sol
Normal file
58
contracts/metatx/MinimalForwarder.sol
Normal file
@ -0,0 +1,58 @@
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
12
contracts/metatx/README.adoc
Normal file
12
contracts/metatx/README.adoc
Normal file
@ -0,0 +1,12 @@
|
||||
= Meta Transactions
|
||||
|
||||
[.readme-notice]
|
||||
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/metatx
|
||||
|
||||
== Core
|
||||
|
||||
{{ERC2771Context}}
|
||||
|
||||
== Utils
|
||||
|
||||
{{MinimalForwarder}}
|
||||
15
contracts/mocks/AccessControlEnumerableMock.sol
Normal file
15
contracts/mocks/AccessControlEnumerableMock.sol
Normal file
@ -0,0 +1,15 @@
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
@ -1,11 +1,11 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../access/AccessControl.sol";
|
||||
|
||||
contract AccessControlMock is AccessControl {
|
||||
constructor() public {
|
||||
constructor() {
|
||||
_setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../utils/Address.sol";
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../utils/Arrays.sol";
|
||||
|
||||
@ -9,7 +9,7 @@ contract ArraysImpl {
|
||||
|
||||
uint256[] private _array;
|
||||
|
||||
constructor (uint256[] memory array) public {
|
||||
constructor (uint256[] memory array) {
|
||||
_array = array;
|
||||
}
|
||||
|
||||
|
||||
12
contracts/mocks/BadBeacon.sol
Normal file
12
contracts/mocks/BadBeacon.sol
Normal file
@ -0,0 +1,12 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract BadBeaconNoImpl {
|
||||
}
|
||||
|
||||
contract BadBeaconNotContract {
|
||||
function implementation() external pure returns (address) {
|
||||
return address(0x1);
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract CallReceiverMock {
|
||||
string public sharedAnswer;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
32
contracts/mocks/ClonesMock.sol
Normal file
32
contracts/mocks/ClonesMock.sol
Normal file
@ -0,0 +1,32 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../proxy/Clones.sol";
|
||||
import "../utils/Address.sol";
|
||||
|
||||
contract ClonesMock {
|
||||
using Address for address;
|
||||
using Clones for address;
|
||||
|
||||
event NewInstance(address instance);
|
||||
|
||||
function clone(address implementation, bytes calldata initdata) public payable {
|
||||
_initAndEmit(implementation.clone(), initdata);
|
||||
}
|
||||
|
||||
function cloneDeterministic(address implementation, bytes32 salt, bytes calldata initdata) public payable {
|
||||
_initAndEmit(implementation.cloneDeterministic(salt), initdata);
|
||||
}
|
||||
|
||||
function predictDeterministicAddress(address implementation, bytes32 salt) public view returns (address predicted) {
|
||||
return implementation.predictDeterministicAddress(salt);
|
||||
}
|
||||
|
||||
function _initAndEmit(address instance, bytes memory initdata) private {
|
||||
if (initdata.length > 0) {
|
||||
instance.functionCallWithValue(initdata, msg.value);
|
||||
}
|
||||
emit NewInstance(instance);
|
||||
}
|
||||
}
|
||||
@ -1,8 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../payment/escrow/ConditionalEscrow.sol";
|
||||
import "../utils/escrow/ConditionalEscrow.sol";
|
||||
|
||||
// mock class using ConditionalEscrow
|
||||
contract ConditionalEscrowMock is ConditionalEscrow {
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../GSN/Context.sol";
|
||||
import "../utils/Context.sol";
|
||||
|
||||
contract ContextMock is Context {
|
||||
event Sender(address sender);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../utils/Counters.sol";
|
||||
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../utils/Create2.sol";
|
||||
import "../introspection/ERC1820Implementer.sol";
|
||||
import "../utils/introspection/ERC1820Implementer.sol";
|
||||
|
||||
contract Create2Impl {
|
||||
function deploy(uint256 value, bytes32 salt, bytes memory code) public {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
abstract contract Impl {
|
||||
function version() public pure virtual returns (string memory);
|
||||
@ -19,11 +19,11 @@ contract DummyImplementation {
|
||||
value = 100;
|
||||
}
|
||||
|
||||
function initializeNonPayable(uint256 _value) public {
|
||||
function initializeNonPayableWithValue(uint256 _value) public {
|
||||
value = _value;
|
||||
}
|
||||
|
||||
function initializePayable(uint256 _value) public payable {
|
||||
function initializePayableWithValue(uint256 _value) public payable {
|
||||
value = _value;
|
||||
}
|
||||
|
||||
@ -42,7 +42,7 @@ contract DummyImplementation {
|
||||
}
|
||||
|
||||
function reverts() public pure {
|
||||
require(false);
|
||||
require(false, "DummyImplementation reverted");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../cryptography/ECDSA.sol";
|
||||
import "../utils/cryptography/ECDSA.sol";
|
||||
|
||||
contract ECDSAMock {
|
||||
using ECDSA for bytes32;
|
||||
|
||||
28
contracts/mocks/EIP712External.sol
Normal file
28
contracts/mocks/EIP712External.sol
Normal file
@ -0,0 +1,28 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../utils/cryptography/draft-EIP712.sol";
|
||||
import "../utils/cryptography/ECDSA.sol";
|
||||
|
||||
contract EIP712External is EIP712 {
|
||||
constructor(string memory name, string memory version) EIP712(name, version) {}
|
||||
|
||||
function domainSeparator() external view returns (bytes32) {
|
||||
return _domainSeparatorV4();
|
||||
}
|
||||
|
||||
function verify(bytes memory signature, address signer, address mailTo, string memory mailContents) external view {
|
||||
bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
|
||||
keccak256("Mail(address to,string contents)"),
|
||||
mailTo,
|
||||
keccak256(bytes(mailContents))
|
||||
)));
|
||||
address recoveredSigner = ECDSA.recover(digest, signature);
|
||||
require(recoveredSigner == signer);
|
||||
}
|
||||
|
||||
function getChainId() external view returns (uint256) {
|
||||
return block.chainid;
|
||||
}
|
||||
}
|
||||
@ -1,11 +1,11 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../token/ERC1155/ERC1155Burnable.sol";
|
||||
import "../token/ERC1155/extensions/ERC1155Burnable.sol";
|
||||
|
||||
contract ERC1155BurnableMock is ERC1155Burnable {
|
||||
constructor(string memory uri) public ERC1155(uri) { }
|
||||
constructor(string memory uri) ERC1155(uri) { }
|
||||
|
||||
function mint(address to, uint256 id, uint256 value, bytes memory data) public {
|
||||
_mint(to, id, value, data);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../token/ERC1155/ERC1155.sol";
|
||||
|
||||
@ -9,7 +9,7 @@ import "../token/ERC1155/ERC1155.sol";
|
||||
* This mock just publicizes internal functions for testing purposes
|
||||
*/
|
||||
contract ERC1155Mock is ERC1155 {
|
||||
constructor (string memory uri) public ERC1155(uri) {
|
||||
constructor (string memory uri) ERC1155(uri) {
|
||||
// solhint-disable-previous-line no-empty-blocks
|
||||
}
|
||||
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "./ERC1155Mock.sol";
|
||||
import "../token/ERC1155/ERC1155Pausable.sol";
|
||||
import "../token/ERC1155/extensions/ERC1155Pausable.sol";
|
||||
|
||||
contract ERC1155PausableMock is ERC1155Mock, ERC1155Pausable {
|
||||
constructor(string memory uri) public ERC1155Mock(uri) { }
|
||||
constructor(string memory uri) ERC1155Mock(uri) { }
|
||||
|
||||
function pause() external {
|
||||
_pause();
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../token/ERC1155/IERC1155Receiver.sol";
|
||||
import "./ERC165Mock.sol";
|
||||
import "../utils/introspection/ERC165.sol";
|
||||
|
||||
contract ERC1155ReceiverMock is IERC1155Receiver, ERC165Mock {
|
||||
contract ERC1155ReceiverMock is IERC1155Receiver, ERC165 {
|
||||
bytes4 private _recRetval;
|
||||
bool private _recReverts;
|
||||
bytes4 private _batRetval;
|
||||
@ -20,7 +20,6 @@ contract ERC1155ReceiverMock is IERC1155Receiver, ERC165Mock {
|
||||
bytes4 batRetval,
|
||||
bool batReverts
|
||||
)
|
||||
public
|
||||
{
|
||||
_recRetval = recRetval;
|
||||
_recReverts = recReverts;
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../../introspection/IERC165.sol";
|
||||
import "../../utils/introspection/IERC165.sol";
|
||||
|
||||
/**
|
||||
* https://eips.ethereum.org/EIPS/eip-214#specification
|
||||
@ -29,7 +29,7 @@ contract SupportsInterfaceWithLookupMock is IERC165 {
|
||||
* @dev A contract implementing SupportsInterfaceWithLookup
|
||||
* implement ERC165 itself.
|
||||
*/
|
||||
constructor () public {
|
||||
constructor () {
|
||||
_registerInterface(INTERFACE_ID_ERC165);
|
||||
}
|
||||
|
||||
@ -50,7 +50,7 @@ contract SupportsInterfaceWithLookupMock is IERC165 {
|
||||
}
|
||||
|
||||
contract ERC165InterfacesSupported is SupportsInterfaceWithLookupMock {
|
||||
constructor (bytes4[] memory interfaceIds) public {
|
||||
constructor (bytes4[] memory interfaceIds) {
|
||||
for (uint256 i = 0; i < interfaceIds.length; i++) {
|
||||
_registerInterface(interfaceIds[i]);
|
||||
}
|
||||
|
||||
7
contracts/mocks/ERC165/ERC165MissingData.sol
Normal file
7
contracts/mocks/ERC165/ERC165MissingData.sol
Normal file
@ -0,0 +1,7 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract ERC165MissingData {
|
||||
function supportsInterface(bytes4 interfaceId) public view {} // missing return
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract ERC165NotSupported { }
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../introspection/ERC165Checker.sol";
|
||||
import "../utils/introspection/ERC165Checker.sol";
|
||||
|
||||
contract ERC165CheckerMock {
|
||||
using ERC165Checker for address;
|
||||
@ -18,4 +18,8 @@ contract ERC165CheckerMock {
|
||||
function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) public view returns (bool) {
|
||||
return account.supportsAllInterfaces(interfaceIds);
|
||||
}
|
||||
|
||||
function getSupportedInterfaces(address account, bytes4[] memory interfaceIds) public view returns (bool[] memory) {
|
||||
return account.getSupportedInterfaces(interfaceIds);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,11 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../introspection/ERC165.sol";
|
||||
import "../utils/introspection/ERC165.sol";
|
||||
|
||||
contract ERC165Mock is ERC165 {
|
||||
function registerInterface(bytes4 interfaceId) public {
|
||||
_registerInterface(interfaceId);
|
||||
}
|
||||
}
|
||||
|
||||
11
contracts/mocks/ERC165StorageMock.sol
Normal file
11
contracts/mocks/ERC165StorageMock.sol
Normal file
@ -0,0 +1,11 @@
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
@ -1,8 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../introspection/ERC1820Implementer.sol";
|
||||
import "../utils/introspection/ERC1820Implementer.sol";
|
||||
|
||||
contract ERC1820ImplementerMock is ERC1820Implementer {
|
||||
function registerInterfaceForAddress(bytes32 interfaceHash, address account) public {
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../token/ERC20/ERC20Burnable.sol";
|
||||
import "../token/ERC20/extensions/ERC20Burnable.sol";
|
||||
|
||||
contract ERC20BurnableMock is ERC20Burnable {
|
||||
constructor (
|
||||
@ -10,7 +10,7 @@ contract ERC20BurnableMock is ERC20Burnable {
|
||||
string memory symbol,
|
||||
address initialAccount,
|
||||
uint256 initialBalance
|
||||
) public ERC20(name, symbol) {
|
||||
) ERC20(name, symbol) {
|
||||
_mint(initialAccount, initialBalance);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../token/ERC20/ERC20Capped.sol";
|
||||
import "../token/ERC20/extensions/ERC20Capped.sol";
|
||||
|
||||
contract ERC20CappedMock is ERC20Capped {
|
||||
constructor (string memory name, string memory symbol, uint256 cap)
|
||||
public ERC20(name, symbol) ERC20Capped(cap)
|
||||
ERC20(name, symbol) ERC20Capped(cap)
|
||||
{ }
|
||||
|
||||
function mint(address to, uint256 tokenId) public {
|
||||
|
||||
@ -1,11 +1,17 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../token/ERC20/ERC20.sol";
|
||||
|
||||
contract ERC20DecimalsMock is ERC20 {
|
||||
constructor (string memory name, string memory symbol, uint8 decimals) public ERC20(name, symbol) {
|
||||
_setupDecimals(decimals);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../token/ERC20/ERC20.sol";
|
||||
|
||||
@ -11,7 +11,7 @@ contract ERC20Mock is ERC20 {
|
||||
string memory symbol,
|
||||
address initialAccount,
|
||||
uint256 initialBalance
|
||||
) public payable ERC20(name, symbol) {
|
||||
) payable ERC20(name, symbol) {
|
||||
_mint(initialAccount, initialBalance);
|
||||
}
|
||||
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../token/ERC20/ERC20Pausable.sol";
|
||||
import "../token/ERC20/extensions/ERC20Pausable.sol";
|
||||
|
||||
// mock class using ERC20Pausable
|
||||
contract ERC20PausableMock is ERC20Pausable {
|
||||
@ -11,7 +11,7 @@ contract ERC20PausableMock is ERC20Pausable {
|
||||
string memory symbol,
|
||||
address initialAccount,
|
||||
uint256 initialBalance
|
||||
) public ERC20(name, symbol) {
|
||||
) ERC20(name, symbol) {
|
||||
_mint(initialAccount, initialBalance);
|
||||
}
|
||||
|
||||
|
||||
21
contracts/mocks/ERC20PermitMock.sol
Normal file
21
contracts/mocks/ERC20PermitMock.sol
Normal file
@ -0,0 +1,21 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
|
||||
import "../token/ERC20/extensions/draft-ERC20Permit.sol";
|
||||
|
||||
contract ERC20PermitMock is ERC20Permit {
|
||||
constructor (
|
||||
string memory name,
|
||||
string memory symbol,
|
||||
address initialAccount,
|
||||
uint256 initialBalance
|
||||
) payable ERC20(name, symbol) ERC20Permit(name) {
|
||||
_mint(initialAccount, initialBalance);
|
||||
}
|
||||
|
||||
function getChainId() external view returns (uint256) {
|
||||
return block.chainid;
|
||||
}
|
||||
}
|
||||
@ -1,8 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../token/ERC20/ERC20Snapshot.sol";
|
||||
import "../token/ERC20/extensions/ERC20Snapshot.sol";
|
||||
|
||||
|
||||
contract ERC20SnapshotMock is ERC20Snapshot {
|
||||
@ -11,7 +11,7 @@ contract ERC20SnapshotMock is ERC20Snapshot {
|
||||
string memory symbol,
|
||||
address initialAccount,
|
||||
uint256 initialBalance
|
||||
) public ERC20(name, symbol) {
|
||||
) ERC20(name, symbol) {
|
||||
_mint(initialAccount, initialBalance);
|
||||
}
|
||||
|
||||
|
||||
19
contracts/mocks/ERC2771ContextMock.sol
Normal file
19
contracts/mocks/ERC2771ContextMock.sol
Normal file
@ -0,0 +1,19 @@
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
@ -1,13 +1,25 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../token/ERC721/ERC721Burnable.sol";
|
||||
import "../token/ERC721/extensions/ERC721Burnable.sol";
|
||||
|
||||
contract ERC721BurnableMock is ERC721Burnable {
|
||||
constructor(string memory name, string memory symbol) public ERC721(name, symbol) { }
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
47
contracts/mocks/ERC721EnumerableMock.sol
Normal file
47
contracts/mocks/ERC721EnumerableMock.sol
Normal file
@ -0,0 +1,47 @@
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
@ -1,31 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.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)
|
||||
public
|
||||
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();
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../token/ERC721/ERC721.sol";
|
||||
|
||||
@ -9,20 +9,26 @@ import "../token/ERC721/ERC721.sol";
|
||||
* This mock just provides a public safeMint, mint, and burn functions for testing purposes
|
||||
*/
|
||||
contract ERC721Mock is ERC721 {
|
||||
constructor (string memory name, string memory symbol) public ERC721(name, symbol) { }
|
||||
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);
|
||||
}
|
||||
|
||||
@ -1,27 +1,15 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../token/ERC721/ERC721Pausable.sol";
|
||||
import "../token/ERC721/extensions/ERC721Pausable.sol";
|
||||
|
||||
/**
|
||||
* @title ERC721PausableMock
|
||||
* This mock just provides a public mint, burn and exists functions for testing purposes
|
||||
*/
|
||||
contract ERC721PausableMock is ERC721Pausable {
|
||||
constructor (string memory name, string memory symbol) public 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);
|
||||
}
|
||||
constructor (string memory name, string memory symbol) ERC721(name, symbol) { }
|
||||
|
||||
function pause() external {
|
||||
_pause();
|
||||
@ -30,4 +18,24 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,24 +1,38 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../token/ERC721/IERC721Receiver.sol";
|
||||
|
||||
contract ERC721ReceiverMock is IERC721Receiver {
|
||||
bytes4 private _retval;
|
||||
bool private _reverts;
|
||||
enum Error {
|
||||
None,
|
||||
RevertWithMessage,
|
||||
RevertWithoutMessage,
|
||||
Panic
|
||||
}
|
||||
|
||||
bytes4 private immutable _retval;
|
||||
Error private immutable _error;
|
||||
|
||||
event Received(address operator, address from, uint256 tokenId, bytes data, uint256 gas);
|
||||
|
||||
constructor (bytes4 retval, bool reverts) public {
|
||||
constructor (bytes4 retval, Error error) {
|
||||
_retval = retval;
|
||||
_reverts = reverts;
|
||||
_error = error;
|
||||
}
|
||||
|
||||
function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data)
|
||||
public override returns (bytes4)
|
||||
{
|
||||
require(!_reverts, "ERC721ReceiverMock: reverting");
|
||||
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;
|
||||
}
|
||||
emit Received(operator, from, tokenId, data, gasleft());
|
||||
return _retval;
|
||||
}
|
||||
|
||||
51
contracts/mocks/ERC721URIStorageMock.sol
Normal file
51
contracts/mocks/ERC721URIStorageMock.sol
Normal file
@ -0,0 +1,51 @@
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
@ -1,18 +1,20 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../GSN/Context.sol";
|
||||
import "../utils/Context.sol";
|
||||
import "../token/ERC777/ERC777.sol";
|
||||
|
||||
contract ERC777Mock is Context, ERC777 {
|
||||
event BeforeTokenTransfer();
|
||||
|
||||
constructor(
|
||||
address initialHolder,
|
||||
uint256 initialBalance,
|
||||
string memory name,
|
||||
string memory symbol,
|
||||
address[] memory defaultOperators
|
||||
) public ERC777(name, symbol, defaultOperators) {
|
||||
) ERC777(name, symbol, defaultOperators) {
|
||||
_mint(initialHolder, initialBalance, "", "");
|
||||
}
|
||||
|
||||
@ -28,4 +30,8 @@ contract ERC777Mock is Context, ERC777 {
|
||||
function approveInternal(address holder, address spender, uint256 value) public {
|
||||
_approve(holder, spender, value);
|
||||
}
|
||||
|
||||
function _beforeTokenTransfer(address, address, address, uint256) internal override {
|
||||
emit BeforeTokenTransfer();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../GSN/Context.sol";
|
||||
import "../token/ERC777/IERC777.sol";
|
||||
import "../token/ERC777/IERC777Sender.sol";
|
||||
import "../token/ERC777/IERC777Recipient.sol";
|
||||
import "../introspection/IERC1820Registry.sol";
|
||||
import "../introspection/ERC1820Implementer.sol";
|
||||
import "../utils/Context.sol";
|
||||
import "../utils/introspection/IERC1820Registry.sol";
|
||||
import "../utils/introspection/ERC1820Implementer.sol";
|
||||
|
||||
contract ERC777SenderRecipientMock is Context, IERC777Sender, IERC777Recipient, ERC1820Implementer {
|
||||
event TokensToSendCalled(
|
||||
@ -34,6 +34,9 @@ contract ERC777SenderRecipientMock is Context, IERC777Sender, IERC777Recipient,
|
||||
uint256 toBalance
|
||||
);
|
||||
|
||||
// Emitted in ERC777Mock. Here for easier decoding
|
||||
event BeforeTokenTransfer();
|
||||
|
||||
bool private _shouldRevertSend;
|
||||
bool private _shouldRevertReceive;
|
||||
|
||||
@ -147,4 +150,3 @@ contract ERC777SenderRecipientMock is Context, IERC777Sender, IERC777Recipient,
|
||||
token.burn(amount, data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../utils/EnumerableMap.sol";
|
||||
import "../utils/structs/EnumerableMap.sol";
|
||||
|
||||
contract EnumerableMapMock {
|
||||
using EnumerableMap for EnumerableMap.UintToAddressMap;
|
||||
@ -34,7 +34,15 @@ contract EnumerableMapMock {
|
||||
}
|
||||
|
||||
|
||||
function tryGet(uint256 key) public view returns (bool, address) {
|
||||
return _map.tryGet(key);
|
||||
}
|
||||
|
||||
function get(uint256 key) public view returns (address) {
|
||||
return _map.get(key);
|
||||
}
|
||||
|
||||
function getWithMessage(uint256 key, string calldata errorMessage) public view returns (address) {
|
||||
return _map.get(key, errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../utils/EnumerableSet.sol";
|
||||
import "../utils/structs/EnumerableSet.sol";
|
||||
|
||||
// Bytes32Set
|
||||
contract EnumerableBytes32SetMock {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract EtherReceiverMock {
|
||||
bool private _acceptEther;
|
||||
|
||||
@ -1,20 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "../GSN/GSNRecipient.sol";
|
||||
import "../GSN/GSNRecipientERC20Fee.sol";
|
||||
|
||||
contract GSNRecipientERC20FeeMock is GSNRecipient, GSNRecipientERC20Fee {
|
||||
constructor(string memory name, string memory symbol) public 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()));
|
||||
}
|
||||
}
|
||||
@ -1,38 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.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
|
||||
view
|
||||
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();
|
||||
}
|
||||
}
|
||||
@ -1,16 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "../GSN/GSNRecipient.sol";
|
||||
import "../GSN/GSNRecipientSignature.sol";
|
||||
|
||||
contract GSNRecipientSignatureMock is GSNRecipient, GSNRecipientSignature {
|
||||
constructor(address trustedSigner) public GSNRecipientSignature(trustedSigner) { }
|
||||
|
||||
event MockFunctionCalled();
|
||||
|
||||
function mockFunction() public {
|
||||
emit MockFunctionCalled();
|
||||
}
|
||||
}
|
||||
@ -1,8 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../proxy/Initializable.sol";
|
||||
import "../utils/Initializable.sol";
|
||||
|
||||
/**
|
||||
* @title InitializableMock
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../math/Math.sol";
|
||||
import "../utils/math/Math.sol";
|
||||
|
||||
contract MathMock {
|
||||
function max(uint256 a, uint256 b) public pure returns (uint256) {
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import { MerkleProof } from "../cryptography/MerkleProof.sol";
|
||||
import "../utils/cryptography/MerkleProof.sol";
|
||||
|
||||
contract MerkleProofWrapper {
|
||||
function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) public pure returns (bool) {
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../proxy/Initializable.sol";
|
||||
import "../utils/Initializable.sol";
|
||||
|
||||
// Sample contracts showing upgradeability with multiple inheritance.
|
||||
// Child contract inherits from Father and Mother contracts, and Father extends from Gramps.
|
||||
//
|
||||
//
|
||||
// Human
|
||||
// / \
|
||||
// | Gramps
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../access/Ownable.sol";
|
||||
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../utils/Pausable.sol";
|
||||
import "../security/Pausable.sol";
|
||||
|
||||
contract PausableMock is Pausable {
|
||||
bool public drasticMeasureTaken;
|
||||
uint256 public count;
|
||||
|
||||
constructor () public {
|
||||
constructor () {
|
||||
drasticMeasureTaken = false;
|
||||
count = 0;
|
||||
}
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../payment/PullPayment.sol";
|
||||
import "../security/PullPayment.sol";
|
||||
|
||||
// mock class using PullPayment
|
||||
contract PullPaymentMock is PullPayment {
|
||||
constructor () public payable { }
|
||||
constructor () payable { }
|
||||
|
||||
// test helper function to call asyncTransfer
|
||||
function callTransfer(address dest, uint256 amount) public {
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../GSN/Context.sol";
|
||||
import "../utils/Context.sol";
|
||||
contract ReentrancyAttack is Context {
|
||||
function callSender(bytes4 data) public {
|
||||
// solhint-disable-next-line avoid-low-level-calls
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../utils/ReentrancyGuard.sol";
|
||||
import "../security/ReentrancyGuard.sol";
|
||||
import "./ReentrancyAttack.sol";
|
||||
|
||||
contract ReentrancyMock is ReentrancyGuard {
|
||||
uint256 public counter;
|
||||
|
||||
constructor () public {
|
||||
constructor () {
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../proxy/Initializable.sol";
|
||||
import "../utils/Initializable.sol";
|
||||
|
||||
contract Implementation1 is Initializable {
|
||||
uint internal _value;
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../utils/SafeCast.sol";
|
||||
import "../utils/math/SafeCast.sol";
|
||||
|
||||
contract SafeCastMock {
|
||||
using SafeCast for uint;
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../GSN/Context.sol";
|
||||
import "../utils/Context.sol";
|
||||
import "../token/ERC20/IERC20.sol";
|
||||
import "../token/ERC20/SafeERC20.sol";
|
||||
import "../token/ERC20/utils/SafeERC20.sol";
|
||||
|
||||
contract ERC20ReturnFalseMock is Context {
|
||||
uint256 private _allowance;
|
||||
@ -98,7 +98,7 @@ contract SafeERC20Wrapper is Context {
|
||||
|
||||
IERC20 private _token;
|
||||
|
||||
constructor (IERC20 token) public {
|
||||
constructor (IERC20 token) {
|
||||
_token = token;
|
||||
}
|
||||
|
||||
|
||||
@ -1,27 +1,107 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../math/SafeMath.sol";
|
||||
import "../utils/math/SafeMath.sol";
|
||||
|
||||
contract SafeMathMock {
|
||||
function mul(uint256 a, uint256 b) public pure returns (uint256) {
|
||||
return SafeMath.mul(a, b);
|
||||
function tryAdd(uint256 a, uint256 b) public pure returns (bool flag, uint256 value) {
|
||||
return SafeMath.tryAdd(a, b);
|
||||
}
|
||||
|
||||
function div(uint256 a, uint256 b) public pure returns (uint256) {
|
||||
return SafeMath.div(a, b);
|
||||
function trySub(uint256 a, uint256 b) public pure returns (bool flag, uint256 value) {
|
||||
return SafeMath.trySub(a, b);
|
||||
}
|
||||
|
||||
function sub(uint256 a, uint256 b) public pure returns (uint256) {
|
||||
return SafeMath.sub(a, b);
|
||||
function tryMul(uint256 a, uint256 b) public pure returns (bool flag, uint256 value) {
|
||||
return SafeMath.tryMul(a, b);
|
||||
}
|
||||
|
||||
function add(uint256 a, uint256 b) public pure returns (uint256) {
|
||||
function tryDiv(uint256 a, uint256 b) public pure returns (bool flag, uint256 value) {
|
||||
return SafeMath.tryDiv(a, b);
|
||||
}
|
||||
|
||||
function tryMod(uint256 a, uint256 b) public pure returns (bool flag, uint256 value) {
|
||||
return SafeMath.tryMod(a, b);
|
||||
}
|
||||
|
||||
// using the do* naming convention to avoid warnings due to clashing opcode names
|
||||
|
||||
function doAdd(uint256 a, uint256 b) public pure returns (uint256) {
|
||||
return SafeMath.add(a, b);
|
||||
}
|
||||
|
||||
function mod(uint256 a, uint256 b) public pure returns (uint256) {
|
||||
function doSub(uint256 a, uint256 b) public pure returns (uint256) {
|
||||
return SafeMath.sub(a, b);
|
||||
}
|
||||
|
||||
function doMul(uint256 a, uint256 b) public pure returns (uint256) {
|
||||
return SafeMath.mul(a, b);
|
||||
}
|
||||
|
||||
function doDiv(uint256 a, uint256 b) public pure returns (uint256) {
|
||||
return SafeMath.div(a, b);
|
||||
}
|
||||
|
||||
function doMod(uint256 a, uint256 b) public pure returns (uint256) {
|
||||
return SafeMath.mod(a, b);
|
||||
}
|
||||
|
||||
function subWithMessage(uint256 a, uint256 b, string memory errorMessage) public pure returns (uint256) {
|
||||
return SafeMath.sub(a, b, errorMessage);
|
||||
}
|
||||
|
||||
function divWithMessage(uint256 a, uint256 b, string memory errorMessage) public pure returns (uint256) {
|
||||
return SafeMath.div(a, b, errorMessage);
|
||||
}
|
||||
|
||||
function modWithMessage(uint256 a, uint256 b, string memory errorMessage) public pure returns (uint256) {
|
||||
return SafeMath.mod(a, b, errorMessage);
|
||||
}
|
||||
|
||||
function addMemoryCheck() public pure returns (uint256 mem) {
|
||||
uint256 length = 32;
|
||||
// solhint-disable-next-line no-inline-assembly
|
||||
assembly { mem := mload(0x40) }
|
||||
for (uint256 i = 0; i < length; ++i) { SafeMath.add(1, 1); }
|
||||
// solhint-disable-next-line no-inline-assembly
|
||||
assembly { mem := sub(mload(0x40), mem) }
|
||||
}
|
||||
|
||||
function subMemoryCheck() public pure returns (uint256 mem) {
|
||||
uint256 length = 32;
|
||||
// solhint-disable-next-line no-inline-assembly
|
||||
assembly { mem := mload(0x40) }
|
||||
for (uint256 i = 0; i < length; ++i) { SafeMath.sub(1, 1); }
|
||||
// solhint-disable-next-line no-inline-assembly
|
||||
assembly { mem := sub(mload(0x40), mem) }
|
||||
}
|
||||
|
||||
function mulMemoryCheck() public pure returns (uint256 mem) {
|
||||
uint256 length = 32;
|
||||
// solhint-disable-next-line no-inline-assembly
|
||||
assembly { mem := mload(0x40) }
|
||||
for (uint256 i = 0; i < length; ++i) { SafeMath.mul(1, 1); }
|
||||
// solhint-disable-next-line no-inline-assembly
|
||||
assembly { mem := sub(mload(0x40), mem) }
|
||||
}
|
||||
|
||||
function divMemoryCheck() public pure returns (uint256 mem) {
|
||||
uint256 length = 32;
|
||||
// solhint-disable-next-line no-inline-assembly
|
||||
assembly { mem := mload(0x40) }
|
||||
for (uint256 i = 0; i < length; ++i) { SafeMath.div(1, 1); }
|
||||
// solhint-disable-next-line no-inline-assembly
|
||||
assembly { mem := sub(mload(0x40), mem) }
|
||||
}
|
||||
|
||||
function modMemoryCheck() public pure returns (uint256 mem) {
|
||||
uint256 length = 32;
|
||||
// solhint-disable-next-line no-inline-assembly
|
||||
assembly { mem := mload(0x40) }
|
||||
for (uint256 i = 0; i < length; ++i) { SafeMath.mod(1, 1); }
|
||||
// solhint-disable-next-line no-inline-assembly
|
||||
assembly { mem := sub(mload(0x40), mem) }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../math/SignedSafeMath.sol";
|
||||
import "../utils/math/SignedSafeMath.sol";
|
||||
|
||||
contract SignedSafeMathMock {
|
||||
function mul(int256 a, int256 b) public pure returns (int256) {
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../proxy/Initializable.sol";
|
||||
import "../utils/Initializable.sol";
|
||||
|
||||
/**
|
||||
* @title MigratableMockV1
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../utils/Strings.sol";
|
||||
|
||||
@ -8,4 +8,10 @@ contract StringsMock {
|
||||
function fromUint256(uint256 value) public pure returns (string memory) {
|
||||
return Strings.toString(value);
|
||||
}
|
||||
function fromUint256Hex(uint256 value) public pure returns (string memory) {
|
||||
return Strings.toHexString(value);
|
||||
}
|
||||
function fromUint256HexFixed(uint256 value, uint256 length) public pure returns (string memory) {
|
||||
return Strings.toHexString(value, length);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,12 +1,11 @@
|
||||
{
|
||||
"name": "@openzeppelin/contracts",
|
||||
"description": "Secure Smart Contract library for Solidity",
|
||||
"version": "3.3.0-rc.0",
|
||||
"version": "4.0.0-beta.1",
|
||||
"files": [
|
||||
"**/*.sol",
|
||||
"/build/contracts/*.json",
|
||||
"!/mocks",
|
||||
"!/examples"
|
||||
"!/mocks/**/*"
|
||||
],
|
||||
"scripts": {
|
||||
"prepare": "bash ../scripts/prepare-contracts-package.sh",
|
||||
|
||||
@ -1,22 +0,0 @@
|
||||
= Payment
|
||||
|
||||
[.readme-notice]
|
||||
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/payment
|
||||
|
||||
Utilities related to sending and receiving payments. Examples are {PullPayment}, which implements the best security practices when sending funds to third parties, and {PaymentSplitter} to receive incoming payments among a number of beneficiaries.
|
||||
|
||||
TIP: When transferring funds to and from untrusted third parties, there is always a security risk of reentrancy. If you would like to learn more about this and ways to protect against it, check out our blog post https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
|
||||
|
||||
== Utilities
|
||||
|
||||
{{PaymentSplitter}}
|
||||
|
||||
{{PullPayment}}
|
||||
|
||||
== Escrow
|
||||
|
||||
{{Escrow}}
|
||||
|
||||
{{ConditionalEscrow}}
|
||||
|
||||
{{RefundEscrow}}
|
||||
@ -1,18 +0,0 @@
|
||||
= Presets
|
||||
|
||||
[.readme-notice]
|
||||
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/presets
|
||||
|
||||
These contracts integrate different Ethereum standards (ERCs) with custom extensions and modules, showcasing common configurations that are ready to deploy **without having to write any Solidity code**.
|
||||
|
||||
They can be used as-is for quick prototyping and testing, but are **also suitable for production environments**.
|
||||
|
||||
TIP: Intermediate and advanced users can use these as starting points when writing their own contracts, extending them with custom functionality as they see fit.
|
||||
|
||||
== Tokens
|
||||
|
||||
{{ERC20PresetMinterPauser}}
|
||||
|
||||
{{ERC721PresetMinterPauserAutoId}}
|
||||
|
||||
{{ERC1155PresetMinterPauser}}
|
||||
78
contracts/proxy/Clones.sol
Normal file
78
contracts/proxy/Clones.sol
Normal file
@ -0,0 +1,78 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
/**
|
||||
* @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
|
||||
* deploying minimal proxy contracts, also known as "clones".
|
||||
*
|
||||
* > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
|
||||
* > a minimal bytecode implementation that delegates all calls to a known, fixed address.
|
||||
*
|
||||
* The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
|
||||
* (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
|
||||
* deterministic method.
|
||||
*
|
||||
* _Available since v3.4._
|
||||
*/
|
||||
library Clones {
|
||||
/**
|
||||
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
|
||||
*
|
||||
* This function uses the create opcode, which should never revert.
|
||||
*/
|
||||
function clone(address implementation) internal returns (address instance) {
|
||||
// solhint-disable-next-line no-inline-assembly
|
||||
assembly {
|
||||
let ptr := mload(0x40)
|
||||
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
|
||||
mstore(add(ptr, 0x14), shl(0x60, implementation))
|
||||
mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
|
||||
instance := create(0, ptr, 0x37)
|
||||
}
|
||||
require(instance != address(0), "ERC1167: create failed");
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
|
||||
*
|
||||
* This function uses the create2 opcode and a `salt` to deterministically deploy
|
||||
* the clone. Using the same `implementation` and `salt` multiple time will revert, since
|
||||
* the clones cannot be deployed twice at the same address.
|
||||
*/
|
||||
function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
|
||||
// solhint-disable-next-line no-inline-assembly
|
||||
assembly {
|
||||
let ptr := mload(0x40)
|
||||
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
|
||||
mstore(add(ptr, 0x14), shl(0x60, implementation))
|
||||
mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
|
||||
instance := create2(0, ptr, 0x37, salt)
|
||||
}
|
||||
require(instance != address(0), "ERC1167: create2 failed");
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
|
||||
*/
|
||||
function predictDeterministicAddress(address implementation, bytes32 salt, address deployer) internal pure returns (address predicted) {
|
||||
// solhint-disable-next-line no-inline-assembly
|
||||
assembly {
|
||||
let ptr := mload(0x40)
|
||||
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
|
||||
mstore(add(ptr, 0x14), shl(0x60, implementation))
|
||||
mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000)
|
||||
mstore(add(ptr, 0x38), shl(0x60, deployer))
|
||||
mstore(add(ptr, 0x4c), salt)
|
||||
mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))
|
||||
predicted := keccak256(add(ptr, 0x37), 0x55)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
|
||||
*/
|
||||
function predictDeterministicAddress(address implementation, bytes32 salt) internal view returns (address predicted) {
|
||||
return predictDeterministicAddress(implementation, salt, address(this));
|
||||
}
|
||||
}
|
||||
@ -1,33 +1,31 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "./Proxy.sol";
|
||||
import "../utils/Address.sol";
|
||||
import "../Proxy.sol";
|
||||
import "../../utils/Address.sol";
|
||||
|
||||
/**
|
||||
* @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
|
||||
* implementation address that can be changed. This address is stored in storage in the location specified by
|
||||
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
|
||||
* implementation behind the proxy.
|
||||
*
|
||||
*
|
||||
* Upgradeability is only provided internally through {_upgradeTo}. For an externally upgradeable proxy see
|
||||
* {TransparentUpgradeableProxy}.
|
||||
*/
|
||||
contract UpgradeableProxy is Proxy {
|
||||
contract ERC1967Proxy is Proxy {
|
||||
/**
|
||||
* @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
|
||||
*
|
||||
*
|
||||
* If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
|
||||
* function call, and allows initializating the storage of the proxy like a Solidity constructor.
|
||||
*/
|
||||
constructor(address _logic, bytes memory _data) public payable {
|
||||
constructor(address _logic, bytes memory _data) payable {
|
||||
assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1));
|
||||
_setImplementation(_logic);
|
||||
if(_data.length > 0) {
|
||||
// solhint-disable-next-line avoid-low-level-calls
|
||||
(bool success,) = _logic.delegatecall(_data);
|
||||
require(success);
|
||||
Address.functionDelegateCall(_logic, _data);
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,7 +44,7 @@ contract UpgradeableProxy is Proxy {
|
||||
/**
|
||||
* @dev Returns the current implementation address.
|
||||
*/
|
||||
function _implementation() internal override view returns (address impl) {
|
||||
function _implementation() internal view virtual override returns (address impl) {
|
||||
bytes32 slot = _IMPLEMENTATION_SLOT;
|
||||
// solhint-disable-next-line no-inline-assembly
|
||||
assembly {
|
||||
@ -56,10 +54,10 @@ contract UpgradeableProxy is Proxy {
|
||||
|
||||
/**
|
||||
* @dev Upgrades the proxy to a new implementation.
|
||||
*
|
||||
*
|
||||
* Emits an {Upgraded} event.
|
||||
*/
|
||||
function _upgradeTo(address newImplementation) internal {
|
||||
function _upgradeTo(address newImplementation) internal virtual {
|
||||
_setImplementation(newImplementation);
|
||||
emit Upgraded(newImplementation);
|
||||
}
|
||||
@ -68,7 +66,7 @@ contract UpgradeableProxy is Proxy {
|
||||
* @dev Stores a new address in the EIP1967 implementation slot.
|
||||
*/
|
||||
function _setImplementation(address newImplementation) private {
|
||||
require(Address.isContract(newImplementation), "UpgradeableProxy: new implementation is not a contract");
|
||||
require(Address.isContract(newImplementation), "ERC1967Proxy: new implementation is not a contract");
|
||||
|
||||
bytes32 slot = _IMPLEMENTATION_SLOT;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user