Merge branch 'OpenZeppelin:master' into master

pull/3478/head
Michael D. George 3 years ago committed by GitHub
commit 1c3b17826e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      .eslintrc
  2. 4
      .github/ISSUE_TEMPLATE/config.yml
  3. 25
      .github/workflows/docs.yml
  4. 29
      .github/workflows/test.yml
  5. 5
      .gitignore
  6. 3
      .prettierrc
  7. 62
      CHANGELOG.md
  8. 2
      LICENSE
  9. 2
      README.md
  10. 24
      certora/Makefile
  11. 56
      certora/README.md
  12. 101
      certora/applyHarness.patch
  13. 28
      certora/harnesses/ERC20VotesHarness.sol
  14. 150
      certora/harnesses/WizardControlFirstPriority.sol
  15. 141
      certora/harnesses/WizardFirstTry.sol
  16. 2
      certora/munged/.gitignore
  17. 10
      certora/scripts/Governor.sh
  18. 10
      certora/scripts/GovernorCountingSimple-counting.sh
  19. 12
      certora/scripts/WizardControlFirstPriority.sh
  20. 10
      certora/scripts/WizardFirstTry.sh
  21. 14
      certora/scripts/sanity.sh
  22. 39
      certora/scripts/verifyAll.sh
  23. 334
      certora/specs/GovernorBase.spec
  24. 221
      certora/specs/GovernorCountingSimple.spec
  25. 139
      certora/specs/RulesInProgress.spec
  26. 14
      certora/specs/sanity.spec
  27. 22
      contracts/access/AccessControl.sol
  28. 6
      contracts/access/AccessControlEnumerable.sol
  29. 2
      contracts/access/IAccessControl.sol
  30. 2
      contracts/access/IAccessControlEnumerable.sol
  31. 2
      contracts/access/Ownable.sol
  32. 2
      contracts/finance/PaymentSplitter.sol
  33. 2
      contracts/finance/VestingWallet.sol
  34. 67
      contracts/governance/Governor.sol
  35. 4
      contracts/governance/IGovernor.sol
  36. 4
      contracts/governance/README.adoc
  37. 5
      contracts/governance/TimelockController.sol
  38. 4
      contracts/governance/compatibility/GovernorCompatibilityBravo.sol
  39. 2
      contracts/governance/compatibility/IGovernorCompatibilityBravo.sol
  40. 2
      contracts/governance/extensions/GovernorCountingSimple.sol
  41. 1
      contracts/governance/extensions/GovernorPreventLateQuorum.sol
  42. 2
      contracts/governance/extensions/GovernorProposalThreshold.sol
  43. 2
      contracts/governance/extensions/GovernorSettings.sol
  44. 8
      contracts/governance/extensions/GovernorTimelockCompound.sol
  45. 16
      contracts/governance/extensions/GovernorTimelockControl.sol
  46. 11
      contracts/governance/extensions/GovernorVotes.sol
  47. 2
      contracts/governance/extensions/GovernorVotesComp.sol
  48. 37
      contracts/governance/extensions/GovernorVotesQuorumFraction.sol
  49. 2
      contracts/governance/extensions/IGovernorTimelock.sol
  50. 61
      contracts/governance/utils/IVotes.sol
  51. 211
      contracts/governance/utils/Votes.sol
  52. 2
      contracts/interfaces/IERC1155.sol
  53. 2
      contracts/interfaces/IERC1155MetadataURI.sol
  54. 2
      contracts/interfaces/IERC1155Receiver.sol
  55. 2
      contracts/interfaces/IERC1271.sol
  56. 2
      contracts/interfaces/IERC1363.sol
  57. 2
      contracts/interfaces/IERC1363Receiver.sol
  58. 2
      contracts/interfaces/IERC1363Spender.sol
  59. 2
      contracts/interfaces/IERC165.sol
  60. 2
      contracts/interfaces/IERC1820Implementer.sol
  61. 2
      contracts/interfaces/IERC1820Registry.sol
  62. 2
      contracts/interfaces/IERC20.sol
  63. 2
      contracts/interfaces/IERC20Metadata.sol
  64. 18
      contracts/interfaces/IERC2981.sol
  65. 2
      contracts/interfaces/IERC3156.sol
  66. 2
      contracts/interfaces/IERC3156FlashBorrower.sol
  67. 2
      contracts/interfaces/IERC3156FlashLender.sol
  68. 2
      contracts/interfaces/IERC721.sol
  69. 2
      contracts/interfaces/IERC721Enumerable.sol
  70. 2
      contracts/interfaces/IERC721Metadata.sol
  71. 2
      contracts/interfaces/IERC721Receiver.sol
  72. 2
      contracts/interfaces/IERC777.sol
  73. 2
      contracts/interfaces/IERC777Recipient.sol
  74. 2
      contracts/interfaces/IERC777Sender.sol
  75. 2
      contracts/interfaces/README.adoc
  76. 20
      contracts/interfaces/draft-IERC1822.sol
  77. 2
      contracts/interfaces/draft-IERC2612.sol
  78. 8
      contracts/metatx/ERC2771Context.sol
  79. 12
      contracts/metatx/MinimalForwarder.sol
  80. 11
      contracts/mocks/Base64Mock.sol
  81. 7
      contracts/mocks/CallReceiverMock.sol
  82. 23
      contracts/mocks/CheckpointsImpl.sol
  83. 58
      contracts/mocks/DoubleEndedQueueMock.sol
  84. 7
      contracts/mocks/ERC2771ContextMock.sol
  85. 33
      contracts/mocks/ERC721RoyaltyMock.sol
  86. 25
      contracts/mocks/ERC721VotesMock.sol
  87. 42
      contracts/mocks/EnumerableMapMock.sol
  88. 2
      contracts/mocks/GovernorMock.sol
  89. 2
      contracts/mocks/GovernorPreventLateQuorumMock.sol
  90. 2
      contracts/mocks/GovernorTimelockCompoundMock.sol
  91. 4
      contracts/mocks/GovernorTimelockControlMock.sol
  92. 41
      contracts/mocks/GovernorVoteMock.sol
  93. 29
      contracts/mocks/InitializableMock.sol
  94. 4
      contracts/mocks/MathMock.sol
  95. 65
      contracts/mocks/MultipleInheritanceInitializableMocks.sol
  96. 2
      contracts/mocks/SafeERC20Helper.sol
  97. 23
      contracts/mocks/SignedMathMock.sol
  98. 58
      contracts/mocks/UUPS/UUPSLegacy.sol
  99. 10
      contracts/mocks/UUPS/UUPSUpgradeableMock.sol
  100. 40
      contracts/mocks/VotesMock.sol
  101. Some files were not shown because too many files have changed in this diff Show More

@ -1,11 +1,9 @@
{
"extends" : [
"standard",
"plugin:promise/recommended",
"standard"
],
"plugins": [
"mocha-no-only",
"promise",
"mocha"
],
"env": {
"browser" : true,
@ -53,7 +51,7 @@
"semi": ["error", "always"],
"space-before-function-paren": ["error", "always"],
"mocha-no-only/mocha-no-only": ["error"],
"mocha/no-exclusive-tests": ["error"],
"promise/always-return": "off",
"promise/avoid-new": "off",

@ -1,4 +1,4 @@
contact_links:
- name: Support request
- name: Questions & Support Requests
url: https://forum.openzeppelin.com/c/support/contracts/18
about: Ask the community in the Community Forum
about: Ask in the OpenZeppelin Forum

@ -0,0 +1,25 @@
name: Build Docs
on:
push:
branches: [release-v*]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v3
with:
node-version: 12.x
- uses: actions/cache@v2
id: cache
with:
path: '**/node_modules'
key: npm-v2-${{ hashFiles('**/package-lock.json') }}
restore-keys: npm-v2-
- run: npm ci
if: steps.cache.outputs.cache-hit != 'true'
- run: bash scripts/git-user-config.sh
- run: node scripts/update-docs-branch.js
- run: git push --all origin

@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
- uses: actions/setup-node@v3
with:
node-version: 12.x
- uses: actions/cache@v2
@ -29,7 +29,7 @@ jobs:
env:
FORCE_COLOR: 1
ENABLE_GAS_REPORT: true
- run: npm run test:inheritance
- run: npm run test:inheritance
- name: Print gas report
run: cat gas-report.txt
@ -39,7 +39,7 @@ jobs:
- uses: actions/checkout@v2
with:
fetch-depth: 2
- uses: actions/setup-node@v2
- uses: actions/setup-node@v3
with:
node-version: 12.x
- uses: actions/cache@v2
@ -54,3 +54,26 @@ jobs:
env:
NODE_OPTIONS: --max_old_space_size=4096
- uses: codecov/codecov-action@v2
slither:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v3
with:
node-version: 12.x
- uses: actions/cache@v2
id: cache
with:
path: '**/node_modules'
key: npm-v2-${{ hashFiles('**/package-lock.json') }}
restore-keys: npm-v2-
- run: npm ci
if: steps.cache.outputs.cache-hit != 'true'
- name: Set up Python
uses: actions/setup-python@v2
- name: Install dependencies
run: pip3 install slither-analyzer
- name: Summary of static analysis
run: npm run slither

5
.gitignore vendored

@ -57,3 +57,8 @@ allFiredEvents
# hardhat
cache
artifacts
# Certora
.certora*
.last_confs
certora_*

@ -1,8 +1,11 @@
{
"singleQuote": true,
"trailingComma": "all",
"overrides": [
{
"files": "*.sol",
"options": {
"singleQuote": false,
"printWidth": 120,
"explicitTypes": "always"
}

@ -2,11 +2,65 @@
## Unreleased
* `GovernorTimelockControl`: improve the `state()` function to have it reflect cases where a proposal has been canceled directly on the timelock. ([#2977](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2977))
* `Math`: add a `abs(int256)` method that returns the unsigned absolute value of a signed value. ([#2984](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2984))
* Preset contracts are now deprecated in favor of [Contracts Wizard](https://wizard.openzeppelin.com). ([#2986](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2986))
* `AccessControl`: add a virtual `_checkRole(bytes32)` function that can be overridden to alter the `onlyRole` modifier behavior. ([#3137](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3137))
* `EnumerableMap`: add new `AddressToUintMap` map type. ([#3150](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3150))
* `ERC1155`: Add a `_afterTokenTransfer` hook for improved extensibility. ([#3166](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3166))
* `DoubleEndedQueue`: a new data structure that supports efficient push and pop to both front and back, useful for FIFO and LIFO queues. ([#3153](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3153))
* `Governor`: improved security of `onlyGovernance` modifier when using an external executor contract (e.g. a timelock) that can operate without necessarily going through the governance protocol. ([#3147](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3147))
## 4.5.0 (2022-02-09)
* `ERC2981`: add implementation of the royalty standard, and the respective extensions for `ERC721` and `ERC1155`. ([#3012](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3012))
* `GovernorTimelockControl`: improve the `state()` function to have it reflect cases where a proposal has been canceled directly on the timelock. ([#2977](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2977))
* Preset contracts are now deprecated in favor of [Contracts Wizard](https://wizard.openzeppelin.com). ([#2986](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2986))
* `Governor`: add a relay function to help recover assets sent to a governor that is not its own executor (e.g. when using a timelock). ([#2926](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2926))
* `GovernorExtendedVoting`: add new module to ensure a minimum voting duration is available after the quorum is reached. ([#2973](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2973))
* `GovernorPreventLateQuorum`: add new module to ensure a minimum voting duration is available after the quorum is reached. ([#2973](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2973))
* `ERC721`: improved revert reason when transferring from wrong owner. ([#2975](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2975))
* `Votes`: Added a base contract for vote tracking with delegation. ([#2944](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2944))
* `ERC721Votes`: Added an extension of ERC721 enabled with vote tracking and delegation. ([#2944](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2944))
* `ERC2771Context`: use immutable storage to store the forwarder address, no longer an issue since Solidity >=0.8.8 allows reading immutable variables in the constructor. ([#2917](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2917))
* `Base64`: add a library to parse bytes into base64 strings using `encode(bytes memory)` function, and provide examples to show how to use to build URL-safe `tokenURIs`. ([#2884](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2884))
* `ERC20`: reduce allowance before triggering transfer. ([#3056](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3056))
* `ERC20`: do not update allowance on `transferFrom` when allowance is `type(uint256).max`. ([#3085](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3085))
* `ERC20`: add a `_spendAllowance` internal function. ([#3170](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3170))
* `ERC20Burnable`: do not update allowance on `burnFrom` when allowance is `type(uint256).max`. ([#3170](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3170))
* `ERC777`: do not update allowance on `transferFrom` when allowance is `type(uint256).max`. ([#3085](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3085))
* `ERC777`: add a `_spendAllowance` internal function. ([#3170](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3170))
* `SignedMath`: a new signed version of the Math library with `max`, `min`, and `average`. ([#2686](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2686))
* `SignedMath`: add a `abs(int256)` method that returns the unsigned absolute value of a signed value. ([#2984](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2984))
* `ERC1967Upgrade`: Refactor the secure upgrade to use `ERC1822` instead of the previous rollback mechanism. This reduces code complexity and attack surface with similar security guarantees. ([#3021](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3021))
* `UUPSUpgradeable`: Add `ERC1822` compliance to support the updated secure upgrade mechanism. ([#3021](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3021))
* Some more 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.
### Breaking changes
* `ERC1967Upgrade`: The function `_upgradeToAndCallSecure` was renamed to `_upgradeToAndCallUUPS`, along with the change in security mechanism described above.
* `Address`: The Solidity pragma is increased from `^0.8.0` to `^0.8.1`. This is required by the `account.code.length` syntax that replaces inline assembly. This may require users to bump their compiler version from `0.8.0` to `0.8.1` or later. Note that other parts of the code already include stricter requirements.
## 4.4.2 (2022-01-11)
### Bugfixes
* `GovernorCompatibilityBravo`: Fix error in the encoding of calldata for proposals submitted through the compatibility interface with explicit signatures. ([#3100](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3100))
## 4.4.1 (2021-12-14)
* `Initializable`: change the existing `initializer` modifier and add a new `onlyInitializing` modifier to prevent reentrancy risk. ([#3006](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3006))
### Breaking change
It is no longer possible to call an `initializer`-protected function from within another `initializer` function outside the context of a constructor. Projects using OpenZeppelin upgradeable proxies should continue to work as is, since in the common case the initializer is invoked in the constructor directly. If this is not the case for you, the suggested change is to use the new `onlyInitializing` modifier in the following way:
```diff
contract A {
- function initialize() public initializer { ... }
+ function initialize() internal onlyInitializing { ... }
}
contract B is A {
function initialize() public initializer {
A.initialize();
}
}
```
## 4.4.0 (2021-11-25)

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2016-2020 zOS Global Limited
Copyright (c) 2016-2022 zOS Global Limited and contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

@ -22,6 +22,8 @@ $ npm install @openzeppelin/contracts
OpenZeppelin Contracts features a [stable API](https://docs.openzeppelin.com/contracts/releases-stability#api-stability), which means your contracts won't break unexpectedly when upgrading to a newer minor version.
An alternative to npm is to use the GitHub repository `openzeppelin/openzeppelin-contracts` to retrieve the contracts. When doing this, make sure to specify the tag for a release such as `v4.5.0`, instead of using the `master` branch.
### Usage
Once installed, you can use the contracts in the library by importing them:

@ -0,0 +1,24 @@
default: help
PATCH = applyHarness.patch
CONTRACTS_DIR = ../contracts
MUNGED_DIR = munged
help:
@echo "usage:"
@echo " make clean: remove all generated files (those ignored by git)"
@echo " make $(MUNGED_DIR): create $(MUNGED_DIR) directory by applying the patch file to $(CONTRACTS_DIR)"
@echo " make record: record a new patch file capturing the differences between $(CONTRACTS_DIR) and $(MUNGED_DIR)"
munged: $(wildcard $(CONTRACTS_DIR)/*.sol) $(PATCH)
rm -rf $@
cp -r $(CONTRACTS_DIR) $@
patch -p0 -d $@ < $(PATCH)
record:
diff -ruN $(CONTRACTS_DIR) $(MUNGED_DIR) | sed 's+../contracts/++g' | sed 's+munged/++g' > $(PATCH)
clean:
git clean -fdX
touch $(PATCH)

@ -0,0 +1,56 @@
# Running the certora verification tool
These instructions detail the process for running CVT on the OpenZeppelin (Wizard/Governor) contracts.
Documentation for CVT and the specification language are available
[here](https://certora.atlassian.net/wiki/spaces/CPD/overview)
## Running the verification
The scripts in the `certora/scripts` directory are used to submit verification
jobs to the Certora verification service. After the job is complete, the results will be available on
[the Certora portal](https://vaas-stg.certora.com/).
These scripts should be run from the root directory; for example by running
```
sh certora/scripts/verifyAll.sh <meaningful comment>
```
The most important of these is `verifyAll.sh`, which checks
all of the harnessed contracts (`certora/harness/Wizard*.sol`) against all of
the specifications (`certora/spec/*.spec`).
The other scripts run a subset of the specifications or the contracts. You can
verify different contracts or specifications by changing the `--verify` option,
and you can run a single rule or method with the `--rule` or `--method` option.
For example, to verify the `WizardFirstPriority` contract against the
`GovernorCountingSimple` specification, you could change the `--verify` line of
the `WizardControlFirstPriortity.sh` script to:
```
--verify WizardFirstPriority:certora/specs/GovernorCountingSimple.spec \
```
## Adapting to changes in the contracts
Some of our rules require the code to be simplified in various ways. Our
primary tool for performing these simplifications is to run verification on a
contract that extends the original contracts and overrides some of the methods.
These "harness" contracts can be found in the `certora/harness` directory.
This pattern does require some modifications to the original code: some methods
need to be made virtual or public, for example. These changes are handled by
applying a patch to the code before verification.
When one of the `verify` scripts is executed, it first applies the patch file
`certora/applyHarness.patch` to the `contracts` directory, placing the output
in the `certora/munged` directory. We then verify the contracts in the
`certora/munged` directory.
If the original contracts change, it is possible to create a conflict with the
patch. In this case, the verify scripts will report an error message and output
rejected changes in the `munged` directory. After merging the changes, run
`make record` in the `certora` directory; this will regenerate the patch file,
which can then be checked into git.

@ -0,0 +1,101 @@
diff -ruN .gitignore .gitignore
--- .gitignore 1969-12-31 19:00:00.000000000 -0500
+++ .gitignore 2021-12-09 14:46:33.923637220 -0500
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff -ruN governance/compatibility/GovernorCompatibilityBravo.sol governance/compatibility/GovernorCompatibilityBravo.sol
--- governance/compatibility/GovernorCompatibilityBravo.sol 2021-12-03 15:24:56.523654357 -0500
+++ governance/compatibility/GovernorCompatibilityBravo.sol 2021-12-09 14:46:33.923637220 -0500
@@ -245,7 +245,7 @@
/**
* @dev See {Governor-_quorumReached}. In this module, only forVotes count toward the quorum.
*/
- function _quorumReached(uint256 proposalId) internal view virtual override returns (bool) {
+ function _quorumReached(uint256 proposalId) public view virtual override returns (bool) { // HARNESS: changed to public from internal
ProposalDetails storage details = _proposalDetails[proposalId];
return quorum(proposalSnapshot(proposalId)) <= details.forVotes;
}
@@ -253,7 +253,7 @@
/**
* @dev See {Governor-_voteSucceeded}. In this module, the forVotes must be scritly over the againstVotes.
*/
- function _voteSucceeded(uint256 proposalId) internal view virtual override returns (bool) {
+ function _voteSucceeded(uint256 proposalId) public view virtual override returns (bool) { // HARNESS: changed to public from internal
ProposalDetails storage details = _proposalDetails[proposalId];
return details.forVotes > details.againstVotes;
}
diff -ruN governance/extensions/GovernorCountingSimple.sol governance/extensions/GovernorCountingSimple.sol
--- governance/extensions/GovernorCountingSimple.sol 2021-12-03 15:24:56.523654357 -0500
+++ governance/extensions/GovernorCountingSimple.sol 2021-12-09 14:46:33.923637220 -0500
@@ -64,7 +64,7 @@
/**
* @dev See {Governor-_quorumReached}.
*/
- function _quorumReached(uint256 proposalId) internal view virtual override returns (bool) {
+ function _quorumReached(uint256 proposalId) public view virtual override returns (bool) {
ProposalVote storage proposalvote = _proposalVotes[proposalId];
return quorum(proposalSnapshot(proposalId)) <= proposalvote.forVotes + proposalvote.abstainVotes;
@@ -73,7 +73,7 @@
/**
* @dev See {Governor-_voteSucceeded}. In this module, the forVotes must be strictly over the againstVotes.
*/
- function _voteSucceeded(uint256 proposalId) internal view virtual override returns (bool) {
+ function _voteSucceeded(uint256 proposalId) public view virtual override returns (bool) {
ProposalVote storage proposalvote = _proposalVotes[proposalId];
return proposalvote.forVotes > proposalvote.againstVotes;
diff -ruN governance/extensions/GovernorTimelockControl.sol governance/extensions/GovernorTimelockControl.sol
--- governance/extensions/GovernorTimelockControl.sol 2021-12-03 15:24:56.523654357 -0500
+++ governance/extensions/GovernorTimelockControl.sol 2021-12-09 14:46:33.923637220 -0500
@@ -111,7 +111,7 @@
bytes[] memory calldatas,
bytes32 descriptionHash
) internal virtual override {
- _timelock.executeBatch{value: msg.value}(targets, values, calldatas, 0, descriptionHash);
+ _timelock.executeBatch{value: msg.value}(targets, values, calldatas, 0, descriptionHash);
}
/**
diff -ruN governance/Governor.sol governance/Governor.sol
--- governance/Governor.sol 2021-12-03 15:24:56.523654357 -0500
+++ governance/Governor.sol 2021-12-09 14:46:56.411503587 -0500
@@ -38,8 +38,8 @@
string private _name;
- mapping(uint256 => ProposalCore) private _proposals;
-
+ mapping(uint256 => ProposalCore) public _proposals;
+
/**
* @dev Restrict access to governor executing address. Some module might override the _executor function to make
* sure this modifier is consistant with the execution model.
@@ -167,12 +167,12 @@
/**
* @dev Amount of votes already cast passes the threshold limit.
*/
- function _quorumReached(uint256 proposalId) internal view virtual returns (bool);
+ function _quorumReached(uint256 proposalId) public view virtual returns (bool); // HARNESS: changed to public from internal
/**
* @dev Is the proposal successful or not.
*/
- function _voteSucceeded(uint256 proposalId) internal view virtual returns (bool);
+ function _voteSucceeded(uint256 proposalId) public view virtual returns (bool); // HARNESS: changed to public from internal
/**
* @dev Register a vote with a given support and voting weight.
diff -ruN token/ERC20/extensions/ERC20Votes.sol token/ERC20/extensions/ERC20Votes.sol
--- token/ERC20/extensions/ERC20Votes.sol 2021-12-03 15:24:56.527654330 -0500
+++ token/ERC20/extensions/ERC20Votes.sol 2021-12-09 14:46:33.927637196 -0500
@@ -84,7 +84,7 @@
*
* - `blockNumber` must have been already mined
*/
- function getPastVotes(address account, uint256 blockNumber) public view returns (uint256) {
+ function getPastVotes(address account, uint256 blockNumber) public view virtual returns (uint256) {
require(blockNumber < block.number, "ERC20Votes: block not yet mined");
return _checkpointsLookup(_checkpoints[account], blockNumber);
}

@ -0,0 +1,28 @@
import "../munged/token/ERC20/extensions/ERC20Votes.sol";
contract ERC20VotesHarness is ERC20Votes {
constructor(string memory name, string memory symbol) ERC20Permit(name) ERC20(name, symbol) {}
mapping(address => mapping(uint256 => uint256)) public _getPastVotes;
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual override {
super._afterTokenTransfer(from, to, amount);
_getPastVotes[from][block.number] -= amount;
_getPastVotes[to][block.number] += amount;
}
/**
* @dev Change delegation for `delegator` to `delegatee`.
*
* Emits events {DelegateChanged} and {DelegateVotesChanged}.
*/
function _delegate(address delegator, address delegatee) internal virtual override{
super._delegate(delegator, delegatee);
_getPastVotes[delegator][block.number] -= balanceOf(delegator);
_getPastVotes[delegatee][block.number] += balanceOf(delegator);
}
}

@ -0,0 +1,150 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;
import "../munged/governance/Governor.sol";
import "../munged/governance/extensions/GovernorCountingSimple.sol";
import "../munged/governance/extensions/GovernorVotes.sol";
import "../munged/governance/extensions/GovernorVotesQuorumFraction.sol";
import "../munged/governance/extensions/GovernorTimelockControl.sol";
import "../munged/governance/extensions/GovernorProposalThreshold.sol";
/*
Wizard options:
ProposalThreshhold = 10
ERC20Votes
TimelockController
*/
contract WizardControlFirstPriority is Governor, GovernorProposalThreshold, GovernorCountingSimple, GovernorVotes, GovernorVotesQuorumFraction, GovernorTimelockControl {
constructor(ERC20Votes _token, TimelockController _timelock, string memory name, uint256 quorumFraction)
Governor(name)
GovernorVotes(_token)
GovernorVotesQuorumFraction(quorumFraction)
GovernorTimelockControl(_timelock)
{}
//HARNESS
function isExecuted(uint256 proposalId) public view returns (bool) {
return _proposals[proposalId].executed;
}
function isCanceled(uint256 proposalId) public view returns (bool) {
return _proposals[proposalId].canceled;
}
uint256 _votingDelay;
uint256 _votingPeriod;
uint256 _proposalThreshold;
mapping(uint256 => uint256) public ghost_sum_vote_power_by_id;
function _castVote(
uint256 proposalId,
address account,
uint8 support,
string memory reason
) internal override virtual returns (uint256) {
uint256 deltaWeight = super._castVote(proposalId, account, support, reason); //HARNESS
ghost_sum_vote_power_by_id[proposalId] += deltaWeight;
return deltaWeight;
}
function snapshot(uint256 proposalId) public view returns (uint64) {
return _proposals[proposalId].voteStart._deadline;
}
function getExecutor() public view returns (address){
return _executor();
}
// original code, harnessed
function votingDelay() public view override returns (uint256) { // HARNESS: pure -> view
return _votingDelay; // HARNESS: parametric
}
function votingPeriod() public view override returns (uint256) { // HARNESS: pure -> view
return _votingPeriod; // HARNESS: parametric
}
function proposalThreshold() public view override returns (uint256) { // HARNESS: pure -> view
return _proposalThreshold; // HARNESS: parametric
}
// original code, not harnessed
// The following functions are overrides required by Solidity.
function quorum(uint256 blockNumber)
public
view
override(IGovernor, GovernorVotesQuorumFraction)
returns (uint256)
{
return super.quorum(blockNumber);
}
function getVotes(address account, uint256 blockNumber)
public
view
override(IGovernor, GovernorVotes)
returns (uint256)
{
return super.getVotes(account, blockNumber);
}
function state(uint256 proposalId)
public
view
override(Governor, GovernorTimelockControl)
returns (ProposalState)
{
return super.state(proposalId);
}
function propose(address[] memory targets, uint256[] memory values, bytes[] memory calldatas, string memory description)
public
override(Governor, GovernorProposalThreshold, IGovernor)
returns (uint256)
{
return super.propose(targets, values, calldatas, description);
}
function _execute(uint256 proposalId, address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash)
internal
override(Governor, GovernorTimelockControl)
{
super._execute(proposalId, targets, values, calldatas, descriptionHash);
}
function _cancel(address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash)
internal
override(Governor, GovernorTimelockControl)
returns (uint256)
{
return super._cancel(targets, values, calldatas, descriptionHash);
}
function _executor()
internal
view
override(Governor, GovernorTimelockControl)
returns (address)
{
return super._executor();
}
function supportsInterface(bytes4 interfaceId)
public
view
override(Governor, GovernorTimelockControl)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
}

@ -0,0 +1,141 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;
import "../munged/governance/Governor.sol";
import "../munged/governance/extensions/GovernorCountingSimple.sol";
import "../munged/governance/extensions/GovernorVotes.sol";
import "../munged/governance/extensions/GovernorVotesQuorumFraction.sol";
import "../munged/governance/extensions/GovernorTimelockCompound.sol";
/*
Wizard options:
ERC20Votes
TimelockCompound
*/
contract WizardFirstTry is Governor, GovernorCountingSimple, GovernorVotes, GovernorVotesQuorumFraction, GovernorTimelockCompound {
constructor(ERC20Votes _token, ICompoundTimelock _timelock, string memory name, uint256 quorumFraction)
Governor(name)
GovernorVotes(_token)
GovernorVotesQuorumFraction(quorumFraction)
GovernorTimelockCompound(_timelock)
{}
//HARNESS
function isExecuted(uint256 proposalId) public view returns (bool) {
return _proposals[proposalId].executed;
}
function isCanceled(uint256 proposalId) public view returns (bool) {
return _proposals[proposalId].canceled;
}
function snapshot(uint256 proposalId) public view returns (uint64) {
return _proposals[proposalId].voteStart._deadline;
}
function getExecutor() public view returns (address){
return _executor();
}
uint256 _votingDelay;
uint256 _votingPeriod;
mapping(uint256 => uint256) public ghost_sum_vote_power_by_id;
function _castVote(
uint256 proposalId,
address account,
uint8 support,
string memory reason
) internal override virtual returns (uint256) {
uint256 deltaWeight = super._castVote(proposalId, account, support, reason); //HARNESS
ghost_sum_vote_power_by_id[proposalId] += deltaWeight;
return deltaWeight;
}
// original code, harnessed
function votingDelay() public view override virtual returns (uint256) { // HARNESS: pure -> view
return _votingDelay; // HARNESS: parametric
}
function votingPeriod() public view override virtual returns (uint256) { // HARNESS: pure -> view
return _votingPeriod; // HARNESS: parametric
}
// original code, not harnessed
// The following functions are overrides required by Solidity.
function quorum(uint256 blockNumber)
public
view
override(IGovernor, GovernorVotesQuorumFraction)
returns (uint256)
{
return super.quorum(blockNumber);
}
function getVotes(address account, uint256 blockNumber)
public
view
override(IGovernor, GovernorVotes)
returns (uint256)
{
return super.getVotes(account, blockNumber);
}
function state(uint256 proposalId)
public
view
override(Governor, GovernorTimelockCompound)
returns (ProposalState)
{
return super.state(proposalId);
}
function propose(address[] memory targets, uint256[] memory values, bytes[] memory calldatas, string memory description)
public
override(Governor, IGovernor)
returns (uint256)
{
return super.propose(targets, values, calldatas, description);
}
function _execute(uint256 proposalId, address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash)
internal
override(Governor, GovernorTimelockCompound)
{
super._execute(proposalId, targets, values, calldatas, descriptionHash);
}
function _cancel(address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash)
internal
override(Governor, GovernorTimelockCompound)
returns (uint256)
{
return super._cancel(targets, values, calldatas, descriptionHash);
}
function _executor()
internal
view
override(Governor, GovernorTimelockCompound)
returns (address)
{
return super._executor();
}
function supportsInterface(bytes4 interfaceId)
public
view
override(Governor, GovernorTimelockCompound)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
}

@ -0,0 +1,2 @@
*
!.gitignore

@ -0,0 +1,10 @@
make -C certora munged
certoraRun certora/harnesses/ERC20VotesHarness.sol certora/harnesses/GovernorHarness.sol \
--verify GovernorHarness:certora/specs/GovernorBase.spec \
--solc solc8.0 \
--staging shelly/forSasha \
--optimistic_loop \
--settings -copyLoopUnroll=4 \
--rule voteStartBeforeVoteEnd \
--msg "$1"

@ -0,0 +1,10 @@
make -C certora munged
certoraRun certora/harnesses/ERC20VotesHarness.sol certora/harnesses/GovernorBasicHarness.sol \
--verify GovernorBasicHarness:certora/specs/GovernorCountingSimple.spec \
--solc solc8.2 \
--staging shelly/forSasha \
--optimistic_loop \
--settings -copyLoopUnroll=4 \
--rule hasVotedCorrelation \
--msg "$1"

@ -0,0 +1,12 @@
make -C certora munged
certoraRun certora/harnesses/ERC20VotesHarness.sol certora/harnesses/WizardControlFirstPriority.sol \
--link WizardControlFirstPriority:token=ERC20VotesHarness \
--verify WizardControlFirstPriority:certora/specs/GovernorBase.spec \
--solc solc8.2 \
--disableLocalTypeChecking \
--staging shelly/forSasha \
--optimistic_loop \
--settings -copyLoopUnroll=4 \
--rule canVoteDuringVotingPeriod \
--msg "$1"

@ -0,0 +1,10 @@
make -C certora munged
certoraRun certora/harnesses/ERC20VotesHarness.sol certora/harnesses/WizardFirstTry.sol \
--verify WizardFirstTry:certora/specs/GovernorBase.spec \
--solc solc8.2 \
--staging shelly/forSasha \
--optimistic_loop \
--disableLocalTypeChecking \
--settings -copyLoopUnroll=4 \
--msg "$1"

@ -0,0 +1,14 @@
make -C certora munged
for f in certora/harnesses/Wizard*.sol
do
echo "Processing $f"
file=$(basename $f)
echo ${file%.*}
certoraRun certora/harnesses/$file \
--verify ${file%.*}:certora/specs/sanity.spec "$@" \
--solc solc8.2 --staging shelly/forSasha \
--optimistic_loop \
--msg "checking sanity on ${file%.*}"
--settings -copyLoopUnroll=4
done

@ -0,0 +1,39 @@
#!/bin/bash
make -C certora munged
for contract in certora/harnesses/Wizard*.sol;
do
for spec in certora/specs/*.spec;
do
contractFile=$(basename $contract)
specFile=$(basename $spec)
if [[ "${specFile%.*}" != "RulesInProgress" ]];
then
echo "Processing ${contractFile%.*} with $specFile"
if [[ "${contractFile%.*}" = *"WizardControl"* ]];
then
certoraRun certora/harnesses/ERC20VotesHarness.sol certora/harnesses/$contractFile \
--link ${contractFile%.*}:token=ERC20VotesHarness \
--verify ${contractFile%.*}:certora/specs/$specFile "$@" \
--solc solc8.2 \
--staging shelly/forSasha \
--disableLocalTypeChecking \
--optimistic_loop \
--settings -copyLoopUnroll=4 \
--send_only \
--msg "checking $specFile on ${contractFile%.*}"
else
certoraRun certora/harnesses/ERC20VotesHarness.sol certora/harnesses/$contractFile \
--verify ${contractFile%.*}:certora/specs/$specFile "$@" \
--solc solc8.2 \
--staging shelly/forSasha \
--disableLocalTypeChecking \
--optimistic_loop \
--settings -copyLoopUnroll=4 \
--send_only \
--msg "checking $specFile on ${contractFile%.*}"
fi
fi
done
done

@ -0,0 +1,334 @@
//////////////////////////////////////////////////////////////////////////////
///////////////////// Governor.sol base definitions //////////////////////////
//////////////////////////////////////////////////////////////////////////////
using ERC20VotesHarness as erc20votes
methods {
proposalSnapshot(uint256) returns uint256 envfree // matches proposalVoteStart
proposalDeadline(uint256) returns uint256 envfree // matches proposalVoteEnd
hashProposal(address[],uint256[],bytes[],bytes32) returns uint256 envfree
isExecuted(uint256) returns bool envfree
isCanceled(uint256) returns bool envfree
execute(address[], uint256[], bytes[], bytes32) returns uint256
hasVoted(uint256, address) returns bool
castVote(uint256, uint8) returns uint256
updateQuorumNumerator(uint256)
queue(address[], uint256[], bytes[], bytes32) returns uint256
// internal functions made public in harness:
_quorumReached(uint256) returns bool
_voteSucceeded(uint256) returns bool envfree
// function summarization
proposalThreshold() returns uint256 envfree
getVotes(address, uint256) returns uint256 => DISPATCHER(true)
getPastTotalSupply(uint256 t) returns uint256 => PER_CALLEE_CONSTANT
getPastVotes(address a, uint256 t) returns uint256 => PER_CALLEE_CONSTANT
//scheduleBatch(address[],uint256[],bytes[],bytes32,bytes32,uint256) => DISPATCHER(true)
//executeBatch(address[], uint256[], bytes[], bytes32, bytes32) => DISPATCHER(true)
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////// Definitions /////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// proposal was created - relation proved in noStartBeforeCreation
definition proposalCreated(uint256 pId) returns bool = proposalSnapshot(pId) > 0;
//////////////////////////////////////////////////////////////////////////////
///////////////////////////// Helper Functions ///////////////////////////////
//////////////////////////////////////////////////////////////////////////////
function helperFunctionsWithRevert(uint256 proposalId, method f, env e) {
address[] targets; uint256[] values; bytes[] calldatas; string reason; bytes32 descriptionHash;
uint8 support; uint8 v; bytes32 r; bytes32 s;
if (f.selector == propose(address[], uint256[], bytes[], string).selector) {
uint256 result = propose@withrevert(e, targets, values, calldatas, reason);
require(result == proposalId);
} else if (f.selector == execute(address[], uint256[], bytes[], bytes32).selector) {
uint256 result = execute@withrevert(e, targets, values, calldatas, descriptionHash);
require(result == proposalId);
} else if (f.selector == castVote(uint256, uint8).selector) {
castVote@withrevert(e, proposalId, support);
} else if (f.selector == castVoteWithReason(uint256, uint8, string).selector) {
castVoteWithReason@withrevert(e, proposalId, support, reason);
} else if (f.selector == castVoteBySig(uint256, uint8,uint8, bytes32, bytes32).selector) {
castVoteBySig@withrevert(e, proposalId, support, v, r, s);
} else if (f.selector == queue(address[], uint256[], bytes[], bytes32).selector) {
queue@withrevert(e, targets, values, calldatas, descriptionHash);
} else {
calldataarg args;
f@withrevert(e, args);
}
}
/*
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////// State Diagram //////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// castVote(s)() //
// ------------- propose() ---------------------- time pass --------------- time passes ----------- //
// | No Proposal | --------> | Before Start (Delay) | --------> | Voting Period | ----------------------> | execute() | //
// ------------- ---------------------- --------------- -> Executed/Canceled ----------- //
// ------------------------------------------------------------|---------------|-------------------------|--------------> //
// t start end timelock //
// //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
*/
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////// Global Valid States /////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
/*
* Start and end date are either initialized (non zero) or uninitialized (zero) simultaneously
* This invariant assumes that the block number cannot be 0 at any stage of the contract cycle
* This is very safe assumption as usually the 0 block is genesis block which is uploaded with data
* by the developers and will not be valid to raise proposals (at the current way that block chain is functioning)
*/
// To use env with general preserved block disable type checking [--disableLocalTypeChecking]
invariant startAndEndDatesNonZero(uint256 pId)
proposalSnapshot(pId) != 0 <=> proposalDeadline(pId) != 0
{ preserved with (env e){
require e.block.number > 0;
}}
/*
* If a proposal is canceled it must have a start and an end date
*/
// To use env with general preserved block disable type checking [--disableLocalTypeChecking]
invariant canceledImplyStartAndEndDateNonZero(uint pId)
isCanceled(pId) => proposalSnapshot(pId) != 0
{preserved with (env e){
require e.block.number > 0;
}}
/*
* If a proposal is executed it must have a start and an end date
*/
// To use env with general preserved block disable type checking [--disableLocalTypeChecking]
invariant executedImplyStartAndEndDateNonZero(uint pId)
isExecuted(pId) => proposalSnapshot(pId) != 0
{ preserved with (env e){
requireInvariant startAndEndDatesNonZero(pId);
require e.block.number > 0;
}}
/*
* A proposal starting block number must be less or equal than the proposal end date
*/
invariant voteStartBeforeVoteEnd(uint256 pId)
// from < to <= because snapshot and deadline can be the same block number if delays are set to 0
// This is possible before the integration of GovernorSettings.sol to the system.
// After integration of GovernorSettings.sol the invariant expression should be changed from <= to <
(proposalSnapshot(pId) > 0 => proposalSnapshot(pId) <= proposalDeadline(pId))
// (proposalSnapshot(pId) > 0 => proposalSnapshot(pId) <= proposalDeadline(pId))
{ preserved {
requireInvariant startAndEndDatesNonZero(pId);
}}
/*
* A proposal cannot be both executed and canceled simultaneously.
*/
invariant noBothExecutedAndCanceled(uint256 pId)
!isExecuted(pId) || !isCanceled(pId)
/*
* A proposal could be executed only if quorum was reached and vote succeeded
*/
rule executionOnlyIfQuoromReachedAndVoteSucceeded(uint256 pId, env e, method f){
bool isExecutedBefore = isExecuted(pId);
bool quorumReachedBefore = _quorumReached(e, pId);
bool voteSucceededBefore = _voteSucceeded(pId);
calldataarg args;
f(e, args);
bool isExecutedAfter = isExecuted(pId);
assert (!isExecutedBefore && isExecutedAfter) => (quorumReachedBefore && voteSucceededBefore), "quorum was changed";
}
///////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////// In-State Rules /////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
//==========================================
//------------- Voting Period --------------
//==========================================
/*
* A user cannot vote twice
*/
// Checked for castVote only. all 3 castVote functions call _castVote, so the completness of the verification is counted on
// the fact that the 3 functions themselves makes no chages, but rather call an internal function to execute.
// That means that we do not check those 3 functions directly, however for castVote & castVoteWithReason it is quite trivial
// to understand why this is ok. For castVoteBySig we basically assume that the signature referendum is correct without checking it.
// We could check each function seperately and pass the rule, but that would have uglyfied the code with no concrete
// benefit, as it is evident that nothing is happening in the first 2 functions (calling a view function), and we do not desire to check the signature verification.
rule doubleVoting(uint256 pId, uint8 sup, method f) {
env e;
address user = e.msg.sender;
bool votedCheck = hasVoted(e, pId, user);
castVote@withrevert(e, pId, sup);
assert votedCheck => lastReverted, "double voting accured";
}
///////////////////////////////////////////////////////////////////////////////////////
//////////////////////////// State Transitions Rules //////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
//===========================================
//-------- Propose() --> End of Time --------
//===========================================
/*
* Once a proposal is created, voteStart and voteEnd are immutable
*/
rule immutableFieldsAfterProposalCreation(uint256 pId, method f) {
uint256 _voteStart = proposalSnapshot(pId);
uint256 _voteEnd = proposalDeadline(pId);
require proposalCreated(pId); // startDate > 0
env e; calldataarg arg;
f(e, arg);
uint256 voteStart_ = proposalSnapshot(pId);
uint256 voteEnd_ = proposalDeadline(pId);
assert _voteStart == voteStart_, "Start date was changed";
assert _voteEnd == voteEnd_, "End date was changed";
}
/*
* Voting cannot start at a block number prior to proposal’s creation block number
*/
rule noStartBeforeCreation(uint256 pId) {
uint256 previousStart = proposalSnapshot(pId);
// This line makes sure that we see only cases where start date is changed from 0, i.e. creation of proposal
// We proved in immutableFieldsAfterProposalCreation that once dates set for proposal, it cannot be changed
require !proposalCreated(pId); // previousStart == 0;
env e; calldataarg args;
propose(e, args);
uint256 newStart = proposalSnapshot(pId);
// if created, start is after current block number (creation block)
assert(newStart != previousStart => newStart >= e.block.number);
}
//============================================
//--- End of Voting Period --> End of Time ---
//============================================
/*
* A proposal can neither be executed nor canceled before it ends
*/
// By induction it cannot be executed nor canceled before it starts, due to voteStartBeforeVoteEnd
rule noExecuteOrCancelBeforeDeadline(uint256 pId, method f){
require !isExecuted(pId) && !isCanceled(pId);
env e; calldataarg args;
f(e, args);
assert e.block.number < proposalDeadline(pId) => (!isExecuted(pId) && !isCanceled(pId)), "executed/cancelled before deadline";
}
////////////////////////////////////////////////////////////////////////////////
////////////////////// Integrity Of Functions (Unit Tests) /////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////// High Level Rules ////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
///////////////////////////// Not Categorized Yet //////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/*
* All proposal specific (non-view) functions should revert if proposal is executed
*/
// In this rule we show that if a function is executed, i.e. execute() was called on the proposal ID,
// non of the proposal specific functions can make changes again. In executedOnlyAfterExecuteFunc
// we connected the executed attribute to the execute() function, showing that only execute() can
// change it, and that it will always change it.
rule allFunctionsRevertIfExecuted(method f) filtered { f ->
!f.isView && !f.isFallback
&& f.selector != updateTimelock(address).selector
&& f.selector != updateQuorumNumerator(uint256).selector
&& f.selector != queue(address[],uint256[],bytes[],bytes32).selector
&& f.selector != relay(address,uint256,bytes).selector
&& f.selector != 0xb9a61961 // __acceptAdmin()
} {
env e; calldataarg args;
uint256 pId;
require(isExecuted(pId));
requireInvariant noBothExecutedAndCanceled(pId);
requireInvariant executedImplyStartAndEndDateNonZero(pId);
helperFunctionsWithRevert(pId, f, e);
assert(lastReverted, "Function was not reverted");
}
/*
* All proposal specific (non-view) functions should revert if proposal is canceled
*/
rule allFunctionsRevertIfCanceled(method f) filtered {
f -> !f.isView && !f.isFallback
&& f.selector != updateTimelock(address).selector
&& f.selector != updateQuorumNumerator(uint256).selector
&& f.selector != queue(address[],uint256[],bytes[],bytes32).selector
&& f.selector != relay(address,uint256,bytes).selector
&& f.selector != 0xb9a61961 // __acceptAdmin()
} {
env e; calldataarg args;
uint256 pId;
require(isCanceled(pId));
requireInvariant noBothExecutedAndCanceled(pId);
requireInvariant canceledImplyStartAndEndDateNonZero(pId);
helperFunctionsWithRevert(pId, f, e);
assert(lastReverted, "Function was not reverted");
}
/*
* Proposal can be switched to executed only via execute() function
*/
rule executedOnlyAfterExecuteFunc(address[] targets, uint256[] values, bytes[] calldatas, bytes32 descriptionHash, method f) {
env e; calldataarg args;
uint256 pId;
bool executedBefore = isExecuted(pId);
require(!executedBefore);
helperFunctionsWithRevert(pId, f, e);
bool executedAfter = isExecuted(pId);
assert(executedAfter != executedBefore => f.selector == execute(address[], uint256[], bytes[], bytes32).selector, "isExecuted only changes in the execute method");
}

@ -0,0 +1,221 @@
import "GovernorBase.spec"
using ERC20VotesHarness as erc20votes
methods {
ghost_sum_vote_power_by_id(uint256) returns uint256 envfree
quorum(uint256) returns uint256
proposalVotes(uint256) returns (uint256, uint256, uint256) envfree
quorumNumerator() returns uint256
_executor() returns address
erc20votes._getPastVotes(address, uint256) returns uint256
getExecutor() returns address
timelock() returns address
}
//////////////////////////////////////////////////////////////////////////////
///////////////////////////////// GHOSTS /////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////// ghosts to keep track of votes counting ////////////
/*
* the sum of voting power of those who voted
*/
ghost sum_all_votes_power() returns uint256 {
init_state axiom sum_all_votes_power() == 0;
}
hook Sstore ghost_sum_vote_power_by_id [KEY uint256 pId] uint256 current_power(uint256 old_power) STORAGE {
havoc sum_all_votes_power assuming sum_all_votes_power@new() == sum_all_votes_power@old() - old_power + current_power;
}
/*
* sum of all votes casted per proposal
*/
ghost tracked_weight(uint256) returns uint256 {
init_state axiom forall uint256 p. tracked_weight(p) == 0;
}
/*
* sum of all votes casted
*/
ghost sum_tracked_weight() returns uint256 {
init_state axiom sum_tracked_weight() == 0;
}
/*
* getter for _proposalVotes.againstVotes
*/
ghost votesAgainst() returns uint256 {
init_state axiom votesAgainst() == 0;
}
/*
* getter for _proposalVotes.forVotes
*/
ghost votesFor() returns uint256 {
init_state axiom votesFor() == 0;
}
/*
* getter for _proposalVotes.abstainVotes
*/
ghost votesAbstain() returns uint256 {
init_state axiom votesAbstain() == 0;
}
hook Sstore _proposalVotes [KEY uint256 pId].againstVotes uint256 votes(uint256 old_votes) STORAGE {
havoc tracked_weight assuming forall uint256 p.(p == pId => tracked_weight@new(p) == tracked_weight@old(p) - old_votes + votes) &&
(p != pId => tracked_weight@new(p) == tracked_weight@old(p));
havoc sum_tracked_weight assuming sum_tracked_weight@new() == sum_tracked_weight@old() - old_votes + votes;
havoc votesAgainst assuming votesAgainst@new() == votesAgainst@old() - old_votes + votes;
}
hook Sstore _proposalVotes [KEY uint256 pId].forVotes uint256 votes(uint256 old_votes) STORAGE {
havoc tracked_weight assuming forall uint256 p.(p == pId => tracked_weight@new(p) == tracked_weight@old(p) - old_votes + votes) &&
(p != pId => tracked_weight@new(p) == tracked_weight@old(p));
havoc sum_tracked_weight assuming sum_tracked_weight@new() == sum_tracked_weight@old() - old_votes + votes;
havoc votesFor assuming votesFor@new() == votesFor@old() - old_votes + votes;
}
hook Sstore _proposalVotes [KEY uint256 pId].abstainVotes uint256 votes(uint256 old_votes) STORAGE {
havoc tracked_weight assuming forall uint256 p.(p == pId => tracked_weight@new(p) == tracked_weight@old(p) - old_votes + votes) &&
(p != pId => tracked_weight@new(p) == tracked_weight@old(p));
havoc sum_tracked_weight assuming sum_tracked_weight@new() == sum_tracked_weight@old() - old_votes + votes;
havoc votesAbstain assuming votesAbstain@new() == votesAbstain@old() - old_votes + votes;
}
//////////////////////////////////////////////////////////////////////////////
////////////////////////////// INVARIANTS ////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
/*
* sum of all votes casted is equal to the sum of voting power of those who voted, per each proposal
*/
invariant SumOfVotesCastEqualSumOfPowerOfVotedPerProposal(uint256 pId)
tracked_weight(pId) == ghost_sum_vote_power_by_id(pId)
/*
* sum of all votes casted is equal to the sum of voting power of those who voted
*/
invariant SumOfVotesCastEqualSumOfPowerOfVoted()
sum_tracked_weight() == sum_all_votes_power()
/*
* sum of all votes casted is greater or equal to the sum of voting power of those who voted at a specific proposal
*/
invariant OneIsNotMoreThanAll(uint256 pId)
sum_all_votes_power() >= tracked_weight(pId)
//////////////////////////////////////////////////////////////////////////////
///////////////////////////////// RULES //////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
/*
* Only sender's voting status can be changed by execution of any cast vote function
*/
// Checked for castVote only. all 3 castVote functions call _castVote, so the completness of the verification is counted on
// the fact that the 3 functions themselves makes no chages, but rather call an internal function to execute.
// That means that we do not check those 3 functions directly, however for castVote & castVoteWithReason it is quite trivial
// to understand why this is ok. For castVoteBySig we basically assume that the signature referendum is correct without checking it.
// We could check each function seperately and pass the rule, but that would have uglyfied the code with no concrete
// benefit, as it is evident that nothing is happening in the first 2 functions (calling a view function), and we do not desire to check the signature verification.
rule noVoteForSomeoneElse(uint256 pId, uint8 sup, method f) {
env e; calldataarg args;
address voter = e.msg.sender;
address user;
bool hasVotedBefore_User = hasVoted(e, pId, user);
castVote@withrevert(e, pId, sup);
require(!lastReverted);
bool hasVotedAfter_User = hasVoted(e, pId, user);
assert user != voter => hasVotedBefore_User == hasVotedAfter_User;
}
/*
* Total voting tally is monotonically non-decreasing in every operation
*/
rule votingWeightMonotonicity(method f){
uint256 votingWeightBefore = sum_tracked_weight();
env e;
calldataarg args;
f(e, args);
uint256 votingWeightAfter = sum_tracked_weight();
assert votingWeightBefore <= votingWeightAfter, "Voting weight was decreased somehow";
}
/*
* A change in hasVoted must be correlated with an non-decreasing of the vote supports (nondecrease because user can vote with weight 0)
*/
rule hasVotedCorrelation(uint256 pId, method f, env e, uint256 bn) {
address acc = e.msg.sender;
uint256 againstBefore = votesAgainst();
uint256 forBefore = votesFor();
uint256 abstainBefore = votesAbstain();
bool hasVotedBefore = hasVoted(e, pId, acc);
helperFunctionsWithRevert(pId, f, e);
require(!lastReverted);
uint256 againstAfter = votesAgainst();
uint256 forAfter = votesFor();
uint256 abstainAfter = votesAbstain();
bool hasVotedAfter = hasVoted(e, pId, acc);
assert (!hasVotedBefore && hasVotedAfter) => againstBefore <= againstAfter || forBefore <= forAfter || abstainBefore <= abstainAfter, "no correlation";
}
/*
* Only privileged users can execute privileged operations, e.g. change _quorumNumerator or _timelock
*/
rule privilegedOnlyNumerator(method f, uint256 newQuorumNumerator){
env e;
calldataarg arg;
uint256 quorumNumBefore = quorumNumerator(e);
f(e, arg);
uint256 quorumNumAfter = quorumNumerator(e);
address executorCheck = getExecutor(e);
assert quorumNumBefore != quorumNumAfter => e.msg.sender == executorCheck, "non priveleged user changed quorum numerator";
}
rule privilegedOnlyTimelock(method f, uint256 newQuorumNumerator){
env e;
calldataarg arg;
uint256 timelockBefore = timelock(e);
f(e, arg);
uint256 timelockAfter = timelock(e);
assert timelockBefore != timelockAfter => e.msg.sender == timelockBefore, "non priveleged user changed timelock";
}

@ -0,0 +1,139 @@
//////////////////////////////////////////////////////////////////////////////
////////////// THIS SPEC IS A RESERVE FOR NOT IN PROGRESS //////////////
//////////////////////////////////////////////////////////////////////////////
import "GovernorBase.spec"
using ERC20VotesHarness as erc20votes
methods {
ghost_sum_vote_power_by_id(uint256) returns uint256 envfree
quorum(uint256) returns uint256
proposalVotes(uint256) returns (uint256, uint256, uint256) envfree
quorumNumerator() returns uint256
_executor() returns address
erc20votes._getPastVotes(address, uint256) returns uint256
getExecutor() returns address
timelock() returns address
}
//////////////////////////////////////////////////////////////////////////////
///////////////////////////////// GHOSTS /////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////// ghosts to keep track of votes counting ////////////
/*
* the sum of voting power of those who voted
*/
ghost sum_all_votes_power() returns uint256 {
init_state axiom sum_all_votes_power() == 0;
}
hook Sstore ghost_sum_vote_power_by_id [KEY uint256 pId] uint256 current_power(uint256 old_power) STORAGE {
havoc sum_all_votes_power assuming sum_all_votes_power@new() == sum_all_votes_power@old() - old_power + current_power;
}
/*
* sum of all votes casted per proposal
*/
ghost tracked_weight(uint256) returns uint256 {
init_state axiom forall uint256 p. tracked_weight(p) == 0;
}
/*
* sum of all votes casted
*/
ghost sum_tracked_weight() returns uint256 {
init_state axiom sum_tracked_weight() == 0;
}
/*
* getter for _proposalVotes.againstVotes
*/
ghost votesAgainst() returns uint256 {
init_state axiom votesAgainst() == 0;
}
/*
* getter for _proposalVotes.forVotes
*/
ghost votesFor() returns uint256 {
init_state axiom votesFor() == 0;
}
/*
* getter for _proposalVotes.abstainVotes
*/
ghost votesAbstain() returns uint256 {
init_state axiom votesAbstain() == 0;
}
hook Sstore _proposalVotes [KEY uint256 pId].againstVotes uint256 votes(uint256 old_votes) STORAGE {
havoc tracked_weight assuming forall uint256 p.(p == pId => tracked_weight@new(p) == tracked_weight@old(p) - old_votes + votes) &&
(p != pId => tracked_weight@new(p) == tracked_weight@old(p));
havoc sum_tracked_weight assuming sum_tracked_weight@new() == sum_tracked_weight@old() - old_votes + votes;
havoc votesAgainst assuming votesAgainst@new() == votesAgainst@old() - old_votes + votes;
}
hook Sstore _proposalVotes [KEY uint256 pId].forVotes uint256 votes(uint256 old_votes) STORAGE {
havoc tracked_weight assuming forall uint256 p.(p == pId => tracked_weight@new(p) == tracked_weight@old(p) - old_votes + votes) &&
(p != pId => tracked_weight@new(p) == tracked_weight@old(p));
havoc sum_tracked_weight assuming sum_tracked_weight@new() == sum_tracked_weight@old() - old_votes + votes;
havoc votesFor assuming votesFor@new() == votesFor@old() - old_votes + votes;
}
hook Sstore _proposalVotes [KEY uint256 pId].abstainVotes uint256 votes(uint256 old_votes) STORAGE {
havoc tracked_weight assuming forall uint256 p.(p == pId => tracked_weight@new(p) == tracked_weight@old(p) - old_votes + votes) &&
(p != pId => tracked_weight@new(p) == tracked_weight@old(p));
havoc sum_tracked_weight assuming sum_tracked_weight@new() == sum_tracked_weight@old() - old_votes + votes;
havoc votesAbstain assuming votesAbstain@new() == votesAbstain@old() - old_votes + votes;
}
//////////////////////////////////////////////////////////////////////////////
////////////////////////////// INVARIANTS ////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
///////////////////////////////// RULES //////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//NOT FINISHED
/*
* the sum of voting power of those who voted is less or equal to the maximum possible votes, per each proposal
*/
rule possibleTotalVotes(uint256 pId, uint8 sup, env e, method f) {
// add requireinvariant for all i, j. i = i - 1 && i < j => checkpointlookup[i] < checkpointlookup[j];
require tracked_weight(pId) <= erc20votes.getPastTotalSupply(e, proposalSnapshot(pId));
uint256 againstB;
uint256 forB;
uint256 absatinB;
againstB, forB, absatinB = proposalVotes(pId);
calldataarg args;
//f(e, args);
castVote(e, pId, sup);
uint256 against;
uint256 for;
uint256 absatin;
against, for, absatin = proposalVotes(pId);
uint256 ps = proposalSnapshot(pId);
assert tracked_weight(pId) <= erc20votes.getPastTotalSupply(e, proposalSnapshot(pId)), "bla bla bla";
}

@ -0,0 +1,14 @@
/*
This rule looks for a non-reverting execution path to each method, including those overridden in the harness.
A method has such an execution path if it violates this rule.
How it works:
- If there is a non-reverting execution path, we reach the false assertion, and the sanity fails.
- If all execution paths are reverting, we never call the assertion, and the method will pass this rule vacuously.
*/
rule sanity(method f) {
env e;
calldataarg arg;
f(e, arg);
assert false;
}

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (access/AccessControl.sol)
// OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControl.sol)
pragma solidity ^0.8.0;
@ -67,7 +67,7 @@ abstract contract AccessControl is Context, IAccessControl, ERC165 {
* _Available since v4.1._
*/
modifier onlyRole(bytes32 role) {
_checkRole(role, _msgSender());
_checkRole(role);
_;
}
@ -81,10 +81,22 @@ abstract contract AccessControl is Context, IAccessControl, ERC165 {
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view override returns (bool) {
function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
return _roles[role].members[account];
}
/**
* @dev Revert with a standard message if `_msgSender()` is missing `role`.
* Overriding this function changes the behavior of the {onlyRole} modifier.
*
* Format of the revert message is described in {_checkRole}.
*
* _Available since v4.6._
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Revert with a standard message if `account` is missing `role`.
*
@ -92,7 +104,7 @@ abstract contract AccessControl is Context, IAccessControl, ERC165 {
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*/
function _checkRole(bytes32 role, address account) internal view {
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert(
string(
@ -113,7 +125,7 @@ abstract contract AccessControl is Context, IAccessControl, ERC165 {
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view override returns (bytes32) {
function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
return _roles[role].adminRole;
}

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (access/AccessControlEnumerable.sol)
// OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControlEnumerable.sol)
pragma solidity ^0.8.0;
@ -34,7 +34,7 @@ abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessCon
* https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
* for more information.
*/
function getRoleMember(bytes32 role, uint256 index) public view override returns (address) {
function getRoleMember(bytes32 role, uint256 index) public view virtual override returns (address) {
return _roleMembers[role].at(index);
}
@ -42,7 +42,7 @@ abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessCon
* @dev Returns the number of accounts that have `role`. Can be used
* together with {getRoleMember} to enumerate all bearers of a role.
*/
function getRoleMemberCount(bytes32 role) public view override returns (uint256) {
function getRoleMemberCount(bytes32 role) public view virtual override returns (uint256) {
return _roleMembers[role].length();
}

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (access/IAccessControl.sol)
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
pragma solidity ^0.8.0;

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (access/IAccessControlEnumerable.sol)
// OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol)
pragma solidity ^0.8.0;

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (access/Ownable.sol)
// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)
pragma solidity ^0.8.0;

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (finance/PaymentSplitter.sol)
// OpenZeppelin Contracts v4.4.1 (finance/PaymentSplitter.sol)
pragma solidity ^0.8.0;

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (finance/VestingWallet.sol)
// OpenZeppelin Contracts v4.4.1 (finance/VestingWallet.sol)
pragma solidity ^0.8.0;
import "../token/ERC20/utils/SafeERC20.sol";

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (governance/Governor.sol)
// OpenZeppelin Contracts (last updated v4.5.0) (governance/Governor.sol)
pragma solidity ^0.8.0;
@ -7,6 +7,7 @@ import "../utils/cryptography/ECDSA.sol";
import "../utils/cryptography/draft-EIP712.sol";
import "../utils/introspection/ERC165.sol";
import "../utils/math/SafeCast.sol";
import "../utils/structs/DoubleEndedQueue.sol";
import "../utils/Address.sol";
import "../utils/Context.sol";
import "../utils/Timers.sol";
@ -24,6 +25,7 @@ import "./IGovernor.sol";
* _Available since v4.3._
*/
abstract contract Governor is Context, ERC165, EIP712, IGovernor {
using DoubleEndedQueue for DoubleEndedQueue.Bytes32Deque;
using SafeCast for uint256;
using Timers for Timers.BlockNumber;
@ -40,12 +42,29 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor {
mapping(uint256 => ProposalCore) private _proposals;
// This queue keeps track of the governor operating on itself. Calls to functions protected by the
// {onlyGovernance} modifier needs to be whitelisted in this queue. Whitelisting is set in {_beforeExecute},
// consummed by the {onlyGovernance} modifier and eventually reset in {_afterExecute}. This ensures that the
// execution of {onlyGovernance} protected calls can only be achieved through successful proposals.
DoubleEndedQueue.Bytes32Deque private _governanceCall;
/**
* @dev Restrict access to governor executing address. Some module might override the _executor function to make
* sure this modifier is consistant with the execution model.
* @dev Restricts a function so it can only be executed through governance proposals. For example, governance
* parameter setters in {GovernorSettings} are protected using this modifier.
*
* The governance executing address may be different from the Governor's own address, for example it could be a
* timelock. This can be customized by modules by overriding {_executor}. The executor is only able to invoke these
* functions during the execution of the governor's {execute} function, and not under any other circumstances. Thus,
* for example, additional timelock proposers are not able to change governance parameters without going through the
* governance protocol (since v4.6).
*/
modifier onlyGovernance() {
require(_msgSender() == _executor(), "Governor: onlyGovernance");
if (_executor() != address(this)) {
bytes32 msgDataHash = keccak256(_msgData());
// loop until poping the expected operation - throw if deque is empty (operation not authorized)
while (_governanceCall.popFront() != msgDataHash) {}
}
_;
}
@ -196,7 +215,7 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor {
string memory description
) public virtual override returns (uint256) {
require(
getVotes(msg.sender, block.number - 1) >= proposalThreshold(),
getVotes(_msgSender(), block.number - 1) >= proposalThreshold(),
"GovernorCompatibilityBravo: proposer votes below proposal threshold"
);
@ -250,7 +269,9 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor {
emit ProposalExecuted(proposalId);
_beforeExecute(proposalId, targets, values, calldatas, descriptionHash);
_execute(proposalId, targets, values, calldatas, descriptionHash);
_afterExecute(proposalId, targets, values, calldatas, descriptionHash);
return proposalId;
}
@ -272,6 +293,42 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor {
}
}
/**
* @dev Hook before execution is trigerred.
*/
function _beforeExecute(
uint256, /* proposalId */
address[] memory targets,
uint256[] memory, /* values */
bytes[] memory calldatas,
bytes32 /*descriptionHash*/
) internal virtual {
if (_executor() != address(this)) {
for (uint256 i = 0; i < targets.length; ++i) {
if (targets[i] == address(this)) {
_governanceCall.pushBack(keccak256(calldatas[i]));
}
}
}
}
/**
* @dev Hook after execution is trigerred.
*/
function _afterExecute(
uint256, /* proposalId */
address[] memory, /* targets */
uint256[] memory, /* values */
bytes[] memory, /* calldatas */
bytes32 /*descriptionHash*/
) internal virtual {
if (_executor() != address(this)) {
if (!_governanceCall.empty()) {
_governanceCall.clear();
}
}
}
/**
* @dev Internal cancel mechanism: locks up the proposal timer, preventing it from being re-submitted. Marks it as
* canceled to allow distinguishing it from executed proposals.
@ -370,7 +427,7 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor {
address target,
uint256 value,
bytes calldata data
) external onlyGovernance {
) external virtual onlyGovernance {
Address.functionCallWithValue(target, data, value);
}

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (governance/IGovernor.sol)
// OpenZeppelin Contracts (last updated v4.5.0) (governance/IGovernor.sol)
pragma solidity ^0.8.0;
@ -193,7 +193,7 @@ abstract contract IGovernor is IERC165 {
function castVote(uint256 proposalId, uint8 support) public virtual returns (uint256 balance);
/**
* @dev Cast a with a reason
* @dev Cast a vote with a reason
*
* Emits a {VoteCast} event.
*/

@ -84,6 +84,10 @@ NOTE: Functions of the `Governor` contract do not include access control. If you
{{GovernorProposalThreshold}}
== Utils
{{Votes}}
== Timelock
In a governance system, the {TimelockController} contract is in charge of introducing a delay between a proposal and its execution. It can be used with or without a {Governor}.

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (governance/TimelockController.sol)
// OpenZeppelin Contracts v4.4.1 (governance/TimelockController.sol)
pragma solidity ^0.8.0;
@ -261,6 +261,9 @@ contract TimelockController is AccessControl {
*
* - the caller must have the 'executor' role.
*/
// This function can reenter, but it doesn't pose a risk because _afterCall checks that the proposal is pending,
// thus any modifications to the operation during reentrancy should be caught.
// slither-disable-next-line reentrancy-eth
function execute(
address target,
uint256 value,

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (governance/compatibility/GovernorCompatibilityBravo.sol)
// OpenZeppelin Contracts (last updated v4.5.0) (governance/compatibility/GovernorCompatibilityBravo.sol)
pragma solidity ^0.8.0;
@ -132,7 +132,7 @@ abstract contract GovernorCompatibilityBravo is IGovernorTimelock, IGovernorComp
for (uint256 i = 0; i < signatures.length; ++i) {
fullcalldatas[i] = bytes(signatures[i]).length == 0
? calldatas[i]
: abi.encodeWithSignature(signatures[i], calldatas[i]);
: abi.encodePacked(bytes4(keccak256(bytes(signatures[i]))), calldatas[i]);
}
return fullcalldatas;

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (governance/compatibility/IGovernorCompatibilityBravo.sol)
// OpenZeppelin Contracts v4.4.1 (governance/compatibility/IGovernorCompatibilityBravo.sol)
pragma solidity ^0.8.0;

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (governance/extensions/GovernorCountingSimple.sol)
// OpenZeppelin Contracts v4.4.1 (governance/extensions/GovernorCountingSimple.sol)
pragma solidity ^0.8.0;

@ -1,4 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (governance/extensions/GovernorPreventLateQuorum.sol)
pragma solidity ^0.8.0;

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (governance/extensions/GovernorProposalThreshold.sol)
// OpenZeppelin Contracts v4.4.1 (governance/extensions/GovernorProposalThreshold.sol)
pragma solidity ^0.8.0;

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (governance/extensions/GovernorSettings.sol)
// OpenZeppelin Contracts v4.4.1 (governance/extensions/GovernorSettings.sol)
pragma solidity ^0.8.0;

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (governance/extensions/GovernorTimelockCompound.sol)
// OpenZeppelin Contracts (last updated v4.5.0) (governance/extensions/GovernorTimelockCompound.sol)
pragma solidity ^0.8.0;
@ -224,14 +224,16 @@ abstract contract GovernorTimelockCompound is IGovernorTimelock, Governor {
/**
* @dev Public endpoint to update the underlying timelock instance. Restricted to the timelock itself, so updates
* must be proposed, scheduled and executed using the {Governor} workflow.
* must be proposed, scheduled, and executed through governance proposals.
*
* For security reason, the timelock must be handed over to another admin before setting up a new one. The two
* For security reasons, the timelock must be handed over to another admin before setting up a new one. The two
* operations (hand over the timelock) and do the update can be batched in a single proposal.
*
* Note that if the timelock admin has been handed over in a previous operation, we refuse updates made through the
* timelock if admin of the timelock has already been accepted and the operation is executed outside the scope of
* governance.
* CAUTION: It is not recommended to change the timelock while there are other queued governance proposals.
*/
function updateTimelock(ICompoundTimelock newTimelock) external virtual onlyGovernance {
_updateTimelock(newTimelock);

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (governance/extensions/GovernorTimelockControl.sol)
// OpenZeppelin Contracts (last updated v4.5.0) (governance/extensions/GovernorTimelockControl.sol)
pragma solidity ^0.8.0;
@ -10,12 +10,17 @@ import "../TimelockController.sol";
/**
* @dev Extension of {Governor} that binds the execution process to an instance of {TimelockController}. This adds a
* delay, enforced by the {TimelockController} to all successful proposal (in addition to the voting duration). The
* {Governor} needs the proposer (an ideally the executor) roles for the {Governor} to work properly.
* {Governor} needs the proposer (and ideally the executor) roles for the {Governor} to work properly.
*
* Using this model means the proposal will be operated by the {TimelockController} and not by the {Governor}. Thus,
* the assets and permissions must be attached to the {TimelockController}. Any asset sent to the {Governor} will be
* inaccessible.
*
* WARNING: Setting up the TimelockController to have additional proposers besides the governor is very risky, as it
* grants them powers that they must be trusted or known not to use: 1) {onlyGovernance} functions like {relay} are
* available to them through the timelock, and 2) approved governance proposals can be blocked by them, effectively
* executing a Denial of Service attack. This risk will be mitigated in a future release.
*
* _Available since v4.3._
*/
abstract contract GovernorTimelockControl is IGovernorTimelock, Governor {
@ -118,6 +123,9 @@ abstract contract GovernorTimelockControl is IGovernorTimelock, Governor {
* @dev Overriden version of the {Governor-_cancel} function to cancel the timelocked proposal if it as already
* been queued.
*/
// This function can reenter through the external call to the timelock, but we assume the timelock is trusted and
// well behaved (according to TimelockController) and this will not happen.
// slither-disable-next-line reentrancy-no-eth
function _cancel(
address[] memory targets,
uint256[] memory values,
@ -143,7 +151,9 @@ abstract contract GovernorTimelockControl is IGovernorTimelock, Governor {
/**
* @dev Public endpoint to update the underlying timelock instance. Restricted to the timelock itself, so updates
* must be proposed, scheduled and executed using the {Governor} workflow.
* must be proposed, scheduled, and executed through governance proposals.
*
* CAUTION: It is not recommended to change the timelock while there are other queued governance proposals.
*/
function updateTimelock(TimelockController newTimelock) external virtual onlyGovernance {
_updateTimelock(newTimelock);

@ -1,21 +1,20 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (governance/extensions/GovernorVotes.sol)
// OpenZeppelin Contracts (last updated v4.5.0) (governance/extensions/GovernorVotes.sol)
pragma solidity ^0.8.0;
import "../Governor.sol";
import "../../token/ERC20/extensions/ERC20Votes.sol";
import "../../utils/math/Math.sol";
import "../utils/IVotes.sol";
/**
* @dev Extension of {Governor} for voting weight extraction from an {ERC20Votes} token.
* @dev Extension of {Governor} for voting weight extraction from an {ERC20Votes} token, or since v4.5 an {ERC721Votes} token.
*
* _Available since v4.3._
*/
abstract contract GovernorVotes is Governor {
ERC20Votes public immutable token;
IVotes public immutable token;
constructor(ERC20Votes tokenAddress) {
constructor(IVotes tokenAddress) {
token = tokenAddress;
}

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (governance/extensions/GovernorVotesComp.sol)
// OpenZeppelin Contracts v4.4.1 (governance/extensions/GovernorVotesComp.sol)
pragma solidity ^0.8.0;

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (governance/extensions/GovernorVotesQuorumFraction.sol)
// OpenZeppelin Contracts (last updated v4.5.0) (governance/extensions/GovernorVotesQuorumFraction.sol)
pragma solidity ^0.8.0;
@ -16,26 +16,61 @@ abstract contract GovernorVotesQuorumFraction is GovernorVotes {
event QuorumNumeratorUpdated(uint256 oldQuorumNumerator, uint256 newQuorumNumerator);
/**
* @dev Initialize quorum as a fraction of the token's total supply.
*
* The fraction is specified as `numerator / denominator`. By default the denominator is 100, so quorum is
* specified as a percent: a numerator of 10 corresponds to quorum being 10% of total supply. The denominator can be
* customized by overriding {quorumDenominator}.
*/
constructor(uint256 quorumNumeratorValue) {
_updateQuorumNumerator(quorumNumeratorValue);
}
/**
* @dev Returns the current quorum numerator. See {quorumDenominator}.
*/
function quorumNumerator() public view virtual returns (uint256) {
return _quorumNumerator;
}
/**
* @dev Returns the quorum denominator. Defaults to 100, but may be overridden.
*/
function quorumDenominator() public view virtual returns (uint256) {
return 100;
}
/**
* @dev Returns the quorum for a block number, in terms of number of votes: `supply * numerator / denominator`.
*/
function quorum(uint256 blockNumber) public view virtual override returns (uint256) {
return (token.getPastTotalSupply(blockNumber) * quorumNumerator()) / quorumDenominator();
}
/**
* @dev Changes the quorum numerator.
*
* Emits a {QuorumNumeratorUpdated} event.
*
* Requirements:
*
* - Must be called through a governance proposal.
* - New numerator must be smaller or equal to the denominator.
*/
function updateQuorumNumerator(uint256 newQuorumNumerator) external virtual onlyGovernance {
_updateQuorumNumerator(newQuorumNumerator);
}
/**
* @dev Changes the quorum numerator.
*
* Emits a {QuorumNumeratorUpdated} event.
*
* Requirements:
*
* - New numerator must be smaller or equal to the denominator.
*/
function _updateQuorumNumerator(uint256 newQuorumNumerator) internal virtual {
require(
newQuorumNumerator <= quorumDenominator(),

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (governance/extensions/IGovernorTimelock.sol)
// OpenZeppelin Contracts v4.4.1 (governance/extensions/IGovernorTimelock.sol)
pragma solidity ^0.8.0;

@ -0,0 +1,61 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (governance/utils/IVotes.sol)
pragma solidity ^0.8.0;
/**
* @dev Common interface for {ERC20Votes}, {ERC721Votes}, and other {Votes}-enabled contracts.
*
* _Available since v4.5._
*/
interface IVotes {
/**
* @dev Emitted when an account changes their delegate.
*/
event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);
/**
* @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of votes.
*/
event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance);
/**
* @dev Returns the current amount of votes that `account` has.
*/
function getVotes(address account) external view returns (uint256);
/**
* @dev Returns the amount of votes that `account` had at the end of a past block (`blockNumber`).
*/
function getPastVotes(address account, uint256 blockNumber) external view returns (uint256);
/**
* @dev Returns the total supply of votes available at the end of a past block (`blockNumber`).
*
* NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes.
* Votes that have not been delegated are still part of total supply, even though they would not participate in a
* vote.
*/
function getPastTotalSupply(uint256 blockNumber) external view returns (uint256);
/**
* @dev Returns the delegate that `account` has chosen.
*/
function delegates(address account) external view returns (address);
/**
* @dev Delegates votes from the sender to `delegatee`.
*/
function delegate(address delegatee) external;
/**
* @dev Delegates votes from signer to `delegatee`.
*/
function delegateBySig(
address delegatee,
uint256 nonce,
uint256 expiry,
uint8 v,
bytes32 r,
bytes32 s
) external;
}

@ -0,0 +1,211 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (governance/utils/Votes.sol)
pragma solidity ^0.8.0;
import "../../utils/Context.sol";
import "../../utils/Counters.sol";
import "../../utils/Checkpoints.sol";
import "../../utils/cryptography/draft-EIP712.sol";
import "./IVotes.sol";
/**
* @dev This is a base abstract contract that tracks voting units, which are a measure of voting power that can be
* transferred, and provides a system of vote delegation, where an account can delegate its voting units to a sort of
* "representative" that will pool delegated voting units from different accounts and can then use it to vote in
* decisions. In fact, voting units _must_ be delegated in order to count as actual votes, and an account has to
* delegate those votes to itself if it wishes to participate in decisions and does not have a trusted representative.
*
* This contract is often combined with a token contract such that voting units correspond to token units. For an
* example, see {ERC721Votes}.
*
* The full history of delegate votes is tracked on-chain so that governance protocols can consider votes as distributed
* at a particular block number to protect against flash loans and double voting. The opt-in delegate system makes the
* cost of this history tracking optional.
*
* When using this module the derived contract must implement {_getVotingUnits} (for example, make it return
* {ERC721-balanceOf}), and can use {_transferVotingUnits} to track a change in the distribution of those units (in the
* previous example, it would be included in {ERC721-_beforeTokenTransfer}).
*
* _Available since v4.5._
*/
abstract contract Votes is IVotes, Context, EIP712 {
using Checkpoints for Checkpoints.History;
using Counters for Counters.Counter;
bytes32 private constant _DELEGATION_TYPEHASH =
keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");
mapping(address => address) private _delegation;
mapping(address => Checkpoints.History) private _delegateCheckpoints;
Checkpoints.History private _totalCheckpoints;
mapping(address => Counters.Counter) private _nonces;
/**
* @dev Returns the current amount of votes that `account` has.
*/
function getVotes(address account) public view virtual override returns (uint256) {
return _delegateCheckpoints[account].latest();
}
/**
* @dev Returns the amount of votes that `account` had at the end of a past block (`blockNumber`).
*
* Requirements:
*
* - `blockNumber` must have been already mined
*/
function getPastVotes(address account, uint256 blockNumber) public view virtual override returns (uint256) {
return _delegateCheckpoints[account].getAtBlock(blockNumber);
}
/**
* @dev Returns the total supply of votes available at the end of a past block (`blockNumber`).
*
* NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes.
* Votes that have not been delegated are still part of total supply, even though they would not participate in a
* vote.
*
* Requirements:
*
* - `blockNumber` must have been already mined
*/
function getPastTotalSupply(uint256 blockNumber) public view virtual override returns (uint256) {
require(blockNumber < block.number, "Votes: block not yet mined");
return _totalCheckpoints.getAtBlock(blockNumber);
}
/**
* @dev Returns the current total supply of votes.
*/
function _getTotalSupply() internal view virtual returns (uint256) {
return _totalCheckpoints.latest();
}
/**
* @dev Returns the delegate that `account` has chosen.
*/
function delegates(address account) public view virtual override returns (address) {
return _delegation[account];
}
/**
* @dev Delegates votes from the sender to `delegatee`.
*/
function delegate(address delegatee) public virtual override {
address account = _msgSender();
_delegate(account, delegatee);
}
/**
* @dev Delegates votes from signer to `delegatee`.
*/
function delegateBySig(
address delegatee,
uint256 nonce,
uint256 expiry,
uint8 v,
bytes32 r,
bytes32 s
) public virtual override {
require(block.timestamp <= expiry, "Votes: signature expired");
address signer = ECDSA.recover(
_hashTypedDataV4(keccak256(abi.encode(_DELEGATION_TYPEHASH, delegatee, nonce, expiry))),
v,
r,
s
);
require(nonce == _useNonce(signer), "Votes: invalid nonce");
_delegate(signer, delegatee);
}
/**
* @dev Delegate all of `account`'s voting units to `delegatee`.
*
* Emits events {DelegateChanged} and {DelegateVotesChanged}.
*/
function _delegate(address account, address delegatee) internal virtual {
address oldDelegate = delegates(account);
_delegation[account] = delegatee;
emit DelegateChanged(account, oldDelegate, delegatee);
_moveDelegateVotes(oldDelegate, delegatee, _getVotingUnits(account));
}
/**
* @dev Transfers, mints, or burns voting units. To register a mint, `from` should be zero. To register a burn, `to`
* should be zero. Total supply of voting units will be adjusted with mints and burns.
*/
function _transferVotingUnits(
address from,
address to,
uint256 amount
) internal virtual {
if (from == address(0)) {
_totalCheckpoints.push(_add, amount);
}
if (to == address(0)) {
_totalCheckpoints.push(_subtract, amount);
}
_moveDelegateVotes(delegates(from), delegates(to), amount);
}
/**
* @dev Moves delegated votes from one delegate to another.
*/
function _moveDelegateVotes(
address from,
address to,
uint256 amount
) private {
if (from != to && amount > 0) {
if (from != address(0)) {
(uint256 oldValue, uint256 newValue) = _delegateCheckpoints[from].push(_subtract, amount);
emit DelegateVotesChanged(from, oldValue, newValue);
}
if (to != address(0)) {
(uint256 oldValue, uint256 newValue) = _delegateCheckpoints[to].push(_add, amount);
emit DelegateVotesChanged(to, oldValue, newValue);
}
}
}
function _add(uint256 a, uint256 b) private pure returns (uint256) {
return a + b;
}
function _subtract(uint256 a, uint256 b) private pure returns (uint256) {
return a - b;
}
/**
* @dev Consumes a nonce.
*
* Returns the current value and increments nonce.
*/
function _useNonce(address owner) internal virtual returns (uint256 current) {
Counters.Counter storage nonce = _nonces[owner];
current = nonce.current();
nonce.increment();
}
/**
* @dev Returns an address nonce.
*/
function nonces(address owner) public view virtual returns (uint256) {
return _nonces[owner].current();
}
/**
* @dev Returns the contract's {EIP712} domain separator.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32) {
return _domainSeparatorV4();
}
/**
* @dev Must return the voting units held by an account.
*/
function _getVotingUnits(address) internal virtual returns (uint256);
}

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (interfaces/IERC1155.sol)
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1155.sol)
pragma solidity ^0.8.0;

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (interfaces/IERC1155MetadataURI.sol)
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1155MetadataURI.sol)
pragma solidity ^0.8.0;

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (interfaces/IERC1155Receiver.sol)
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1155Receiver.sol)
pragma solidity ^0.8.0;

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (interfaces/IERC1271.sol)
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1271.sol)
pragma solidity ^0.8.0;

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (interfaces/IERC1363.sol)
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1363.sol)
pragma solidity ^0.8.0;

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (interfaces/IERC1363Receiver.sol)
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1363Receiver.sol)
pragma solidity ^0.8.0;

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (interfaces/IERC1363Spender.sol)
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1363Spender.sol)
pragma solidity ^0.8.0;

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (interfaces/IERC165.sol)
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol)
pragma solidity ^0.8.0;

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (interfaces/IERC1820Implementer.sol)
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1820Implementer.sol)
pragma solidity ^0.8.0;

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (interfaces/IERC1820Registry.sol)
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1820Registry.sol)
pragma solidity ^0.8.0;

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (interfaces/IERC20.sol)
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol)
pragma solidity ^0.8.0;

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (interfaces/IERC20Metadata.sol)
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC20Metadata.sol)
pragma solidity ^0.8.0;

@ -1,20 +1,22 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (interfaces/IERC2981.sol)
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/IERC2981.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
import "../utils/introspection/IERC165.sol";
/**
* @dev Interface for the NFT Royalty Standard
* @dev Interface for the NFT Royalty Standard.
*
* A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal
* support for royalty payments across all NFT marketplaces and ecosystem participants.
*
* _Available since v4.5._
*/
interface IERC2981 is IERC165 {
/**
* @dev Called with the sale price to determine how much royalty is owed and to whom.
* @param tokenId - the NFT asset queried for royalty information
* @param salePrice - the sale price of the NFT asset specified by `tokenId`
* @return receiver - address of who should be sent the royalty payment
* @return royaltyAmount - the royalty payment amount for `salePrice`
* @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of
* exchange. The royalty amount is denominated and should be payed in that same unit of exchange.
*/
function royaltyInfo(uint256 tokenId, uint256 salePrice)
external

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (interfaces/IERC3156.sol)
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC3156.sol)
pragma solidity ^0.8.0;

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (interfaces/IERC3156FlashBorrower.sol)
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC3156FlashBorrower.sol)
pragma solidity ^0.8.0;

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (interfaces/IERC3156FlashLender.sol)
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC3156FlashLender.sol)
pragma solidity ^0.8.0;

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (interfaces/IERC721.sol)
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC721.sol)
pragma solidity ^0.8.0;

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (interfaces/IERC721Enumerable.sol)
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC721Enumerable.sol)
pragma solidity ^0.8.0;

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (interfaces/IERC721Metadata.sol)
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC721Metadata.sol)
pragma solidity ^0.8.0;

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (interfaces/IERC721Receiver.sol)
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC721Receiver.sol)
pragma solidity ^0.8.0;

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (interfaces/IERC777.sol)
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC777.sol)
pragma solidity ^0.8.0;

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (interfaces/IERC777Recipient.sol)
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC777Recipient.sol)
pragma solidity ^0.8.0;

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (interfaces/IERC777Sender.sol)
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC777Sender.sol)
pragma solidity ^0.8.0;

@ -5,7 +5,7 @@ NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/
== List of standardized interfaces
These interfaces are available as `.sol` files, and also as compiler `.json` ABI files (through the npm package). These
are usefull to interract with third party contracts that implement them.
are useful to interact with third party contracts that implement them.
- {IERC20}
- {IERC20Metadata}

@ -0,0 +1,20 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.0;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822Proxiable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (interfaces/draft-IERC2612.sol)
// OpenZeppelin Contracts v4.4.1 (interfaces/draft-IERC2612.sol)
pragma solidity ^0.8.0;

@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (metatx/ERC2771Context.sol)
// OpenZeppelin Contracts (last updated v4.5.0) (metatx/ERC2771Context.sol)
pragma solidity ^0.8.0;
pragma solidity ^0.8.9;
import "../utils/Context.sol";
@ -9,8 +9,10 @@ import "../utils/Context.sol";
* @dev Context variant with ERC2771 support.
*/
abstract contract ERC2771Context is Context {
address private _trustedForwarder;
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
address private immutable _trustedForwarder;
/// @custom:oz-upgrades-unsafe-allow constructor
constructor(address trustedForwarder) {
_trustedForwarder = trustedForwarder;
}

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (metatx/MinimalForwarder.sol)
// OpenZeppelin Contracts (last updated v4.5.0) (metatx/MinimalForwarder.sol)
pragma solidity ^0.8.0;
@ -50,9 +50,17 @@ contract MinimalForwarder is EIP712 {
(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);
if (gasleft() <= req.gas / 63) {
// We explicitly trigger invalid opcode to consume all gas and bubble-up the effects, since
// neither revert or assert consume all gas since Solidity 0.8.0
// https://docs.soliditylang.org/en/v0.8.0/control-structures.html#panic-via-assert-and-error-via-require
assembly {
invalid()
}
}
return (success, returndata);
}

@ -0,0 +1,11 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../utils/Base64.sol";
contract Base64Mock {
function encode(bytes memory value) external pure returns (string memory) {
return Base64.encode(value);
}
}

@ -6,6 +6,7 @@ contract CallReceiverMock {
string public sharedAnswer;
event MockFunctionCalled();
event MockFunctionCalledWithArgs(uint256 a, uint256 b);
uint256[] private _array;
@ -15,6 +16,12 @@ contract CallReceiverMock {
return "0x1234";
}
function mockFunctionWithArgs(uint256 a, uint256 b) public payable returns (string memory) {
emit MockFunctionCalledWithArgs(a, b);
return "0x1234";
}
function mockFunctionNonPayable() public returns (string memory) {
emit MockFunctionCalled();

@ -0,0 +1,23 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../utils/Checkpoints.sol";
contract CheckpointsImpl {
using Checkpoints for Checkpoints.History;
Checkpoints.History private _totalCheckpoints;
function latest() public view returns (uint256) {
return _totalCheckpoints.latest();
}
function getAtBlock(uint256 blockNumber) public view returns (uint256) {
return _totalCheckpoints.getAtBlock(blockNumber);
}
function push(uint256 value) public returns (uint256, uint256) {
return _totalCheckpoints.push(value);
}
}

@ -0,0 +1,58 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../utils/structs/DoubleEndedQueue.sol";
// Bytes32Deque
contract Bytes32DequeMock {
using DoubleEndedQueue for DoubleEndedQueue.Bytes32Deque;
event OperationResult(bytes32 value);
DoubleEndedQueue.Bytes32Deque private _vector;
function pushBack(bytes32 value) public {
_vector.pushBack(value);
}
function pushFront(bytes32 value) public {
_vector.pushFront(value);
}
function popFront() public returns (bytes32) {
bytes32 value = _vector.popFront();
emit OperationResult(value);
return value;
}
function popBack() public returns (bytes32) {
bytes32 value = _vector.popBack();
emit OperationResult(value);
return value;
}
function front() public view returns (bytes32) {
return _vector.front();
}
function back() public view returns (bytes32) {
return _vector.back();
}
function at(uint256 i) public view returns (bytes32) {
return _vector.at(i);
}
function clear() public {
_vector.clear();
}
function length() public view returns (uint256) {
return _vector.length();
}
function empty() public view returns (bool) {
return _vector.empty();
}
}

@ -1,13 +1,16 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.8.9;
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) {}
/// @custom:oz-upgrades-unsafe-allow constructor
constructor(address trustedForwarder) ERC2771Context(trustedForwarder) {
emit Sender(_msgSender()); // _msgSender() should be accessible during construction
}
function _msgSender() internal view virtual override(Context, ERC2771Context) returns (address) {
return ERC2771Context._msgSender();

@ -0,0 +1,33 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../token/ERC721/extensions/ERC721Royalty.sol";
contract ERC721RoyaltyMock is ERC721Royalty {
constructor(string memory name, string memory symbol) ERC721(name, symbol) {}
function setTokenRoyalty(
uint256 tokenId,
address recipient,
uint96 fraction
) public {
_setTokenRoyalty(tokenId, recipient, fraction);
}
function setDefaultRoyalty(address recipient, uint96 fraction) public {
_setDefaultRoyalty(recipient, fraction);
}
function mint(address to, uint256 tokenId) public {
_mint(to, tokenId);
}
function burn(uint256 tokenId) public {
_burn(tokenId);
}
function deleteDefaultRoyalty() public {
_deleteDefaultRoyalty();
}
}

@ -0,0 +1,25 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../token/ERC721/extensions/draft-ERC721Votes.sol";
contract ERC721VotesMock is ERC721Votes {
constructor(string memory name, string memory symbol) ERC721(name, symbol) EIP712(name, "1") {}
function getTotalSupply() public view returns (uint256) {
return _getTotalSupply();
}
function mint(address account, uint256 tokenId) public {
_mint(account, tokenId);
}
function burn(uint256 tokenId) public {
_burn(tokenId);
}
function getChainId() external view returns (uint256) {
return block.chainid;
}
}

@ -4,7 +4,8 @@ pragma solidity ^0.8.0;
import "../utils/structs/EnumerableMap.sol";
contract EnumerableMapMock {
// UintToAddressMap
contract UintToAddressMapMock {
using EnumerableMap for EnumerableMap.UintToAddressMap;
event OperationResult(bool result);
@ -45,3 +46,42 @@ contract EnumerableMapMock {
return _map.get(key, errorMessage);
}
}
// AddressToUintMap
contract AddressToUintMapMock {
using EnumerableMap for EnumerableMap.AddressToUintMap;
event OperationResult(bool result);
EnumerableMap.AddressToUintMap private _map;
function contains(address key) public view returns (bool) {
return _map.contains(key);
}
function set(address key, uint256 value) public {
bool result = _map.set(key, value);
emit OperationResult(result);
}
function remove(address key) public {
bool result = _map.remove(key);
emit OperationResult(result);
}
function length() public view returns (uint256) {
return _map.length();
}
function at(uint256 index) public view returns (address key, uint256 value) {
return _map.at(index);
}
function tryGet(address key) public view returns (bool, uint256) {
return _map.tryGet(key);
}
function get(address key) public view returns (uint256) {
return _map.get(key);
}
}

@ -15,7 +15,7 @@ contract GovernorMock is
{
constructor(
string memory name_,
ERC20Votes token_,
IVotes token_,
uint256 votingDelay_,
uint256 votingPeriod_,
uint256 quorumNumerator_

@ -17,7 +17,7 @@ contract GovernorPreventLateQuorumMock is
constructor(
string memory name_,
ERC20Votes token_,
IVotes token_,
uint256 votingDelay_,
uint256 votingPeriod_,
uint256 quorum_,

@ -15,7 +15,7 @@ contract GovernorTimelockCompoundMock is
{
constructor(
string memory name_,
ERC20Votes token_,
IVotes token_,
uint256 votingDelay_,
uint256 votingPeriod_,
ICompoundTimelock timelock_,

@ -15,7 +15,7 @@ contract GovernorTimelockControlMock is
{
constructor(
string memory name_,
ERC20Votes token_,
IVotes token_,
uint256 votingDelay_,
uint256 votingPeriod_,
TimelockController timelock_,
@ -105,4 +105,6 @@ contract GovernorTimelockControlMock is
function _executor() internal view virtual override(Governor, GovernorTimelockControl) returns (address) {
return super._executor();
}
function nonGovernanceFunction() external {}
}

@ -0,0 +1,41 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../governance/extensions/GovernorCountingSimple.sol";
import "../governance/extensions/GovernorVotes.sol";
contract GovernorVoteMocks is GovernorVotes, GovernorCountingSimple {
constructor(string memory name_, IVotes token_) Governor(name_) GovernorVotes(token_) {}
function quorum(uint256) public pure override returns (uint256) {
return 0;
}
function votingDelay() public pure override returns (uint256) {
return 4;
}
function votingPeriod() public pure override returns (uint256) {
return 16;
}
function cancel(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 salt
) public returns (uint256 proposalId) {
return _cancel(targets, values, calldatas, salt);
}
function getVotes(address account, uint256 blockNumber)
public
view
virtual
override(IGovernor, GovernorVotes)
returns (uint256)
{
return super.getVotes(account, blockNumber);
}
}

@ -10,16 +10,25 @@ import "../proxy/utils/Initializable.sol";
*/
contract InitializableMock is Initializable {
bool public initializerRan;
bool public onlyInitializingRan;
uint256 public x;
function initialize() public initializer {
initializerRan = true;
}
function initializeNested() public initializer {
function initializeOnlyInitializing() public onlyInitializing {
onlyInitializingRan = true;
}
function initializerNested() public initializer {
initialize();
}
function onlyInitializingNested() public initializer {
initializeOnlyInitializing();
}
function initializeWithX(uint256 _x) public payable initializer {
x = _x;
}
@ -32,3 +41,21 @@ contract InitializableMock is Initializable {
require(false, "InitializableMock forced failure");
}
}
contract ConstructorInitializableMock is Initializable {
bool public initializerRan;
bool public onlyInitializingRan;
constructor() initializer {
initialize();
initializeOnlyInitializing();
}
function initialize() public initializer {
initializerRan = true;
}
function initializeOnlyInitializing() public onlyInitializing {
onlyInitializingRan = true;
}
}

@ -20,8 +20,4 @@ contract MathMock {
function ceilDiv(uint256 a, uint256 b) public pure returns (uint256) {
return Math.ceilDiv(a, b);
}
function abs(int256 n) public pure returns (uint256) {
return Math.abs(n);
}
}

@ -22,6 +22,16 @@ contract SampleHuman is Initializable {
bool public isHuman;
function initialize() public initializer {
__SampleHuman_init();
}
// solhint-disable-next-line func-name-mixedcase
function __SampleHuman_init() internal onlyInitializing {
__SampleHuman_init_unchained();
}
// solhint-disable-next-line func-name-mixedcase
function __SampleHuman_init_unchained() internal onlyInitializing {
isHuman = true;
}
}
@ -33,7 +43,17 @@ contract SampleMother is Initializable, SampleHuman {
uint256 public mother;
function initialize(uint256 value) public virtual initializer {
SampleHuman.initialize();
__SampleMother_init(value);
}
// solhint-disable-next-line func-name-mixedcase
function __SampleMother_init(uint256 value) internal onlyInitializing {
__SampleHuman_init();
__SampleMother_init_unchained(value);
}
// solhint-disable-next-line func-name-mixedcase
function __SampleMother_init_unchained(uint256 value) internal onlyInitializing {
mother = value;
}
}
@ -45,7 +65,17 @@ contract SampleGramps is Initializable, SampleHuman {
string public gramps;
function initialize(string memory value) public virtual initializer {
SampleHuman.initialize();
__SampleGramps_init(value);
}
// solhint-disable-next-line func-name-mixedcase
function __SampleGramps_init(string memory value) internal onlyInitializing {
__SampleHuman_init();
__SampleGramps_init_unchained(value);
}
// solhint-disable-next-line func-name-mixedcase
function __SampleGramps_init_unchained(string memory value) internal onlyInitializing {
gramps = value;
}
}
@ -57,7 +87,17 @@ contract SampleFather is Initializable, SampleGramps {
uint256 public father;
function initialize(string memory _gramps, uint256 _father) public initializer {
SampleGramps.initialize(_gramps);
__SampleFather_init(_gramps, _father);
}
// solhint-disable-next-line func-name-mixedcase
function __SampleFather_init(string memory _gramps, uint256 _father) internal onlyInitializing {
__SampleGramps_init(_gramps);
__SampleFather_init_unchained(_father);
}
// solhint-disable-next-line func-name-mixedcase
function __SampleFather_init_unchained(uint256 _father) internal onlyInitializing {
father = _father;
}
}
@ -74,8 +114,23 @@ contract SampleChild is Initializable, SampleMother, SampleFather {
uint256 _father,
uint256 _child
) public initializer {
SampleMother.initialize(_mother);
SampleFather.initialize(_gramps, _father);
__SampleChild_init(_mother, _gramps, _father, _child);
}
// solhint-disable-next-line func-name-mixedcase
function __SampleChild_init(
uint256 _mother,
string memory _gramps,
uint256 _father,
uint256 _child
) internal onlyInitializing {
__SampleMother_init(_mother);
__SampleFather_init(_gramps, _father);
__SampleChild_init_unchained(_child);
}
// solhint-disable-next-line func-name-mixedcase
function __SampleChild_init_unchained(uint256 _child) internal onlyInitializing {
child = _child;
}
}

@ -33,7 +33,7 @@ contract ERC20ReturnFalseMock is Context {
}
function allowance(address, address) public view returns (uint256) {
require(_dummy == 0); // Duummy read from a state variable so that the function is view
require(_dummy == 0); // Dummy read from a state variable so that the function is view
return 0;
}
}

@ -0,0 +1,23 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../utils/math/SignedMath.sol";
contract SignedMathMock {
function max(int256 a, int256 b) public pure returns (int256) {
return SignedMath.max(a, b);
}
function min(int256 a, int256 b) public pure returns (int256) {
return SignedMath.min(a, b);
}
function average(int256 a, int256 b) public pure returns (int256) {
return SignedMath.average(a, b);
}
function abs(int256 n) public pure returns (uint256) {
return SignedMath.abs(n);
}
}

@ -0,0 +1,58 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./UUPSUpgradeableMock.sol";
// This contract implements the pre-4.5 UUPS upgrade function with a rollback test.
// It's used to test that newer UUPS contracts are considered valid upgrades by older UUPS contracts.
contract UUPSUpgradeableLegacyMock is UUPSUpgradeableMock {
// Inlined from ERC1967Upgrade
bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
// ERC1967Upgrade._setImplementation is private so we reproduce it here.
// An extra underscore prevents a name clash error.
function __setImplementation(address newImplementation) private {
require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
}
function _upgradeToAndCallSecureLegacyV1(
address newImplementation,
bytes memory data,
bool forceCall
) internal {
address oldImplementation = _getImplementation();
// Initial upgrade and setup call
__setImplementation(newImplementation);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(newImplementation, data);
}
// Perform rollback test if not already in progress
StorageSlot.BooleanSlot storage rollbackTesting = StorageSlot.getBooleanSlot(_ROLLBACK_SLOT);
if (!rollbackTesting.value) {
// Trigger rollback using upgradeTo from the new implementation
rollbackTesting.value = true;
Address.functionDelegateCall(
newImplementation,
abi.encodeWithSignature("upgradeTo(address)", oldImplementation)
);
rollbackTesting.value = false;
// Check rollback was effective
require(oldImplementation == _getImplementation(), "ERC1967Upgrade: upgrade breaks further upgrades");
// Finally reset to the new implementation and log the upgrade
_upgradeTo(newImplementation);
}
}
// hooking into the old mechanism
function upgradeTo(address newImplementation) external virtual override {
_upgradeToAndCallSecureLegacyV1(newImplementation, bytes(""), false);
}
function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual override {
_upgradeToAndCallSecureLegacyV1(newImplementation, data, false);
}
}

@ -19,13 +19,3 @@ contract UUPSUpgradeableUnsafeMock is UUPSUpgradeableMock {
ERC1967Upgrade._upgradeToAndCall(newImplementation, data, false);
}
}
contract UUPSUpgradeableBrokenMock is UUPSUpgradeableMock {
function upgradeTo(address) external virtual override {
// pass
}
function upgradeToAndCall(address, bytes memory) external payable virtual override {
// pass
}
}

@ -0,0 +1,40 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../governance/utils/Votes.sol";
contract VotesMock is Votes {
mapping(address => uint256) private _balances;
mapping(uint256 => address) private _owners;
constructor(string memory name) EIP712(name, "1") {}
function getTotalSupply() public view returns (uint256) {
return _getTotalSupply();
}
function delegate(address account, address newDelegation) public {
return _delegate(account, newDelegation);
}
function _getVotingUnits(address account) internal virtual override returns (uint256) {
return _balances[account];
}
function mint(address account, uint256 voteId) external {
_balances[account] += 1;
_owners[voteId] = account;
_transferVotingUnits(address(0), account, 1);
}
function burn(uint256 voteId) external {
address owner = _owners[voteId];
_balances[owner] -= 1;
_transferVotingUnits(owner, address(0), 1);
}
function getChainId() external view returns (uint256) {
return block.chainid;
}
}

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

Loading…
Cancel
Save