Compare commits
336 Commits
formal-ver
...
v5.0.1
| Author | SHA1 | Date | |
|---|---|---|---|
| 01ef448981 | |||
| 9ce0340466 | |||
| 4eb67a408c | |||
| 83330a6e4c | |||
| ab967b8639 | |||
| a34d986eca | |||
| 5161a4dc8a | |||
| 932fddf69a | |||
| 73995884f3 | |||
| 12735415d6 | |||
| d27635fc67 | |||
| cff043486b | |||
| 6a0cfcedf0 | |||
| bd25a0a26f | |||
| 228013d232 | |||
| a874080fc1 | |||
| 3e45ab2d51 | |||
| 37f0b3b2ce | |||
| e49fcbeb56 | |||
| 21ef8130c8 | |||
| d6954f17b5 | |||
| 51191d3152 | |||
| a14d8149ed | |||
| 7a4064d886 | |||
| bf629d4ea7 | |||
| aef22bddc9 | |||
| bc96591f65 | |||
| fb2aec6946 | |||
| 322df4226d | |||
| 4ce98d75bf | |||
| 3a1e1bd336 | |||
| 57c84f6bb8 | |||
| 8f3f4f7f17 | |||
| 621fc0fe99 | |||
| 011c8bb034 | |||
| 53f2721e8c | |||
| b805cc82d3 | |||
| 33894d2a5b | |||
| 9aaca67aa6 | |||
| abcec9e4a3 | |||
| b55b47d421 | |||
| 0d6703b852 | |||
| f7db0bea31 | |||
| 64da2c10a4 | |||
| 68204769a1 | |||
| 652d0c5fb3 | |||
| 2215d9fd5e | |||
| 618304cc01 | |||
| af06fdcfd4 | |||
| d555464c53 | |||
| a714fe6dbd | |||
| 05205ab2e1 | |||
| 224c23b38f | |||
| 80b2d1df38 | |||
| 3bd9ed377e | |||
| 75eb7c2d49 | |||
| e48f8fd0d2 | |||
| 6f1685c3eb | |||
| 60e3ffe6a3 | |||
| 63851f8de5 | |||
| 36bf1e46fa | |||
| b6111faac8 | |||
| 095c8e120c | |||
| 9e09e0653a | |||
| a07f28b00c | |||
| bba33516b1 | |||
| 01659449d4 | |||
| 7ae7f3ef4b | |||
| 26c22169f0 | |||
| 6f80048ce9 | |||
| d54f4ac4b7 | |||
| a05a529049 | |||
| 25c416d01c | |||
| 5a77c9995f | |||
| e2a9353dea | |||
| 87f7a2cd42 | |||
| bb7ca7d151 | |||
| 5abbd04933 | |||
| ff9d089dad | |||
| 33cab7cd25 | |||
| 9ef69c03d1 | |||
| 1523a4f071 | |||
| e7ba2f7784 | |||
| f154bc31d4 | |||
| 9d2adccf87 | |||
| 630844ef50 | |||
| e891ec587d | |||
| 9612083826 | |||
| a503ba1a0a | |||
| c0545f741b | |||
| 98b83dfbaa | |||
| 424149a682 | |||
| b7da617d8d | |||
| 00c5da2034 | |||
| 10e00c8ef5 | |||
| 8186c07a83 | |||
| 8a0b7bed82 | |||
| 3266bca150 | |||
| cd67894914 | |||
| 812404cee8 | |||
| a5ed318634 | |||
| b2e7bab920 | |||
| 98203a72a6 | |||
| adbb8c9d27 | |||
| fab65cd08b | |||
| 9e3f4d60c5 | |||
| 8643fd45fd | |||
| cb0ffefe2f | |||
| b5a3e693e7 | |||
| 48b860124c | |||
| 736091afc4 | |||
| 70578bbb44 | |||
| 9bb8008c23 | |||
| 1169bb1e51 | |||
| 54a235f895 | |||
| b81bec4552 | |||
| f715365ec4 | |||
| 21716722ad | |||
| d39df78f6c | |||
| 5ae630684a | |||
| 48cc8a92f5 | |||
| fa680739e9 | |||
| 00cbf5a236 | |||
| d6b63a48ba | |||
| f631d8a5f0 | |||
| aed5720a01 | |||
| 02ea01765a | |||
| 9445f96223 | |||
| 7c02b5cab2 | |||
| 7222a31d54 | |||
| 28d9ac2bdb | |||
| 19293f3ecd | |||
| f347b410cf | |||
| 21bb89ef5b | |||
| 121be5dd09 | |||
| 9cf873ea14 | |||
| 84db204a41 | |||
| a55af77c75 | |||
| 4d4a509b1f | |||
| b6c5abbde5 | |||
| 0abf18f305 | |||
| 921ac49ccb | |||
| 8b72e20e32 | |||
| 24ebff5ae9 | |||
| 3d0edbecf1 | |||
| cd981f6521 | |||
| 2a4396c9dd | |||
| 4bac6fa310 | |||
| e47b53bce4 | |||
| 5229b75785 | |||
| 6d74b91388 | |||
| f5bf7233cb | |||
| 0053ee040a | |||
| 996168f1f1 | |||
| 7ccea54dc1 | |||
| 6bf68a41d1 | |||
| 3fe28e19af | |||
| 3ff9b42ff5 | |||
| 63bfab1a0c | |||
| 90163661df | |||
| e3adf91e50 | |||
| 6e21422737 | |||
| bb64458928 | |||
| 06861dce54 | |||
| 37270eb08a | |||
| 621b867b1a | |||
| 04342118dc | |||
| 874c2d3c02 | |||
| d6a8b2ccd7 | |||
| 023894deef | |||
| f29307cfe0 | |||
| 8cab922347 | |||
| cb4bf950df | |||
| c44c220254 | |||
| da89c438f1 | |||
| a7a94c7746 | |||
| 1e0e4e20bb | |||
| 6ddacdbde8 | |||
| dac2457a80 | |||
| b66c77a1fc | |||
| 9fa550c62f | |||
| 2271e2c58d | |||
| 365aca6d60 | |||
| 1d0dbcf9ab | |||
| 1f4e33fb72 | |||
| fc19a7947c | |||
| c95a445130 | |||
| 1a77a508f9 | |||
| 002a7c8812 | |||
| cd48b3eab3 | |||
| 6724873895 | |||
| c014c8f148 | |||
| ff85c7b0eb | |||
| 05ef6924ac | |||
| 2477534260 | |||
| ac5480e7ca | |||
| ef103f37e4 | |||
| 5cc1ea0a39 | |||
| 7cc2cbfeb5 | |||
| 604025400f | |||
| d6c7cee321 | |||
| fe08f58c69 | |||
| b425a72240 | |||
| 08fd777f6d | |||
| e73f90fa9d | |||
| cc04263170 | |||
| 1d5bcd04e7 | |||
| d9474327a4 | |||
| df2778f38e | |||
| 4fd2f8be33 | |||
| 85696d80ad | |||
| 6c14de4f0c | |||
| 253bfa68c2 | |||
| ffceb3cd98 | |||
| eecd5e15c7 | |||
| 2d1da295e6 | |||
| 3902a410f1 | |||
| 5cef83d2c7 | |||
| 30256fa838 | |||
| 2ee1da12c4 | |||
| 4c713f8cea | |||
| 7bb5592ad5 | |||
| 15c5c71795 | |||
| 4448c13c3c | |||
| 5420879d9b | |||
| 25edd3cd62 | |||
| 238d17cab9 | |||
| 5955d8e85b | |||
| 09329f8a18 | |||
| cbc6145f5f | |||
| 13d5e0466a | |||
| 7e814a3074 | |||
| a1d57bac50 | |||
| 11d65442b3 | |||
| dfef6a68ee | |||
| 0f10efe232 | |||
| 96b95592c3 | |||
| 8de6eba8a3 | |||
| 1642b6639b | |||
| 3ec4307c8a | |||
| f355bd3a2a | |||
| 3e1b25a5cf | |||
| f7b236dca8 | |||
| e5dbc7435e | |||
| 9a2e4cb3a7 | |||
| d095542fa4 | |||
| dff520afae | |||
| df3f1fc4db | |||
| 0ee84342b7 | |||
| 51294b7480 | |||
| 34d926dd7e | |||
| 832c352c7d | |||
| 908f78d07b | |||
| 692d8c85a4 | |||
| 72ed4ca67a | |||
| dcba9f995f | |||
| 8b2ed0f570 | |||
| 9e8b74a0e2 | |||
| a7ee03565b | |||
| 10022da83d | |||
| 538655c3c0 | |||
| 0a2a33be30 | |||
| ab2604ac5b | |||
| 6ff415de6b | |||
| d23f818a59 | |||
| 44d6053b43 | |||
| f959d7e4e6 | |||
| 8f14d52b73 | |||
| 1a079d258b | |||
| 6aac66d065 | |||
| a522187b50 | |||
| 91df66c4a9 | |||
| 8d633cb7d1 | |||
| 3b117992e1 | |||
| dd1265cb1d | |||
| 788d6a129a | |||
| 86f6eb2c9c | |||
| 661343f74c | |||
| 473d0b6884 | |||
| f2346b6749 | |||
| cf86fd9962 | |||
| 31723ed608 | |||
| 5523c1482b | |||
| ead3bcaccb | |||
| 7e7060e00e | |||
| 7f5e91062e | |||
| ca822213f2 | |||
| fa112be682 | |||
| 3f610ebc25 | |||
| 1a60b061d5 | |||
| 4f4b6ab403 | |||
| 1c8df659b9 | |||
| 75ef7b8b27 | |||
| ea2d5ad2e7 | |||
| e69248e551 | |||
| e739144cb0 | |||
| 6794c9460b | |||
| f8e3c375d1 | |||
| 58a62916de | |||
| 3214f6c256 | |||
| 5f7f660c6e | |||
| b952a82d29 | |||
| a55013e742 | |||
| aaad1f4a4f | |||
| 4fb6833e32 | |||
| de520fe25a | |||
| 7f028d6959 | |||
| eedca5d873 | |||
| e58c6d8ff4 | |||
| 8ba26f388f | |||
| 0ebc6e3529 | |||
| e1a77ab15f | |||
| 2d05db171a | |||
| e919d96ff2 | |||
| 54c31ad98b | |||
| 5ad74c6d10 | |||
| c5d040beb9 | |||
| 30c3c6c16e | |||
| 147dc89054 | |||
| 7c6e289782 | |||
| d210847e28 | |||
| a290e13099 | |||
| 97bba5adaa | |||
| fbbaf3365b | |||
| 4147005b0c | |||
| 81dbe643a0 | |||
| 9cbe8b340c | |||
| 3c80a42866 | |||
| e2d2ebc8fc | |||
| bc8f442d00 | |||
| 4a9db80cb9 | |||
| 887985413c | |||
| b18cf4ba42 | |||
| 39a752e398 | |||
| 6ff283bebc | |||
| 1cf4db9615 |
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': patch
|
||||
---
|
||||
|
||||
`Initializable`: optimize `_disableInitializers` by using `!=` instead of `<`. ([#3787](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3787))
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': minor
|
||||
---
|
||||
|
||||
`ReentrancyGuard`: Add a `_reentrancyGuardEntered` function to expose the guard status. ([#3714](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3714))
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': patch
|
||||
---
|
||||
|
||||
`Ownable2Step`: make `acceptOwnership` public virtual to enable usecases that require overriding it. ([#3960](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3960))
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': minor
|
||||
---
|
||||
|
||||
`ERC721Wrapper`: add a new extension of the `ERC721` token which wraps an underlying token. Deposit and withdraw guarantee that the ownership of each token is backed by a corresponding underlying token with the same identifier.
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': minor
|
||||
---
|
||||
|
||||
`EnumerableMap`: add a `keys()` function that returns an array containing all the keys. ([#3920](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3920))
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': patch
|
||||
---
|
||||
|
||||
`UUPSUpgradeable.sol`: Change visibility to the functions `upgradeTo ` and `upgradeToAndCall ` from `external` to `public`.
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': patch
|
||||
---
|
||||
|
||||
`TimelockController`: Add the `CallSalt` event to emit on operation schedule.
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': minor
|
||||
---
|
||||
|
||||
`Governor`: add a public `cancel(uint256)` function.
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': minor
|
||||
---
|
||||
|
||||
`Governor`: Enable timestamp operation for blockchains without a stable block time. This is achieved by connecting a Governor's internal clock to match a voting token's EIP-6372 interface.
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': patch
|
||||
---
|
||||
|
||||
Reformatted codebase with latest version of Prettier Solidity. ([#3898](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3898))
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': minor
|
||||
---
|
||||
|
||||
`Strings`: add `equal` method. ([#3774](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3774))
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': minor
|
||||
---
|
||||
|
||||
`IERC5313`: Add an interface for EIP-5313 that is now final.
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': patch
|
||||
---
|
||||
|
||||
`Math`: optimize `log256` rounding check. ([#3745](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3745))
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': patch
|
||||
---
|
||||
|
||||
`ERC20Votes`: optimize by using unchecked arithmetic. ([#3748](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3748))
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': patch
|
||||
---
|
||||
|
||||
`Multicall`: annotate `multicall` function as upgrade safe to not raise a flag for its delegatecall. ([#3961](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3961))
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': minor
|
||||
---
|
||||
|
||||
`IERC4906`: Add an interface for ERC-4906 that is now Final.
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': minor
|
||||
---
|
||||
|
||||
`TransparentUpgradeableProxy`: support value passthrough for all ifAdmin function.
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': minor
|
||||
---
|
||||
|
||||
`StorageSlot`: Add support for `string` and `bytes`.
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': patch
|
||||
---
|
||||
|
||||
`ERC20Pausable`, `ERC721Pausable`, `ERC1155Pausable`: Add note regarding missing public pausing functionality
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': minor
|
||||
---
|
||||
|
||||
`Votes`, `ERC20Votes`, `ERC721Votes`: support timestamp checkpointing using EIP-6372.
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': minor
|
||||
---
|
||||
|
||||
`ERC4626`: Add mitigation to the inflation attack through virtual shares and assets.
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': minor
|
||||
---
|
||||
|
||||
`Strings`: add `toString` method for signed integers. ([#3773](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3773))
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': minor
|
||||
---
|
||||
|
||||
`ERC20Wrapper`: Make the `underlying` variable private and add a public accessor.
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': minor
|
||||
---
|
||||
|
||||
`EIP712`: add EIP-5267 support for better domain discovery.
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': minor
|
||||
---
|
||||
|
||||
`AccessControlDefaultAdminRules`: Add an extension of `AccessControl` with additional security rules for the `DEFAULT_ADMIN_ROLE`.
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': minor
|
||||
---
|
||||
|
||||
`SignatureChecker`: Add `isValidERC1271SignatureNow` for checking a signature directly against a smart contract using ERC-1271.
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': patch
|
||||
---
|
||||
|
||||
`ECDSA`: Add a function `toDataWithIntendedValidatorHash` that encodes data with version 0x00 following EIP-191.
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': minor
|
||||
---
|
||||
|
||||
`SafeERC20`: Add a `forceApprove` function to improve compatibility with tokens behaving like USDT.
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': minor
|
||||
---
|
||||
|
||||
`ERC1967Upgrade`: removed contract-wide `oz-upgrades-unsafe-allow delegatecall` annotation, replaced by granular annotation in `UUPSUpgradeable`.
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': patch
|
||||
---
|
||||
|
||||
`MerkleProof`: optimize by using unchecked arithmetic. ([#3745](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3745))
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': minor
|
||||
---
|
||||
|
||||
`ECDSA`: optimize bytes32 computation by using assembly instead of `abi.encodePacked`.
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': minor
|
||||
---
|
||||
|
||||
`ERC721URIStorage`: Emit ERC-4906 `MetadataUpdate` in `_setTokenURI`.
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': minor
|
||||
---
|
||||
|
||||
`ShortStrings`: Added a library for handling short strings in a gas efficient way, with fallback to storage for longer strings.
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': minor
|
||||
---
|
||||
|
||||
`SignatureChecker`: Allow return data length greater than 32 from EIP-1271 signers.
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'openzeppelin-solidity': minor
|
||||
---
|
||||
|
||||
`UUPSUpgradeable`: added granular `oz-upgrades-unsafe-allow-reachable` annotation to improve upgrade safety checks on latest version of the Upgrades Plugins (starting with `@openzeppelin/upgrades-core@1.21.0`).
|
||||
8
.github/actions/setup/action.yml
vendored
8
.github/actions/setup/action.yml
vendored
@ -5,7 +5,7 @@ runs:
|
||||
steps:
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 14.x
|
||||
node-version: 16.x
|
||||
- uses: actions/cache@v3
|
||||
id: cache
|
||||
with:
|
||||
@ -15,5 +15,7 @@ runs:
|
||||
run: npm ci
|
||||
shell: bash
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
env:
|
||||
SKIP_COMPILE: true
|
||||
- name: Install Foundry
|
||||
uses: foundry-rs/foundry-toolchain@v1
|
||||
with:
|
||||
version: nightly
|
||||
|
||||
2
.github/workflows/actionlint.yml
vendored
2
.github/workflows/actionlint.yml
vendored
@ -9,7 +9,7 @@ jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Add problem matchers
|
||||
run: |
|
||||
# https://github.com/rhysd/actionlint/blob/3a2f2c7/docs/usage.md#problem-matchers
|
||||
|
||||
2
.github/workflows/changeset.yml
vendored
2
.github/workflows/changeset.yml
vendored
@ -19,7 +19,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ !contains(github.event.pull_request.labels.*.name, 'ignore-changeset') }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # Include history so Changesets finds merge-base
|
||||
- name: Set up environment
|
||||
|
||||
72
.github/workflows/checks.yml
vendored
72
.github/workflows/checks.yml
vendored
@ -4,6 +4,7 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- next-v*
|
||||
- release-v*
|
||||
pull_request: {}
|
||||
workflow_dispatch: {}
|
||||
@ -12,12 +13,14 @@ concurrency:
|
||||
group: checks-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
NODE_OPTIONS: --max_old_space_size=5120
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
if: github.repository != 'OpenZeppelin/openzeppelin-contracts-upgradeable'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up environment
|
||||
uses: ./.github/actions/setup
|
||||
- run: npm run lint
|
||||
@ -26,10 +29,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
FORCE_COLOR: 1
|
||||
NODE_OPTIONS: --max_old_space_size=4096
|
||||
GAS: true
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up environment
|
||||
uses: ./.github/actions/setup
|
||||
- name: Run tests and generate gas report
|
||||
@ -37,60 +39,80 @@ jobs:
|
||||
- name: Check linearisation of the inheritance graph
|
||||
run: npm run test:inheritance
|
||||
- name: Check proceduraly generated contracts are up-to-date
|
||||
if: github.repository != 'OpenZeppelin/openzeppelin-contracts-upgradeable'
|
||||
run: npm run test:generation
|
||||
- name: Compare gas costs
|
||||
uses: ./.github/actions/gas-compare
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
- name: Check storage layout
|
||||
uses: ./.github/actions/storage-layout
|
||||
if: github.base_ref == 'master'
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
|
||||
foundry-tests:
|
||||
if: github.repository != 'OpenZeppelin/openzeppelin-contracts-upgradeable'
|
||||
tests-upgradeable:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
FORCE_COLOR: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # Include history so patch conflicts are resolved automatically
|
||||
- name: Set up environment
|
||||
uses: ./.github/actions/setup
|
||||
- name: Copy non-upgradeable contracts as dependency
|
||||
run: |
|
||||
mkdir -p lib/openzeppelin-contracts
|
||||
cp -rnT contracts lib/openzeppelin-contracts/contracts
|
||||
- name: Transpile to upgradeable
|
||||
run: bash scripts/upgradeable/transpile.sh
|
||||
- name: Run tests
|
||||
run: npm run test
|
||||
- name: Check linearisation of the inheritance graph
|
||||
run: npm run test:inheritance
|
||||
- name: Check storage layout
|
||||
uses: ./.github/actions/storage-layout
|
||||
if: github.base_ref == 'master'
|
||||
continue-on-error: ${{ contains(github.event.pull_request.labels.*.name, 'breaking change') }}
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
|
||||
tests-foundry:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Install Foundry
|
||||
uses: foundry-rs/foundry-toolchain@v1
|
||||
with:
|
||||
version: nightly
|
||||
- name: Set up environment
|
||||
uses: ./.github/actions/setup
|
||||
- name: Run tests
|
||||
run: forge test -vv
|
||||
|
||||
coverage:
|
||||
if: github.repository != 'OpenZeppelin/openzeppelin-contracts-upgradeable'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up environment
|
||||
uses: ./.github/actions/setup
|
||||
- run: npm run coverage
|
||||
env:
|
||||
NODE_OPTIONS: --max_old_space_size=4096
|
||||
- uses: codecov/codecov-action@v3
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
slither:
|
||||
if: github.repository != 'OpenZeppelin/openzeppelin-contracts-upgradeable'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up environment
|
||||
uses: ./.github/actions/setup
|
||||
- run: rm foundry.toml
|
||||
- uses: crytic/slither-action@v0.3.0
|
||||
with:
|
||||
node-version: 18.15
|
||||
|
||||
codespell:
|
||||
if: github.repository != 'OpenZeppelin/openzeppelin-contracts-upgradeable'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Run CodeSpell
|
||||
uses: codespell-project/actions-codespell@v1.0
|
||||
uses: codespell-project/actions-codespell@v2.0
|
||||
with:
|
||||
check_hidden: true
|
||||
check_filenames: true
|
||||
skip: package-lock.json,*.pdf
|
||||
|
||||
2
.github/workflows/docs.yml
vendored
2
.github/workflows/docs.yml
vendored
@ -11,7 +11,7 @@ jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up environment
|
||||
uses: ./.github/actions/setup
|
||||
- run: bash scripts/git-user-config.sh
|
||||
|
||||
55
.github/workflows/formal-verifiation.yml
vendored
55
.github/workflows/formal-verifiation.yml
vendored
@ -1,55 +0,0 @@
|
||||
name: Formal verification
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- release-v*
|
||||
- formal-verification
|
||||
pull_request: {}
|
||||
workflow_dispatch: {}
|
||||
|
||||
jobs:
|
||||
list-scripts:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- id: set-matrix
|
||||
run: echo ::set-output name=matrix::$(ls certora/scripts/{,**}/*.sh | grep -v '\WnoCI\W' | jq -Rsc 'split("\n")[:-1]')
|
||||
|
||||
verify:
|
||||
runs-on: ubuntu-latest
|
||||
needs: list-scripts
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.10'
|
||||
cache: 'pip'
|
||||
- name: Install java
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: '11'
|
||||
java-package: 'jre'
|
||||
- name: Install certora
|
||||
run: pip install certora-cli
|
||||
- name: Install solc
|
||||
run: |
|
||||
wget https://github.com/ethereum/solidity/releases/download/v0.8.19/solc-static-linux
|
||||
sudo mv solc-static-linux /usr/local/bin/solc
|
||||
chmod +x /usr/local/bin/solc
|
||||
- name: Verify rule ${{ matrix.params }}
|
||||
run: |
|
||||
touch certora/applyHarness.patch
|
||||
make -C certora munged
|
||||
bash ${{ matrix.params }}
|
||||
env:
|
||||
CERTORAKEY: ${{ secrets.CERTORAKEY }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: 4
|
||||
matrix:
|
||||
params: ${{ fromJson(needs.list-scripts.outputs.matrix) }}
|
||||
68
.github/workflows/formal-verification.yml
vendored
Normal file
68
.github/workflows/formal-verification.yml
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
name: formal verification
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- reopened
|
||||
- synchronize
|
||||
- labeled
|
||||
workflow_dispatch: {}
|
||||
|
||||
env:
|
||||
PIP_VERSION: '3.10'
|
||||
JAVA_VERSION: '11'
|
||||
SOLC_VERSION: '0.8.20'
|
||||
|
||||
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
jobs:
|
||||
apply-diff:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Apply patches
|
||||
run: make -C certora apply
|
||||
|
||||
verify:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'formal-verification')
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up environment
|
||||
uses: ./.github/actions/setup
|
||||
- name: identify specs that need to be run
|
||||
id: arguments
|
||||
run: |
|
||||
if [[ ${{ github.event_name }} = 'pull_request' ]];
|
||||
then
|
||||
RESULT=$(git diff ${{ github.event.pull_request.head.sha }}..${{ github.event.pull_request.base.sha }} --name-only certora/specs/*.spec | while IFS= read -r file; do [[ -f $file ]] && basename "${file%.spec}"; done | tr "\n" " ")
|
||||
else
|
||||
RESULT='--all'
|
||||
fi
|
||||
echo "result=$RESULT" >> "$GITHUB_OUTPUT"
|
||||
- name: Install python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ env.PIP_VERSION }}
|
||||
cache: 'pip'
|
||||
- name: Install python packages
|
||||
run: pip install -r requirements.txt
|
||||
- name: Install java
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: ${{ env.JAVA_VERSION }}
|
||||
- name: Install solc
|
||||
run: |
|
||||
wget https://github.com/ethereum/solidity/releases/download/v${{ env.SOLC_VERSION }}/solc-static-linux
|
||||
sudo mv solc-static-linux /usr/local/bin/solc
|
||||
chmod +x /usr/local/bin/solc
|
||||
- name: Verify specification
|
||||
run: |
|
||||
make -C certora apply
|
||||
node certora/run.js ${{ steps.arguments.outputs.result }} >> "$GITHUB_STEP_SUMMARY"
|
||||
env:
|
||||
CERTORAKEY: ${{ secrets.CERTORAKEY }}
|
||||
26
.github/workflows/release-cycle.yml
vendored
26
.github/workflows/release-cycle.yml
vendored
@ -27,7 +27,7 @@ jobs:
|
||||
pull-requests: read
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up environment
|
||||
uses: ./.github/actions/setup
|
||||
- id: state
|
||||
@ -58,7 +58,7 @@ jobs:
|
||||
if: needs.state.outputs.start == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up environment
|
||||
uses: ./.github/actions/setup
|
||||
- run: bash scripts/git-user-config.sh
|
||||
@ -81,7 +81,7 @@ jobs:
|
||||
if: needs.state.outputs.promote == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up environment
|
||||
uses: ./.github/actions/setup
|
||||
- run: bash scripts/git-user-config.sh
|
||||
@ -102,7 +102,7 @@ jobs:
|
||||
if: needs.state.outputs.changesets == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # To get all tags
|
||||
- name: Set up environment
|
||||
@ -134,7 +134,7 @@ jobs:
|
||||
if: needs.state.outputs.publish == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up environment
|
||||
uses: ./.github/actions/setup
|
||||
- id: pack
|
||||
@ -147,16 +147,12 @@ jobs:
|
||||
with:
|
||||
name: ${{ github.ref_name }}
|
||||
path: ${{ steps.pack.outputs.tarball }}
|
||||
- name: Tag
|
||||
run: npx changeset tag
|
||||
- name: Publish
|
||||
run: bash scripts/release/workflow/publish.sh
|
||||
env:
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
TARBALL: ${{ steps.pack.outputs.tarball }}
|
||||
TAG: ${{ steps.pack.outputs.tag }}
|
||||
- name: Push tags
|
||||
run: git push --tags
|
||||
- name: Create Github Release
|
||||
uses: actions/github-script@v6
|
||||
env:
|
||||
@ -171,7 +167,7 @@ jobs:
|
||||
name: Tarball Integrity Check
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Download tarball artifact
|
||||
id: artifact
|
||||
# Replace with actions/upload-artifact@v3 when
|
||||
@ -192,15 +188,19 @@ jobs:
|
||||
pull-requests: write
|
||||
if: needs.state.outputs.merge == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
MERGE_BRANCH: merge/${{ github.ref_name }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # All branches
|
||||
- name: Set up environment
|
||||
uses: ./.github/actions/setup
|
||||
- run: bash scripts/git-user-config.sh
|
||||
- name: Create branch to merge
|
||||
run: bash scripts/release/workflow/prepare-release-merge.sh
|
||||
run: |
|
||||
git checkout -B "$MERGE_BRANCH" "$GITHUB_REF_NAME"
|
||||
git push -f origin "$MERGE_BRANCH"
|
||||
- name: Create PR back to master
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
@ -208,7 +208,7 @@ jobs:
|
||||
await github.rest.pulls.create({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
head: 'merge/${{ github.ref_name }}',
|
||||
head: process.env.MERGE_BRANCH,
|
||||
base: 'master',
|
||||
title: '${{ format('Merge {0} branch', github.ref_name) }}'
|
||||
});
|
||||
|
||||
35
.github/workflows/upgradeable.yml
vendored
35
.github/workflows/upgradeable.yml
vendored
@ -1,4 +1,4 @@
|
||||
name: Upgradeable Trigger
|
||||
name: transpile upgradeable
|
||||
|
||||
on:
|
||||
push:
|
||||
@ -7,17 +7,28 @@ on:
|
||||
- release-v*
|
||||
|
||||
jobs:
|
||||
trigger:
|
||||
transpile:
|
||||
environment: push-upgradeable
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- id: app
|
||||
uses: getsentry/action-github-app-token@v2
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
app_id: ${{ secrets.UPGRADEABLE_APP_ID }}
|
||||
private_key: ${{ secrets.UPGRADEABLE_APP_PK }}
|
||||
- run: |
|
||||
curl -X POST \
|
||||
https://api.github.com/repos/OpenZeppelin/openzeppelin-contracts-upgradeable/dispatches \
|
||||
-H 'Accept: application/vnd.github.v3+json' \
|
||||
-H 'Authorization: token ${{ steps.app.outputs.token }}' \
|
||||
-d '{ "event_type": "Update", "client_payload": { "ref": "${{ github.ref }}" } }'
|
||||
repository: OpenZeppelin/openzeppelin-contracts-upgradeable
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.GH_TOKEN_UPGRADEABLE }}
|
||||
- name: Fetch current non-upgradeable branch
|
||||
run: |
|
||||
git fetch "$REMOTE" master # Fetch default branch first for patch to apply cleanly
|
||||
git fetch "$REMOTE" "$REF"
|
||||
git checkout FETCH_HEAD
|
||||
env:
|
||||
REF: ${{ github.ref }}
|
||||
REMOTE: https://github.com/${{ github.repository }}.git
|
||||
- name: Set up environment
|
||||
uses: ./.github/actions/setup
|
||||
- run: bash scripts/git-user-config.sh
|
||||
- name: Transpile to upgradeable
|
||||
run: bash scripts/upgradeable/transpile-onto.sh ${{ github.ref_name }} origin/${{ github.ref_name }}
|
||||
env:
|
||||
SUBMODULE_REMOTE: https://github.com/${{ github.repository }}.git
|
||||
- run: git push origin ${{ github.ref_name }}
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@ -63,9 +63,10 @@ contracts-exposed
|
||||
|
||||
# Foundry
|
||||
/out
|
||||
/cache_forge
|
||||
|
||||
# Certora
|
||||
.certora*
|
||||
.last_confs
|
||||
certora_*
|
||||
resource_errors.json
|
||||
.zip-output-url.txt
|
||||
|
||||
1
.gitmodules
vendored
1
.gitmodules
vendored
@ -1,4 +1,5 @@
|
||||
[submodule "lib/forge-std"]
|
||||
branch = v1
|
||||
path = lib/forge-std
|
||||
url = https://github.com/foundry-rs/forge-std
|
||||
[submodule "lib/erc4626-tests"]
|
||||
|
||||
@ -10,5 +10,6 @@
|
||||
"singleQuote": false
|
||||
}
|
||||
}
|
||||
]
|
||||
],
|
||||
"plugins": ["prettier-plugin-solidity"]
|
||||
}
|
||||
|
||||
@ -1,14 +0,0 @@
|
||||
{
|
||||
"rules": {
|
||||
"no-unused-vars": "error",
|
||||
"const-name-snakecase": "error",
|
||||
"contract-name-camelcase": "error",
|
||||
"event-name-camelcase": "error",
|
||||
"func-name-mixedcase": "error",
|
||||
"func-param-name-mixedcase": "error",
|
||||
"modifier-name-mixedcase": "error",
|
||||
"private-vars-leading-underscore": "error",
|
||||
"var-name-mixedcase": "error",
|
||||
"imports-on-top": "error"
|
||||
}
|
||||
}
|
||||
338
CHANGELOG.md
338
CHANGELOG.md
@ -1,5 +1,330 @@
|
||||
# Changelog
|
||||
|
||||
|
||||
## 5.0.1 (2023-12-07)
|
||||
|
||||
- `ERC2771Context` and `Context`: Introduce a `_contextPrefixLength()` getter, used to trim extra information appended to `msg.data`.
|
||||
- `Multicall`: Make aware of non-canonical context (i.e. `msg.sender` is not `_msgSender()`), allowing compatibility with `ERC2771Context`.
|
||||
|
||||
## 5.0.0 (2023-10-05)
|
||||
|
||||
### Additions Summary
|
||||
|
||||
The following contracts and libraries were added:
|
||||
|
||||
- `AccessManager`: A consolidated system for managing access control in complex systems.
|
||||
- `AccessManaged`: A module for connecting a contract to an authority in charge of its access control.
|
||||
- `GovernorTimelockAccess`: An adapter for time-locking governance proposals using an `AccessManager`.
|
||||
- `AuthorityUtils`: A library of utilities for interacting with authority contracts.
|
||||
- `GovernorStorage`: A Governor module that stores proposal details in storage.
|
||||
- `ERC2771Forwarder`: An ERC2771 forwarder for meta transactions.
|
||||
- `ERC1967Utils`: A library with ERC1967 events, errors and getters.
|
||||
- `Nonces`: An abstraction for managing account nonces.
|
||||
- `MessageHashUtils`: A library for producing digests for ECDSA operations.
|
||||
- `Time`: A library with helpers for manipulating time-related objects.
|
||||
|
||||
### Removals Summary
|
||||
|
||||
The following contracts, libraries, and functions were removed:
|
||||
|
||||
- `Address.isContract` (because of its ambiguous nature and potential for misuse)
|
||||
- `Checkpoints.History`
|
||||
- `Counters`
|
||||
- `ERC20Snapshot`
|
||||
- `ERC20VotesComp`
|
||||
- `ERC165Storage` (in favor of inheritance based approach)
|
||||
- `ERC777`
|
||||
- `ERC1820Implementer`
|
||||
- `GovernorVotesComp`
|
||||
- `GovernorProposalThreshold` (deprecated since 4.4)
|
||||
- `PaymentSplitter`
|
||||
- `PullPayment`
|
||||
- `SafeMath`
|
||||
- `SignedSafeMath`
|
||||
- `Timers`
|
||||
- `TokenTimelock` (in favor of `VestingWallet`)
|
||||
- All escrow contracts (`Escrow`, `ConditionalEscrow` and `RefundEscrow`)
|
||||
- All cross-chain contracts, including `AccessControlCrossChain` and all the vendored bridge interfaces
|
||||
- All presets in favor of [OpenZeppelin Contracts Wizard](https://wizard.openzeppelin.com/)
|
||||
|
||||
These removals were implemented in the following PRs: [#3637](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3637), [#3880](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3880), [#3945](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3945), [#4258](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4258), [#4276](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4276), [#4289](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4289)
|
||||
|
||||
### Changes by category
|
||||
|
||||
#### General
|
||||
|
||||
- Replaced revert strings and require statements with custom errors. ([#4261](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4261))
|
||||
- Bumped minimum compiler version required to 0.8.20 ([#4288](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4288))
|
||||
- Use of `abi.encodeCall` in place of `abi.encodeWithSelector` and `abi.encodeWithSignature` for improved type-checking of parameters ([#4293](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4293))
|
||||
- Replaced some uses of `abi.encodePacked` with clearer alternatives (e.g. `bytes.concat`, `string.concat`). ([#4504](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4504)) ([#4296](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4296))
|
||||
- Overrides are now used internally for a number of functions that were previously hardcoded to their default implementation in certain locations: `ERC1155Supply.totalSupply`, `ERC721.ownerOf`, `ERC721.balanceOf` and `ERC721.totalSupply` in `ERC721Enumerable`, `ERC20.totalSupply` in `ERC20FlashMint`, and `ERC1967._getImplementation` in `ERC1967Proxy`. ([#4299](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4299))
|
||||
- Removed the `override` specifier from functions that only override a single interface function. ([#4315](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4315))
|
||||
- Switched to using explicit Solidity import statements. Some previously available symbols may now have to be separately imported. ([#4399](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4399))
|
||||
- `Governor`, `Initializable`, and `UUPSUpgradeable`: Use internal functions in modifiers to optimize bytecode size. ([#4472](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4472))
|
||||
- Upgradeable contracts now use namespaced storage (EIP-7201). ([#4534](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4534))
|
||||
- Upgradeable contracts no longer transpile interfaces and libraries. ([#4628](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4628))
|
||||
|
||||
#### Access
|
||||
|
||||
- `Ownable`: Added an `initialOwner` parameter to the constructor, making the ownership initialization explicit. ([#4267](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4267))
|
||||
- `Ownable`: Prevent using address(0) as the initial owner. ([#4531](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4531))
|
||||
- `AccessControl`: Added a boolean return value to the internal `_grantRole` and `_revokeRole` functions indicating whether the role was granted or revoked. ([#4241](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4241))
|
||||
- `access`: Moved `AccessControl` extensions to a dedicated directory. ([#4359](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4359))
|
||||
- `AccessManager`: Added a new contract for managing access control of complex systems in a consolidated location. ([#4121](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4121))
|
||||
- `AccessManager`, `AccessManaged`, `GovernorTimelockAccess`: Ensure that calldata shorter than 4 bytes is not padded to 4 bytes. ([#4624](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4624))
|
||||
- `AccessManager`: Use named return parameters in functions that return multiple values. ([#4624](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4624))
|
||||
- `AccessManager`: Make `schedule` and `execute` more conservative when delay is 0. ([#4644](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4644))
|
||||
|
||||
#### Finance
|
||||
|
||||
- `VestingWallet`: Fixed revert during 1 second time window when duration is 0. ([#4502](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4502))
|
||||
- `VestingWallet`: Use `Ownable` instead of an immutable `beneficiary`. ([#4508](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4508))
|
||||
|
||||
#### Governance
|
||||
|
||||
- `Governor`: Optimized use of storage for proposal data ([#4268](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4268))
|
||||
- `Governor`: Added validation in ERC1155 and ERC721 receiver hooks to ensure Governor is the executor. ([#4314](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4314))
|
||||
- `Governor`: Refactored internals to implement common queuing logic in the core module of the Governor. Added `queue` and `_queueOperations` functions that act at different levels. Modules that implement queuing via timelocks are expected to override `_queueOperations` to implement the timelock-specific logic. Added `_executeOperations` as the equivalent for execution. ([#4360](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4360))
|
||||
- `Governor`: Added `voter` and `nonce` parameters in signed ballots, to avoid forging signatures for random addresses, prevent signature replay, and allow invalidating signatures. Add `voter` as a new parameter in the `castVoteBySig` and `castVoteWithReasonAndParamsBySig` functions. ([#4378](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4378))
|
||||
- `Governor`: Added support for casting votes with ERC-1271 signatures by using a `bytes memory signature` instead of `r`, `s` and `v` arguments in the `castVoteBySig` and `castVoteWithReasonAndParamsBySig` functions. ([#4418](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4418))
|
||||
- `Governor`: Added a mechanism to restrict the address of the proposer using a suffix in the description.
|
||||
- `GovernorStorage`: Added a new governor extension that stores the proposal details in storage, with an interface that operates on `proposalId`, as well as proposal enumerability. This replaces the old `GovernorCompatibilityBravo` module. ([#4360](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4360))
|
||||
- `GovernorTimelockAccess`: Added a module to connect a governor with an instance of `AccessManager`, allowing the governor to make calls that are delay-restricted by the manager using the normal `queue` workflow. ([#4523](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4523))
|
||||
- `GovernorTimelockControl`: Clean up timelock id on execution for gas refund. ([#4118](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4118))
|
||||
- `GovernorTimelockControl`: Added the Governor instance address as part of the TimelockController operation `salt` to avoid operation id collisions between governors using the same TimelockController. ([#4432](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4432))
|
||||
- `TimelockController`: Changed the role architecture to use `DEFAULT_ADMIN_ROLE` as the admin for all roles, instead of the bespoke `TIMELOCK_ADMIN_ROLE` that was used previously. This aligns with the general recommendation for `AccessControl` and makes the addition of new roles easier. Accordingly, the `admin` parameter and timelock will now be granted `DEFAULT_ADMIN_ROLE` instead of `TIMELOCK_ADMIN_ROLE`. ([#3799](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3799))
|
||||
- `TimelockController`: Added a state getter that returns an `OperationState` enum. ([#4358](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4358))
|
||||
- `Votes`: Use Trace208 for checkpoints. This enables EIP-6372 clock support for keys but reduces the max supported voting power to uint208. ([#4539](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4539))
|
||||
|
||||
#### Metatx
|
||||
|
||||
- `ERC2771Forwarder`: Added `deadline` for expiring transactions, batching, and more secure handling of `msg.value`. ([#4346](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4346))
|
||||
- `ERC2771Context`: Return the forwarder address whenever the `msg.data` of a call originating from a trusted forwarder is not long enough to contain the request signer address (i.e. `msg.data.length` is less than 20 bytes), as specified by ERC-2771. ([#4481](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4481))
|
||||
- `ERC2771Context`: Prevent revert in `_msgData()` when a call originating from a trusted forwarder is not long enough to contain the request signer address (i.e. `msg.data.length` is less than 20 bytes). Return the full calldata in that case. ([#4484](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4484))
|
||||
|
||||
#### Proxy
|
||||
|
||||
- `ProxyAdmin`: Removed `getProxyAdmin` and `getProxyImplementation` getters. ([#3820](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3820))
|
||||
- `TransparentUpgradeableProxy`: Removed `admin` and `implementation` getters, which were only callable by the proxy owner and thus not very useful. ([#3820](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3820))
|
||||
- `ERC1967Utils`: Refactored the `ERC1967Upgrade` abstract contract as a library. ([#4325](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4325))
|
||||
- `TransparentUpgradeableProxy`: Admin is now stored in an immutable variable (set during construction) to avoid unnecessary storage reads on every proxy call. This removed the ability to ever change the admin. Transfer of the upgrade capability is exclusively handled through the ownership of the `ProxyAdmin`. ([#4354](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4354))
|
||||
- Moved the logic to validate ERC-1822 during an upgrade from `ERC1967Utils` to `UUPSUpgradeable`. ([#4356](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4356))
|
||||
- `UUPSUpgradeable`, `TransparentUpgradeableProxy` and `ProxyAdmin`: Removed `upgradeTo` and `upgrade` functions, and made `upgradeToAndCall` and `upgradeAndCall` ignore the data argument if it is empty. It is no longer possible to invoke the receive function (or send value with empty data) along with an upgrade. ([#4382](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4382))
|
||||
- `BeaconProxy`: Reject value in initialization unless a payable function is explicitly invoked. ([#4382](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4382))
|
||||
- `Proxy`: Removed redundant `receive` function. ([#4434](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4434))
|
||||
- `BeaconProxy`: Use an immutable variable to store the address of the beacon. It is no longer possible for a `BeaconProxy` to upgrade by changing to another beacon. ([#4435](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4435))
|
||||
- `Initializable`: Use the namespaced storage pattern to avoid putting critical variables in slot 0. Allow reinitializer versions greater than 256. ([#4460](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4460))
|
||||
- `Initializable`: Use intermediate variables to improve readability. ([#4576](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4576))
|
||||
|
||||
#### Token
|
||||
|
||||
- `ERC20`, `ERC721`, `ERC1155`: Deleted `_beforeTokenTransfer` and `_afterTokenTransfer` hooks, added a new internal `_update` function for customizations, and refactored all extensions using those hooks to use `_update` instead. ([#3838](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3838), [#3876](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3876), [#4377](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4377))
|
||||
- `ERC20`: Removed `Approval` event previously emitted in `transferFrom` to indicate that part of the allowance was consumed. With this change, allowances are no longer reconstructible from events. See the code for guidelines on how to re-enable this event if needed. ([#4370](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4370))
|
||||
- `ERC20`: Removed the non-standard `increaseAllowance` and `decreaseAllowance` functions. ([#4585](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4585))
|
||||
- `ERC20Votes`: Changed internal vote accounting to reusable `Votes` module previously used by `ERC721Votes`. Removed implicit `ERC20Permit` inheritance. Note that the `DOMAIN_SEPARATOR` getter was previously guaranteed to be available for `ERC20Votes` contracts, but is no longer available unless `ERC20Permit` is explicitly used; ERC-5267 support is included in `ERC20Votes` with `EIP712` and is recommended as an alternative. ([#3816](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3816))
|
||||
- `SafeERC20`: Refactored `safeDecreaseAllowance` and `safeIncreaseAllowance` to support USDT-like tokens. ([#4260](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4260))
|
||||
- `SafeERC20`: Removed `safePermit` in favor of documentation-only `permit` recommendations. Based on recommendations from @trust1995 ([#4582](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4582))
|
||||
- `ERC721`: `_approve` no longer allows approving the owner of the tokenId. ([#4377](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/4377)) `_setApprovalForAll` no longer allows setting address(0) as an operator. ([#4377](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4377))
|
||||
- `ERC721`: Renamed `_requireMinted` to `_requireOwned` and added a return value with the current owner. Implemented `ownerOf` in terms of `_requireOwned`. ([#4566](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4566))
|
||||
- `ERC721Consecutive`: Added a `_firstConsecutiveId` internal function that can be overridden to change the id of the first token minted through `_mintConsecutive`. ([#4097](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4097))
|
||||
- `ERC721URIStorage`: Allow setting the token URI prior to minting. ([#4559](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4559))
|
||||
- `ERC721URIStorage`, `ERC721Royalty`: Stop resetting token-specific URI and royalties when burning. ([#4561](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4561))
|
||||
- `ERC1155`: Optimized array allocation. ([#4196](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4196))
|
||||
- `ERC1155`: Removed check for address zero in `balanceOf`. ([#4263](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4263))
|
||||
- `ERC1155`: Optimized array accesses by skipping bounds checking when unnecessary. ([#4300](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4300))
|
||||
- `ERC1155`: Bubble errors triggered in the `onERC1155Received` and `onERC1155BatchReceived` hooks. ([#4314](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4314))
|
||||
- `ERC1155Supply`: Added a `totalSupply()` function that returns the total amount of token circulating, this change will restrict the total tokens minted across all ids to 2\*\*256-1 . ([#3962](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3962))
|
||||
- `ERC1155Receiver`: Removed in favor of `ERC1155Holder`. ([#4450](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4450))
|
||||
|
||||
#### Utils
|
||||
|
||||
- `Address`: Removed the ability to customize error messages. A common custom error is always used if the underlying revert reason cannot be bubbled up. ([#4502](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4502))
|
||||
- `Arrays`: Added `unsafeMemoryAccess` helpers to read from a memory array without checking the length. ([#4300](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4300))
|
||||
- `Arrays`: Optimized `findUpperBound` by removing redundant SLOAD. ([#4442](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4442))
|
||||
- `Checkpoints`: Library moved from `utils` to `utils/structs` ([#4275](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4275))
|
||||
- `DoubleEndedQueue`: Refactored internal structure to use `uint128` instead of `int128`. This has no effect on the library interface. ([#4150](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4150))
|
||||
- `ECDSA`: Use unchecked arithmetic for the `tryRecover` function that receives the `r` and `vs` short-signature fields separately. ([#4301](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4301))
|
||||
- `EIP712`: Added internal getters for the name and version strings ([#4303](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4303))
|
||||
- `Math`: Makes `ceilDiv` to revert on 0 division even if the numerator is 0 ([#4348](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4348))
|
||||
- `Math`: Optimized stack operations in `mulDiv`. ([#4494](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4494))
|
||||
- `Math`: Renamed members of `Rounding` enum, and added a new rounding mode for "away from zero". ([#4455](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4455))
|
||||
- `MerkleProof`: Use custom error to report invalid multiproof instead of reverting with overflow panic. ([#4564](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4564))
|
||||
- `MessageHashUtils`: Added a new library for creating message digest to be used along with signing or recovery such as ECDSA or ERC-1271. These functions are moved from the `ECDSA` library. ([#4430](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4430))
|
||||
- `Nonces`: Added a new contract to keep track of user nonces. Used for signatures in `ERC20Permit`, `ERC20Votes`, and `ERC721Votes`. ([#3816](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3816))
|
||||
- `ReentrancyGuard`, `Pausable`: Moved to `utils` directory. ([#4551](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4551))
|
||||
- `Strings`: Renamed `toString(int256)` to `toStringSigned(int256)`. ([#4330](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4330))
|
||||
- Optimized `Strings.equal` ([#4262](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4262))
|
||||
|
||||
### How to migrate from 4.x
|
||||
|
||||
#### ERC20, ERC721, and ERC1155
|
||||
|
||||
These breaking changes will require modifications to ERC20, ERC721, and ERC1155 contracts, since the `_afterTokenTransfer` and `_beforeTokenTransfer` functions were removed. Thus, any customization made through those hooks should now be done overriding the new `_update` function instead.
|
||||
|
||||
Minting and burning are implemented by `_update` and customizations should be done by overriding this function as well. `_transfer`, `_mint` and `_burn` are no longer virtual (meaning they are not overridable) to guard against possible inconsistencies.
|
||||
|
||||
For example, a contract using `ERC20`'s `_beforeTokenTransfer` hook would have to be changed in the following way.
|
||||
|
||||
```diff
|
||||
-function _beforeTokenTransfer(
|
||||
+function _update(
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
) internal virtual override {
|
||||
- super._beforeTokenTransfer(from, to, amount);
|
||||
require(!condition(), "ERC20: wrong condition");
|
||||
+ super._update(from, to, amount);
|
||||
}
|
||||
```
|
||||
|
||||
#### More about ERC721
|
||||
|
||||
In the case of `ERC721`, the `_update` function does not include a `from` parameter, as the sender is implicitly the previous owner of the `tokenId`. The address of this previous owner is returned by the `_update` function, so it can be used for a posteriori checks. In addition to `to` and `tokenId`, a third parameter (`auth`) is present in this function. This parameter enabled an optional check that the caller/spender is approved to do the transfer. This check cannot be performed after the transfer (because the transfer resets the approval), and doing it before `_update` would require a duplicate call to `_ownerOf`.
|
||||
|
||||
In this logic of removing hidden SLOADs, the `_isApprovedOrOwner` function was removed in favor of a new `_isAuthorized` function. Overrides that used to target the `_isApprovedOrOwner` should now be performed on the `_isAuthorized` function. Calls to `_isApprovedOrOwner` that preceded a call to `_transfer`, `_burn` or `_approve` should be removed in favor of using the `auth` argument in `_update` and `_approve`. This is showcased in `ERC721Burnable.burn` and in `ERC721Wrapper.withdrawTo`.
|
||||
|
||||
The `_exists` function was removed. Calls to this function can be replaced by `_ownerOf(tokenId) != address(0)`.
|
||||
|
||||
#### More about ERC1155
|
||||
|
||||
Batch transfers will now emit `TransferSingle` if the batch consists of a single token, while in previous versions the `TransferBatch` event would be used for all transfers initiated through `safeBatchTransferFrom`. Both behaviors are compliant with the ERC-1155 specification.
|
||||
|
||||
#### ERC165Storage
|
||||
|
||||
Users that were registering EIP-165 interfaces with `_registerInterface` from `ERC165Storage` should instead do so so by overriding the `supportsInterface` function as seen below:
|
||||
|
||||
```solidity
|
||||
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
|
||||
return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
|
||||
}
|
||||
```
|
||||
|
||||
#### SafeMath
|
||||
|
||||
Methods in SafeMath superseded by native overflow checks in Solidity 0.8.0 were removed along with operations providing an interface for revert strings. The remaining methods were moved to `utils/Math.sol`.
|
||||
|
||||
```diff
|
||||
- import "@openzeppelin/contracts/utils/math/SafeMath.sol";
|
||||
+ import "@openzeppelin/contracts/utils/math/Math.sol";
|
||||
|
||||
function tryOperations(uint256 x, uint256 y) external view {
|
||||
- (bool overflowsAdd, uint256 resultAdd) = SafeMath.tryAdd(x, y);
|
||||
+ (bool overflowsAdd, uint256 resultAdd) = Math.tryAdd(x, y);
|
||||
- (bool overflowsSub, uint256 resultSub) = SafeMath.trySub(x, y);
|
||||
+ (bool overflowsSub, uint256 resultSub) = Math.trySub(x, y);
|
||||
- (bool overflowsMul, uint256 resultMul) = SafeMath.tryMul(x, y);
|
||||
+ (bool overflowsMul, uint256 resultMul) = Math.tryMul(x, y);
|
||||
- (bool overflowsDiv, uint256 resultDiv) = SafeMath.tryDiv(x, y);
|
||||
+ (bool overflowsDiv, uint256 resultDiv) = Math.tryDiv(x, y);
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
#### Adapting Governor modules
|
||||
|
||||
Custom Governor modules that override internal functions may require modifications if migrated to v5. In particular, the new internal functions `_queueOperations` and `_executeOperations` may need to be used. If assistance with this migration is needed reach out via the [OpenZeppelin Support Forum](https://forum.openzeppelin.com/c/support/contracts/18).
|
||||
|
||||
#### ECDSA and MessageHashUtils
|
||||
|
||||
The `ECDSA` library is now focused on signer recovery. Previously it also included utility methods for producing digests to be used with signing or recovery. These utilities have been moved to the `MessageHashUtils` library and should be imported if needed:
|
||||
|
||||
```diff
|
||||
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
|
||||
+import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
|
||||
|
||||
contract Verifier {
|
||||
using ECDSA for bytes32;
|
||||
+ using MessageHashUtils for bytes32;
|
||||
|
||||
function _verify(bytes32 data, bytes memory signature, address account) internal pure returns (bool) {
|
||||
return data
|
||||
.toEthSignedMessageHash()
|
||||
.recover(signature) == account;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Interfaces and libraries in upgradeable contracts
|
||||
|
||||
The upgradeable version of the contracts library used to include a variant suffixed with `Upgradeable` for every contract. These variants, which are produced automatically, mainly include changes for dealing with storage that don't apply to libraries and interfaces.
|
||||
|
||||
The upgradeable library no longer includes upgradeable variants for libraries and interfaces. Projects migrating to 5.0 should replace their library and interface imports with their corresponding non-upgradeable version:
|
||||
|
||||
```diff
|
||||
// Libraries
|
||||
-import {AddressUpgradeable} from '@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol';
|
||||
+import {Address} from '@openzeppelin/contracts/utils/Address.sol';
|
||||
|
||||
// Interfaces
|
||||
-import {IERC20Upgradeable} from '@openzeppelin/contracts-upgradeable/interfaces/IERC20.sol';
|
||||
+import {IERC20} from '@openzeppelin/contracts/interfaces/IERC20.sol';
|
||||
```
|
||||
|
||||
#### Offchain Considerations
|
||||
|
||||
Some changes may affect offchain systems if they rely on assumptions that are changed along with these new breaking changes. These cases are:
|
||||
|
||||
##### Relying on revert strings for processing errors
|
||||
|
||||
A concrete example is AccessControl, where it was previously advised to catch revert reasons using the following regex:
|
||||
|
||||
```
|
||||
/^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
|
||||
```
|
||||
|
||||
Instead, contracts now revert with custom errors. Systems that interact with smart contracts outside of the network should consider reliance on revert strings and possibly support the new custom errors.
|
||||
|
||||
##### Relying on storage locations for retrieving data
|
||||
|
||||
After 5.0, the storage location of some variables were changed. This is the case for `Initializable` and all the upgradeable contracts since they now use namespaced storaged locations. Any system relying on storage locations for retrieving data or detecting capabilities should be updated to support these new locations.
|
||||
|
||||
## 4.9.2 (2023-06-16)
|
||||
|
||||
- `MerkleProof`: Fix a bug in `processMultiProof` and `processMultiProofCalldata` that allows proving arbitrary leaves if the tree contains a node with value 0 at depth 1.
|
||||
|
||||
## 4.9.1 (2023-06-07)
|
||||
|
||||
- `Governor`: Add a mechanism to restrict the address of the proposer using a suffix in the description.
|
||||
|
||||
## 4.9.0 (2023-05-23)
|
||||
|
||||
- `ReentrancyGuard`: Add a `_reentrancyGuardEntered` function to expose the guard status. ([#3714](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3714))
|
||||
- `ERC721Wrapper`: add a new extension of the `ERC721` token which wraps an underlying token. Deposit and withdraw guarantee that the ownership of each token is backed by a corresponding underlying token with the same identifier. ([#3863](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3863))
|
||||
- `EnumerableMap`: add a `keys()` function that returns an array containing all the keys. ([#3920](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3920))
|
||||
- `Governor`: add a public `cancel(uint256)` function. ([#3983](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3983))
|
||||
- `Governor`: Enable timestamp operation for blockchains without a stable block time. This is achieved by connecting a Governor's internal clock to match a voting token's EIP-6372 interface. ([#3934](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3934))
|
||||
- `Strings`: add `equal` method. ([#3774](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3774))
|
||||
- `IERC5313`: Add an interface for EIP-5313 that is now final. ([#4013](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4013))
|
||||
- `IERC4906`: Add an interface for ERC-4906 that is now Final. ([#4012](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4012))
|
||||
- `StorageSlot`: Add support for `string` and `bytes`. ([#4008](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4008))
|
||||
- `Votes`, `ERC20Votes`, `ERC721Votes`: support timestamp checkpointing using EIP-6372. ([#3934](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3934))
|
||||
- `ERC4626`: Add mitigation to the inflation attack through virtual shares and assets. ([#3979](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3979))
|
||||
- `Strings`: add `toString` method for signed integers. ([#3773](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3773))
|
||||
- `ERC20Wrapper`: Make the `underlying` variable private and add a public accessor. ([#4029](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4029))
|
||||
- `EIP712`: add EIP-5267 support for better domain discovery. ([#3969](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3969))
|
||||
- `AccessControlDefaultAdminRules`: Add an extension of `AccessControl` with additional security rules for the `DEFAULT_ADMIN_ROLE`. ([#4009](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4009))
|
||||
- `SignatureChecker`: Add `isValidERC1271SignatureNow` for checking a signature directly against a smart contract using ERC-1271. ([#3932](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3932))
|
||||
- `SafeERC20`: Add a `forceApprove` function to improve compatibility with tokens behaving like USDT. ([#4067](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4067))
|
||||
- `ERC1967Upgrade`: removed contract-wide `oz-upgrades-unsafe-allow delegatecall` annotation, replaced by granular annotation in `UUPSUpgradeable`. ([#3971](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3971))
|
||||
- `ERC20Wrapper`: self wrapping and deposit by the wrapper itself are now explicitly forbidden. ([#4100](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4100))
|
||||
- `ECDSA`: optimize bytes32 computation by using assembly instead of `abi.encodePacked`. ([#3853](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3853))
|
||||
- `ERC721URIStorage`: Emit ERC-4906 `MetadataUpdate` in `_setTokenURI`. ([#4012](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4012))
|
||||
- `ShortStrings`: Added a library for handling short strings in a gas efficient way, with fallback to storage for longer strings. ([#4023](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4023))
|
||||
- `SignatureChecker`: Allow return data length greater than 32 from EIP-1271 signers. ([#4038](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4038))
|
||||
- `UUPSUpgradeable`: added granular `oz-upgrades-unsafe-allow-reachable` annotation to improve upgrade safety checks on latest version of the Upgrades Plugins (starting with `@openzeppelin/upgrades-core@1.21.0`). ([#3971](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3971))
|
||||
- `Initializable`: optimize `_disableInitializers` by using `!=` instead of `<`. ([#3787](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3787))
|
||||
- `Ownable2Step`: make `acceptOwnership` public virtual to enable usecases that require overriding it. ([#3960](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3960))
|
||||
- `UUPSUpgradeable.sol`: Change visibility to the functions `upgradeTo ` and `upgradeToAndCall ` from `external` to `public`. ([#3959](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3959))
|
||||
- `TimelockController`: Add the `CallSalt` event to emit on operation schedule. ([#4001](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4001))
|
||||
- Reformatted codebase with latest version of Prettier Solidity. ([#3898](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3898))
|
||||
- `Math`: optimize `log256` rounding check. ([#3745](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3745))
|
||||
- `ERC20Votes`: optimize by using unchecked arithmetic. ([#3748](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3748))
|
||||
- `Multicall`: annotate `multicall` function as upgrade safe to not raise a flag for its delegatecall. ([#3961](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3961))
|
||||
- `ERC20Pausable`, `ERC721Pausable`, `ERC1155Pausable`: Add note regarding missing public pausing functionality ([#4007](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4007))
|
||||
- `ECDSA`: Add a function `toDataWithIntendedValidatorHash` that encodes data with version 0x00 following EIP-191. ([#4063](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4063))
|
||||
- `MerkleProof`: optimize by using unchecked arithmetic. ([#3745](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3745))
|
||||
|
||||
### Breaking changes
|
||||
|
||||
- `EIP712`: Addition of ERC5267 support requires support for user defined value types, which was released in Solidity version 0.8.8. This requires a pragma change from `^0.8.0` to `^0.8.8`.
|
||||
@ -12,6 +337,19 @@
|
||||
- `ERC777`: The `ERC777` token standard is no longer supported by OpenZeppelin. Our implementation is now deprecated and will be removed in the next major release. The corresponding standard interfaces remain available. ([#4066](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4066))
|
||||
- `ERC1820Implementer`: The `ERC1820` pseudo-introspection mechanism is no longer supported by OpenZeppelin. Our implementation is now deprecated and will be removed in the next major release. The corresponding standard interfaces remain available. ([#4066](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4066))
|
||||
|
||||
## 4.8.3 (2023-04-13)
|
||||
|
||||
- `GovernorCompatibilityBravo`: Fix encoding of proposal data when signatures are missing.
|
||||
- `TransparentUpgradeableProxy`: Fix transparency in case of selector clash with non-decodable calldata or payable mutability. ([#4154](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4154))
|
||||
|
||||
## 4.8.2 (2023-03-02)
|
||||
|
||||
- `ERC721Consecutive`: Fixed a bug when `_mintConsecutive` is used for batches of size 1 that could lead to balance overflow. Refer to the breaking changes section in the changelog for a note on the behavior of `ERC721._beforeTokenTransfer`.
|
||||
|
||||
### Breaking changes
|
||||
|
||||
- `ERC721`: The internal function `_beforeTokenTransfer` no longer updates balances, which it previously did when `batchSize` was greater than 1. This change has no consequence unless a custom ERC721 extension is explicitly invoking `_beforeTokenTransfer`. Balance updates in extensions must now be done explicitly using `__unsafe_increaseBalance`, with a name that indicates that there is an invariant that has to be manually verified.
|
||||
|
||||
## 4.8.1 (2023-01-12)
|
||||
|
||||
- `ERC4626`: Use staticcall instead of call when fetching underlying ERC-20 decimals. ([#3943](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3943))
|
||||
|
||||
@ -95,8 +95,18 @@ In addition to the official Solidity Style Guide we have a number of other conve
|
||||
}
|
||||
```
|
||||
|
||||
* Events should be emitted immediately after the state change that they
|
||||
represent, and should be named in the past tense.
|
||||
* Functions should be declared virtual, with few exceptions listed below. The
|
||||
contract logic should be written considering that these functions may be
|
||||
overridden by developers, e.g. getting a value using an internal getter rather
|
||||
than reading directly from a state variable.
|
||||
|
||||
If function A is an "alias" of function B, i.e. it invokes function B without
|
||||
significant additional logic, then function A should not be virtual so that
|
||||
any user overrides are implemented on B, preventing inconsistencies.
|
||||
|
||||
* Events should generally be emitted immediately after the state change that they
|
||||
represent, and should be named in the past tense. Some exceptions may be made for gas
|
||||
efficiency if the result doesn't affect observable ordering of events.
|
||||
|
||||
```solidity
|
||||
function _burn(address who, uint256 value) internal {
|
||||
@ -114,4 +124,25 @@ In addition to the official Solidity Style Guide we have a number of other conve
|
||||
interface IERC777 {
|
||||
```
|
||||
|
||||
* Contracts not intended to be used standalone should be marked abstract
|
||||
so they are required to be inherited to other contracts.
|
||||
|
||||
```solidity
|
||||
abstract contract AccessControl is ..., {
|
||||
```
|
||||
|
||||
* Unchecked arithmetic blocks should contain comments explaining why overflow is guaranteed not to happen. If the reason is immediately apparent from the line above the unchecked block, the comment may be omitted.
|
||||
|
||||
* Custom errors should be declared following the [EIP-6093](https://eips.ethereum.org/EIPS/eip-6093) rationale whenever reasonable. Also, consider the following:
|
||||
|
||||
* The domain prefix should be picked in the following order:
|
||||
1. Use `ERC<number>` if the error is a violation of an ERC specification.
|
||||
2. Use the name of the underlying component where it belongs (eg. `Governor`, `ECDSA`, or `Timelock`).
|
||||
|
||||
* The location of custom errors should be decided in the following order:
|
||||
1. Take the errors from their underlying ERCs if they're already defined.
|
||||
2. Declare the errors in the underlying interface/library if the error makes sense in its context.
|
||||
3. Declare the error in the implementation if the underlying interface/library is not suitable to do so (eg. interface/library already specified in an ERC).
|
||||
4. Declare the error in an extension if the error only happens in such extension or child contracts.
|
||||
|
||||
* Custom error names should not be declared twice along the library to avoid duplicated identifier declarations when inheriting from multiple contracts.
|
||||
|
||||
31
README.md
31
README.md
@ -16,26 +16,41 @@
|
||||
|
||||
:building_construction: **Want to scale your decentralized application?** Check out [OpenZeppelin Defender](https://openzeppelin.com/defender) — a secure platform for automating and monitoring your operations.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> OpenZeppelin Contracts uses semantic versioning to communicate backwards compatibility of its API and storage layout. For upgradeable contracts, the storage layout of different major versions should be assumed incompatible, for example, it is unsafe to upgrade from 4.9.3 to 5.0.0. Learn more at [Backwards Compatibility](https://docs.openzeppelin.com/contracts/backwards-compatibility).
|
||||
|
||||
## Overview
|
||||
|
||||
### Installation
|
||||
|
||||
#### Hardhat, Truffle (npm)
|
||||
|
||||
```
|
||||
$ npm install @openzeppelin/contracts
|
||||
```
|
||||
|
||||
OpenZeppelin Contracts features a [stable API](https://docs.openzeppelin.com/contracts/releases-stability#api-stability), which means that your contracts won't break unexpectedly when upgrading to a newer minor version.
|
||||
#### Foundry (git)
|
||||
|
||||
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.
|
||||
> [!WARNING]
|
||||
> When installing via git, it is a common error to use the `master` branch. This is a development branch that should be avoided in favor of tagged releases. The release process involves security measures that the `master` branch does not guarantee.
|
||||
|
||||
> [!WARNING]
|
||||
> Foundry installs the latest version initially, but subsequent `forge update` commands will use the `master` branch.
|
||||
|
||||
```
|
||||
$ forge install OpenZeppelin/openzeppelin-contracts
|
||||
```
|
||||
|
||||
Add `@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/` in `remappings.txt.`
|
||||
|
||||
### Usage
|
||||
|
||||
Once installed, you can use the contracts in the library by importing them:
|
||||
|
||||
```solidity
|
||||
pragma solidity ^0.8.0;
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
|
||||
import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
|
||||
|
||||
contract MyCollectible is ERC721 {
|
||||
constructor() ERC721("MyCollectible", "MCO") {
|
||||
@ -57,7 +72,7 @@ The guides in the [documentation site](https://docs.openzeppelin.com/contracts)
|
||||
|
||||
The [full API](https://docs.openzeppelin.com/contracts/api/token/ERC20) is also thoroughly documented, and serves as a great reference when developing your smart contract application. You can also ask for help or follow Contracts's development in the [community forum](https://forum.openzeppelin.com).
|
||||
|
||||
Finally, you may want to take a look at the [guides on our blog](https://blog.openzeppelin.com/guides), which cover several common use cases and good practices. The following articles provide great background reading, though please note that some of the referenced tools have changed, as the tooling in the ecosystem continues to rapidly evolve.
|
||||
Finally, you may want to take a look at the [guides on our blog](https://blog.openzeppelin.com/), which cover several common use cases and good practices. The following articles provide great background reading, though please note that some of the referenced tools have changed, as the tooling in the ecosystem continues to rapidly evolve.
|
||||
|
||||
* [The Hitchhiker’s Guide to Smart Contracts in Ethereum](https://blog.openzeppelin.com/the-hitchhikers-guide-to-smart-contracts-in-ethereum-848f08001f05) will help you get an overview of the various tools available for smart contract development, and help you set up your environment.
|
||||
* [A Gentle Introduction to Ethereum Programming, Part 1](https://blog.openzeppelin.com/a-gentle-introduction-to-ethereum-programming-part-1-783cc7796094) provides very useful information on an introductory level, including many basic concepts from the Ethereum platform.
|
||||
@ -67,13 +82,15 @@ Finally, you may want to take a look at the [guides on our blog](https://blog.op
|
||||
|
||||
This project is maintained by [OpenZeppelin](https://openzeppelin.com) with the goal of providing a secure and reliable library of smart contract components for the ecosystem. We address security through risk management in various areas such as engineering and open source best practices, scoping and API design, multi-layered review processes, and incident response preparedness.
|
||||
|
||||
The security policy is detailed in [`SECURITY.md`](./SECURITY.md), and specifies how you can report security vulnerabilities, which versions will receive security patches, and how to stay informed about them. We run a [bug bounty program on Immunefi](https://immunefi.com/bounty/openzeppelin) to reward the responsible disclosure of vulnerabilities.
|
||||
The [OpenZeppelin Contracts Security Center](https://contracts.openzeppelin.com/security) contains more details about the secure development process.
|
||||
|
||||
The security policy is detailed in [`SECURITY.md`](./SECURITY.md) as well, and specifies how you can report security vulnerabilities, which versions will receive security patches, and how to stay informed about them. We run a [bug bounty program on Immunefi](https://immunefi.com/bounty/openzeppelin) to reward the responsible disclosure of vulnerabilities.
|
||||
|
||||
The engineering guidelines we follow to promote project quality can be found in [`GUIDELINES.md`](./GUIDELINES.md).
|
||||
|
||||
Past audits can be found in [`audits/`](./audits).
|
||||
|
||||
Smart contracts are a nascent techology and carry a high level of technical risk and uncertainty. Although OpenZeppelin is well known for its security audits, using OpenZeppelin Contracts is not a substitute for a security audit.
|
||||
Smart contracts are a nascent technology and carry a high level of technical risk and uncertainty. Although OpenZeppelin is well known for its security audits, using OpenZeppelin Contracts is not a substitute for a security audit.
|
||||
|
||||
OpenZeppelin Contracts is made available under the MIT License, which disclaims all warranties in relation to the project and which limits the liability of those that contribute and maintain the project, including OpenZeppelin. As set out further in the Terms, you acknowledge that you are solely responsible for any use of OpenZeppelin Contracts and you assume all risks associated with any such use.
|
||||
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
# Releasing
|
||||
|
||||
> Visit the documentation for [details about release schedule](https://docs.openzeppelin.com/contracts/releases-stability).
|
||||
|
||||
OpenZeppelin Contracts uses a fully automated release process that takes care of compiling, packaging, and publishing the library, all of which is carried out in a clean CI environment (GitHub Actions), implemented in the ([`release-cycle`](.github/workflows/release-cycle.yml)) workflow. This helps to reduce the potential for human error and inconsistencies, and ensures that the release process is ongoing and reliable.
|
||||
|
||||
## Changesets
|
||||
|
||||
@ -39,4 +39,4 @@ Note as well that the Solidity language itself only guarantees security updates
|
||||
|
||||
## Legal
|
||||
|
||||
Smart contracts are a nascent techology and carry a high level of technical risk and uncertainty. OpenZeppelin Contracts is made available under the MIT License, which disclaims all warranties in relation to the project and which limits the liability of those that contribute and maintain the project, including OpenZeppelin. Your use of the project is also governed by the terms found at www.openzeppelin.com/tos (the "Terms"). As set out in the Terms, you are solely responsible for any use of OpenZeppelin Contracts and you assume all risks associated with any such use. This Security Policy in no way evidences or represents an on-going duty by any contributor, including OpenZeppelin, to correct any flaws or alert you to all or any of the potential risks of utilizing the project.
|
||||
Smart contracts are a nascent technology and carry a high level of technical risk and uncertainty. OpenZeppelin Contracts is made available under the MIT License, which disclaims all warranties in relation to the project and which limits the liability of those that contribute and maintain the project, including OpenZeppelin. Your use of the project is also governed by the terms found at www.openzeppelin.com/tos (the "Terms"). As set out in the Terms, you are solely responsible for any use of OpenZeppelin Contracts and you assume all risks associated with any such use. This Security Policy in no way evidences or represents an on-going duty by any contributor, including OpenZeppelin, to correct any flaws or alert you to all or any of the potential risks of utilizing the project.
|
||||
|
||||
Binary file not shown.
BIN
audits/2023-05-v4.9.pdf
Normal file
BIN
audits/2023-05-v4.9.pdf
Normal file
Binary file not shown.
BIN
audits/2023-10-v5.0.pdf
Normal file
BIN
audits/2023-10-v5.0.pdf
Normal file
Binary file not shown.
@ -2,6 +2,8 @@
|
||||
|
||||
| Date | Version | Commit | Auditor | Scope | Links |
|
||||
| ------------ | ------- | --------- | ------------ | -------------------- | ----------------------------------------------------------- |
|
||||
| October 2023 | v5.0.0 | `b5a3e69` | OpenZeppelin | v5.0 Changes | [🔗](./2023-10-v5.0.pdf) |
|
||||
| May 2023 | v4.9.0 | `91df66c` | OpenZeppelin | v4.9 Changes | [🔗](./2023-05-v4.9.pdf) |
|
||||
| October 2022 | v4.8.0 | `14f98db` | OpenZeppelin | ERC4626, Checkpoints | [🔗](./2022-10-ERC4626.pdf) [🔗](./2022-10-Checkpoints.pdf) |
|
||||
| October 2018 | v2.0.0 | `dac5bcc` | LevelK | Everything | [🔗](./2018-10.pdf) |
|
||||
| March 2017 | v1.0.4 | `9c5975a` | New Alchemy | Everything | [🔗](./2017-03.md) |
|
||||
|
||||
2
certora/.gitignore
vendored
2
certora/.gitignore
vendored
@ -1 +1 @@
|
||||
munged
|
||||
patched
|
||||
|
||||
@ -1,25 +1,54 @@
|
||||
default: help
|
||||
|
||||
PATCH = applyHarness.patch
|
||||
CONTRACTS_DIR = ../contracts
|
||||
MUNGED_DIR = munged
|
||||
SRC := ../contracts
|
||||
DST := patched
|
||||
DIFF := diff
|
||||
SRCS := $(shell find $(SRC) -type f)
|
||||
DSTS := $(shell find $(DST) -type f)
|
||||
DIFFS := $(shell find $(DIFF) -type f)
|
||||
|
||||
###############################################################################
|
||||
# Apply all patches in the $DIFF folder to the $DST folder
|
||||
apply: $(DST) $(patsubst $(DIFF)/%.patch,$(DST)/%,$(subst _,/,$(DIFFS)))
|
||||
|
||||
# Reset the $DST folder
|
||||
$(DST): FORCE
|
||||
@rm -rf $@
|
||||
@cp -r $(SRC) $@
|
||||
|
||||
# Update a solidity file in the $DST directory using the corresponding patch
|
||||
$(DST)/%.sol: FORCE
|
||||
@echo Applying patch to $@
|
||||
@patch -p0 -d $(DST) < $(patsubst $(DST)_%,$(DIFF)/%.patch,$(subst /,_,$@))
|
||||
|
||||
###############################################################################
|
||||
# Record all difference between $SRC and $DST in patches
|
||||
record: $(DIFF) $(patsubst %,$(DIFF)/%.patch,$(subst /,_,$(subst $(SRC)/,,$(SRCS)) $(subst $(DST)/,,$(DSTS))))
|
||||
|
||||
# Create the $DIFF folder
|
||||
$(DIFF): FORCE
|
||||
@rm -rf $@
|
||||
@mkdir $@
|
||||
|
||||
# Create the patch file by comparing the source and the destination
|
||||
$(DIFF)/%.patch: FORCE
|
||||
@echo Generating patch $@
|
||||
@diff -ruN \
|
||||
$(patsubst $(DIFF)/%.patch,$(SRC)/%,$(subst _,/,$@)) \
|
||||
$(patsubst $(DIFF)/%.patch,$(DST)/%,$(subst _,/,$@)) \
|
||||
| sed 's+$(SRC)/++g' \
|
||||
| sed 's+$(DST)/++g' \
|
||||
> $@
|
||||
@[ -s $@ ] || rm $@
|
||||
|
||||
###############################################################################
|
||||
help:
|
||||
@echo "usage:"
|
||||
@echo " make apply: create $(DST) directory by applying the patches to $(SRC)"
|
||||
@echo " make record: record the patches capturing the differences between $(SRC) and $(DST)"
|
||||
@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 -druN $(CONTRACTS_DIR) $(MUNGED_DIR) | sed 's+../contracts/++g' | sed 's+munged/++g' > $(PATCH)
|
||||
|
||||
refresh: munged record
|
||||
|
||||
clean:
|
||||
git clean -fdX
|
||||
touch $(PATCH)
|
||||
|
||||
FORCE: ;
|
||||
|
||||
@ -1,56 +1,60 @@
|
||||
# Running the certora verification tool
|
||||
|
||||
These instructions detail the process for running CVT on the OpenZeppelin (Wizard/Governor) contracts.
|
||||
These instructions detail the process for running Certora Verification Tool on OpenZeppelin Contracts.
|
||||
|
||||
Documentation for CVT and the specification language are available
|
||||
[here](https://certora.atlassian.net/wiki/spaces/CPD/overview)
|
||||
Documentation for CVT and the specification language are available [here](https://certora.atlassian.net/wiki/spaces/CPD/overview).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Follow the [Certora installation guide](https://docs.certora.com/en/latest/docs/user-guide/getting-started/install.html) in order to get the Certora Prover Package and the `solc` executable folder in your path.
|
||||
|
||||
> **Note**
|
||||
> An API Key is required for local testing. Although the prover will run on a Github Actions' CI environment on selected Pull Requests.
|
||||
|
||||
## 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/).
|
||||
The Certora Verification Tool proves specs for contracts, which are defined by the `./specs.json` file along with their pre-configured options.
|
||||
|
||||
These scripts should be run from the root directory; for example by running
|
||||
The verification script `./run.js` is used to submit verification jobs to the Certora Verification service.
|
||||
|
||||
```
|
||||
sh certora/scripts/verifyAll.sh <meaningful comment>
|
||||
You can run it from the root of the repository with the following command:
|
||||
|
||||
```bash
|
||||
node certora/run.js [[CONTRACT_NAME:]SPEC_NAME] [OPTIONS...]
|
||||
```
|
||||
|
||||
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`).
|
||||
Where:
|
||||
|
||||
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.
|
||||
- `CONTRACT_NAME` matches the `contract` key in the `./spec.json` file and may be empty. It will run all matching contracts if not provided.
|
||||
- `SPEC_NAME` refers to a `spec` key from the `./specs.json` file. It will run every spec if not provided.
|
||||
- `OPTIONS` extend the [Certora Prover CLI options](https://docs.certora.com/en/latest/docs/prover/cli/options.html#certora-prover-cli-options) and will respect the preconfigured options in the `specs.json` file.
|
||||
|
||||
For example, to verify the `WizardFirstPriority` contract against the
|
||||
`GovernorCountingSimple` specification, you could change the `--verify` line of
|
||||
the `WizardControlFirstPriortity.sh` script to:
|
||||
> **Note**
|
||||
> A single spec may be configured to run for multiple contracts, whereas a single contract may run multiple specs.
|
||||
|
||||
```
|
||||
--verify WizardFirstPriority:certora/specs/GovernorCountingSimple.spec \
|
||||
Example usage:
|
||||
|
||||
```bash
|
||||
node certora/run.js AccessControl # Run the AccessControl spec against every contract implementing it
|
||||
```
|
||||
|
||||
## 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.
|
||||
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.
|
||||
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 by running:
|
||||
|
||||
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.
|
||||
```bash
|
||||
make -C certora apply
|
||||
```
|
||||
|
||||
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.
|
||||
Before running the `certora/run.js` script, it's required to apply the corresponding patches to the `contracts` directory, placing the output in the `certora/patched` directory. Then, the contracts are verified by running the verification for the `certora/patched` 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 `patched` 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.
|
||||
|
||||
For more information about the `make` scripts available, run:
|
||||
|
||||
```bash
|
||||
make -C certora help
|
||||
```
|
||||
|
||||
@ -1,408 +0,0 @@
|
||||
diff -druN governance/extensions/GovernorCountingSimple.sol governance/extensions/GovernorCountingSimple.sol
|
||||
--- governance/extensions/GovernorCountingSimple.sol 2023-02-27 10:59:32.652558153 +0100
|
||||
+++ governance/extensions/GovernorCountingSimple.sol 2023-02-28 16:49:10.417726143 +0100
|
||||
@@ -27,7 +27,7 @@
|
||||
mapping(address => bool) hasVoted;
|
||||
}
|
||||
|
||||
- mapping(uint256 => ProposalVote) private _proposalVotes;
|
||||
+ mapping(uint256 => ProposalVote) internal _proposalVotes; // HARNESS: private -> internal
|
||||
|
||||
/**
|
||||
* @dev See {IGovernor-COUNTING_MODE}.
|
||||
diff -druN governance/extensions/GovernorPreventLateQuorum.sol governance/extensions/GovernorPreventLateQuorum.sol
|
||||
--- governance/extensions/GovernorPreventLateQuorum.sol 2023-02-27 10:59:32.652558153 +0100
|
||||
+++ governance/extensions/GovernorPreventLateQuorum.sol 2023-02-28 16:49:10.417726143 +0100
|
||||
@@ -20,10 +20,10 @@
|
||||
abstract contract GovernorPreventLateQuorum is Governor {
|
||||
using SafeCast for uint256;
|
||||
|
||||
- uint64 private _voteExtension;
|
||||
+ uint64 internal _voteExtension; // HARNESS: private -> internal
|
||||
|
||||
/// @custom:oz-retyped-from mapping(uint256 => Timers.BlockNumber)
|
||||
- mapping(uint256 => uint64) private _extendedDeadlines;
|
||||
+ mapping(uint256 => uint64) internal _extendedDeadlines; // HARNESS: private -> internal
|
||||
|
||||
/// @dev Emitted when a proposal deadline is pushed back due to reaching quorum late in its voting period.
|
||||
event ProposalExtended(uint256 indexed proposalId, uint64 extendedDeadline);
|
||||
diff -druN governance/extensions/GovernorVotesQuorumFraction.sol governance/extensions/GovernorVotesQuorumFraction.sol
|
||||
--- governance/extensions/GovernorVotesQuorumFraction.sol 2023-02-27 10:59:32.655891529 +0100
|
||||
+++ governance/extensions/GovernorVotesQuorumFraction.sol 2023-02-28 16:49:10.417726143 +0100
|
||||
@@ -17,10 +17,10 @@
|
||||
using SafeCast for *;
|
||||
using Checkpoints for Checkpoints.Trace224;
|
||||
|
||||
- uint256 private _quorumNumerator; // DEPRECATED in favor of _quorumNumeratorHistory
|
||||
+ uint256 internal _quorumNumerator; // DEPRECATED // MUNGED private => internal
|
||||
|
||||
/// @custom:oz-retyped-from Checkpoints.History
|
||||
- Checkpoints.Trace224 private _quorumNumeratorHistory;
|
||||
+ Checkpoints.Trace224 internal _quorumNumeratorHistory; // MUNGED private => internal
|
||||
|
||||
event QuorumNumeratorUpdated(uint256 oldQuorumNumerator, uint256 newQuorumNumerator);
|
||||
|
||||
diff -druN governance/Governor.sol governance/Governor.sol
|
||||
--- governance/Governor.sol 2023-02-27 10:59:32.652558153 +0100
|
||||
+++ governance/Governor.sol 2023-02-28 16:49:10.421059488 +0100
|
||||
@@ -51,7 +51,7 @@
|
||||
string private _name;
|
||||
|
||||
/// @custom:oz-retyped-from mapping(uint256 => Governor.ProposalCore)
|
||||
- mapping(uint256 => ProposalCore) private _proposals;
|
||||
+ mapping(uint256 => ProposalCore) internal _proposals; // HARNESS: private -> internal
|
||||
|
||||
// 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},
|
||||
diff -druN governance/TimelockController.sol governance/TimelockController.sol
|
||||
--- governance/TimelockController.sol 2023-02-27 10:59:32.652558153 +0100
|
||||
+++ governance/TimelockController.sol 2023-02-28 16:49:10.421059488 +0100
|
||||
@@ -28,10 +28,10 @@
|
||||
bytes32 public constant PROPOSER_ROLE = keccak256("PROPOSER_ROLE");
|
||||
bytes32 public constant EXECUTOR_ROLE = keccak256("EXECUTOR_ROLE");
|
||||
bytes32 public constant CANCELLER_ROLE = keccak256("CANCELLER_ROLE");
|
||||
- uint256 internal constant _DONE_TIMESTAMP = uint256(1);
|
||||
+ uint256 public constant _DONE_TIMESTAMP = uint256(1); // HARNESS: internal -> public
|
||||
|
||||
mapping(bytes32 => uint256) private _timestamps;
|
||||
- uint256 private _minDelay;
|
||||
+ uint256 public _minDelay; // HARNESS: private -> public
|
||||
|
||||
/**
|
||||
* @dev Emitted when a call is scheduled as part of operation `id`.
|
||||
diff -druN governance/utils/Votes.sol governance/utils/Votes.sol
|
||||
--- governance/utils/Votes.sol 2023-02-27 10:59:32.655891529 +0100
|
||||
+++ governance/utils/Votes.sol 2023-02-28 16:49:10.421059488 +0100
|
||||
@@ -35,7 +35,25 @@
|
||||
bytes32 private constant _DELEGATION_TYPEHASH =
|
||||
keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");
|
||||
|
||||
- mapping(address => address) private _delegation;
|
||||
+ // HARNESS : Hooks cannot access any information from Checkpoints yet, so I am also updating votes and fromBlock in this struct
|
||||
+ struct Ckpt {
|
||||
+ uint32 fromBlock;
|
||||
+ uint224 votes;
|
||||
+ }
|
||||
+ mapping(address => Ckpt) public _checkpoints;
|
||||
+
|
||||
+ // HARNESSED getters
|
||||
+ function numCheckpoints(address account) public view returns (uint32) {
|
||||
+ return SafeCast.toUint32(_delegateCheckpoints[account]._checkpoints.length);
|
||||
+ }
|
||||
+ function ckptFromBlock(address account, uint32 pos) public view returns (uint32) {
|
||||
+ return _delegateCheckpoints[account]._checkpoints[pos]._key;
|
||||
+ }
|
||||
+ function ckptVotes(address account, uint32 pos) public view returns (uint224) {
|
||||
+ return _delegateCheckpoints[account]._checkpoints[pos]._value;
|
||||
+ }
|
||||
+
|
||||
+ mapping(address => address) public _delegation; // HARNESS: private -> public
|
||||
|
||||
/// @custom:oz-retyped-from mapping(address => Checkpoints.History)
|
||||
mapping(address => Checkpoints.Trace224) private _delegateCheckpoints;
|
||||
@@ -240,5 +258,5 @@
|
||||
/**
|
||||
* @dev Must return the voting units held by an account.
|
||||
*/
|
||||
- function _getVotingUnits(address) internal view virtual returns (uint256);
|
||||
+ function _getVotingUnits(address) public view virtual returns (uint256); // HARNESS: internal -> public
|
||||
}
|
||||
diff -druN proxy/utils/Initializable.sol proxy/utils/Initializable.sol
|
||||
--- proxy/utils/Initializable.sol 2023-02-27 10:59:32.655891529 +0100
|
||||
+++ proxy/utils/Initializable.sol 2023-02-28 16:49:10.421059488 +0100
|
||||
@@ -60,12 +60,12 @@
|
||||
* @dev Indicates that the contract has been initialized.
|
||||
* @custom:oz-retyped-from bool
|
||||
*/
|
||||
- uint8 private _initialized;
|
||||
+ uint8 internal _initialized; // HARNESS: private -> internal
|
||||
|
||||
/**
|
||||
* @dev Indicates that the contract is in the process of being initialized.
|
||||
*/
|
||||
- bool private _initializing;
|
||||
+ bool internal _initializing; // HARNESS: private -> internal
|
||||
|
||||
/**
|
||||
* @dev Triggered when the contract has been initialized or reinitialized.
|
||||
diff -druN token/ERC1155/ERC1155.sol token/ERC1155/ERC1155.sol
|
||||
--- token/ERC1155/ERC1155.sol 2023-02-27 10:59:32.655891529 +0100
|
||||
+++ token/ERC1155/ERC1155.sol 2023-02-28 16:49:10.421059488 +0100
|
||||
@@ -21,7 +21,7 @@
|
||||
using Address for address;
|
||||
|
||||
// Mapping from token ID to account balances
|
||||
- mapping(uint256 => mapping(address => uint256)) private _balances;
|
||||
+ mapping(uint256 => mapping(address => uint256)) internal _balances; // HARNESS: private -> internal
|
||||
|
||||
// Mapping from account to operator approvals
|
||||
mapping(address => mapping(address => bool)) private _operatorApprovals;
|
||||
@@ -451,7 +451,7 @@
|
||||
uint256 id,
|
||||
uint256 amount,
|
||||
bytes memory data
|
||||
- ) private {
|
||||
+ ) public { // HARNESS: private -> public
|
||||
if (to.isContract()) {
|
||||
try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {
|
||||
if (response != IERC1155Receiver.onERC1155Received.selector) {
|
||||
@@ -472,7 +472,7 @@
|
||||
uint256[] memory ids,
|
||||
uint256[] memory amounts,
|
||||
bytes memory data
|
||||
- ) private {
|
||||
+ ) public { // HARNESS: private -> public
|
||||
if (to.isContract()) {
|
||||
try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (
|
||||
bytes4 response
|
||||
diff -druN token/ERC20/ERC20.sol token/ERC20/ERC20.sol
|
||||
--- token/ERC20/ERC20.sol 2023-02-27 10:59:32.655891529 +0100
|
||||
+++ token/ERC20/ERC20.sol 2023-02-28 16:49:10.421059488 +0100
|
||||
@@ -248,7 +248,7 @@
|
||||
*
|
||||
* - `account` cannot be the zero address.
|
||||
*/
|
||||
- function _mint(address account, uint256 amount) internal virtual {
|
||||
+ function _mint(address account, uint256 amount) public virtual { // HARNESS: internal -> public
|
||||
require(account != address(0), "ERC20: mint to the zero address");
|
||||
|
||||
_beforeTokenTransfer(address(0), account, amount);
|
||||
@@ -274,7 +274,7 @@
|
||||
* - `account` cannot be the zero address.
|
||||
* - `account` must have at least `amount` tokens.
|
||||
*/
|
||||
- function _burn(address account, uint256 amount) internal virtual {
|
||||
+ function _burn(address account, uint256 amount) public virtual { // HARNESS: internal -> public
|
||||
require(account != address(0), "ERC20: burn from the zero address");
|
||||
|
||||
_beforeTokenTransfer(account, address(0), amount);
|
||||
diff -druN token/ERC20/extensions/ERC20Capped.sol token/ERC20/extensions/ERC20Capped.sol
|
||||
--- token/ERC20/extensions/ERC20Capped.sol 2023-02-22 15:43:36.624717708 +0100
|
||||
+++ token/ERC20/extensions/ERC20Capped.sol 2023-02-28 16:49:10.421059488 +0100
|
||||
@@ -30,7 +30,7 @@
|
||||
/**
|
||||
* @dev See {ERC20-_mint}.
|
||||
*/
|
||||
- function _mint(address account, uint256 amount) internal virtual override {
|
||||
+ function _mint(address account, uint256 amount) public virtual override { // HARNESS: internal -> public
|
||||
require(ERC20.totalSupply() + amount <= cap(), "ERC20Capped: cap exceeded");
|
||||
super._mint(account, amount);
|
||||
}
|
||||
diff -druN token/ERC20/extensions/ERC20FlashMint.sol token/ERC20/extensions/ERC20FlashMint.sol
|
||||
--- token/ERC20/extensions/ERC20FlashMint.sol 2023-02-27 10:59:32.655891529 +0100
|
||||
+++ token/ERC20/extensions/ERC20FlashMint.sol 2023-02-28 16:49:10.421059488 +0100
|
||||
@@ -53,9 +53,11 @@
|
||||
// silence warning about unused variable without the addition of bytecode.
|
||||
token;
|
||||
amount;
|
||||
- return 0;
|
||||
+ return fee; // HARNESS: made "return" nonzero
|
||||
}
|
||||
|
||||
+ uint256 public fee; // HARNESS: added it to simulate random fee amount
|
||||
+
|
||||
/**
|
||||
* @dev Returns the receiver address of the flash fee. By default this
|
||||
* implementation returns the address(0) which means the fee amount will be burnt.
|
||||
diff -druN token/ERC20/extensions/ERC20Votes.sol token/ERC20/extensions/ERC20Votes.sol
|
||||
--- token/ERC20/extensions/ERC20Votes.sol 2023-02-27 10:59:32.655891529 +0100
|
||||
+++ token/ERC20/extensions/ERC20Votes.sol 2023-02-28 16:49:10.421059488 +0100
|
||||
@@ -33,8 +33,8 @@
|
||||
bytes32 private constant _DELEGATION_TYPEHASH =
|
||||
keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");
|
||||
|
||||
- mapping(address => address) private _delegates;
|
||||
- mapping(address => Checkpoint[]) private _checkpoints;
|
||||
+ mapping(address => address) public _delegates; // HARNESS: private -> public
|
||||
+ mapping(address => Checkpoint[]) public _checkpoints; // HARNESS: private -> public
|
||||
Checkpoint[] private _totalSupplyCheckpoints;
|
||||
|
||||
/**
|
||||
@@ -186,27 +186,27 @@
|
||||
/**
|
||||
* @dev Maximum token supply. Defaults to `type(uint224).max` (2^224^ - 1).
|
||||
*/
|
||||
- function _maxSupply() internal view virtual returns (uint224) {
|
||||
+ function _maxSupply() public view virtual returns (uint224) { // HARNESS: internal -> public
|
||||
return type(uint224).max;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Snapshots the totalSupply after it has been increased.
|
||||
*/
|
||||
- function _mint(address account, uint256 amount) internal virtual override {
|
||||
+ function _mint(address account, uint256 amount) public virtual override { // HARNESS: internal -> public
|
||||
super._mint(account, amount);
|
||||
require(totalSupply() <= _maxSupply(), "ERC20Votes: total supply risks overflowing votes");
|
||||
|
||||
- _writeCheckpoint(_totalSupplyCheckpoints, _add, amount);
|
||||
+ _writeCheckpointAdd(_totalSupplyCheckpoints, amount); // HARNESS: new version without pointer
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Snapshots the totalSupply after it has been decreased.
|
||||
*/
|
||||
- function _burn(address account, uint256 amount) internal virtual override {
|
||||
+ function _burn(address account, uint256 amount) public virtual override { // HARNESS: internal -> public (to comply with the ERC20 harness)
|
||||
super._burn(account, amount);
|
||||
|
||||
- _writeCheckpoint(_totalSupplyCheckpoints, _subtract, amount);
|
||||
+ _writeCheckpointSub(_totalSupplyCheckpoints, amount); // HARNESS: new version without pointer
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -225,7 +225,7 @@
|
||||
*
|
||||
* Emits events {IVotes-DelegateChanged} and {IVotes-DelegateVotesChanged}.
|
||||
*/
|
||||
- function _delegate(address delegator, address delegatee) internal virtual {
|
||||
+ function _delegate(address delegator, address delegatee) public virtual { // HARNESS: internal -> public
|
||||
address currentDelegate = delegates(delegator);
|
||||
uint256 delegatorBalance = balanceOf(delegator);
|
||||
_delegates[delegator] = delegatee;
|
||||
@@ -238,35 +238,60 @@
|
||||
function _moveVotingPower(address src, address dst, uint256 amount) private {
|
||||
if (src != dst && amount > 0) {
|
||||
if (src != address(0)) {
|
||||
- (uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[src], _subtract, amount);
|
||||
+ (uint256 oldWeight, uint256 newWeight) = _writeCheckpointSub(_checkpoints[src], amount); // HARNESS: new version without pointer
|
||||
emit DelegateVotesChanged(src, oldWeight, newWeight);
|
||||
}
|
||||
|
||||
if (dst != address(0)) {
|
||||
- (uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[dst], _add, amount);
|
||||
+ (uint256 oldWeight, uint256 newWeight) = _writeCheckpointAdd(_checkpoints[dst], amount); // HARNESS: new version without pointer
|
||||
emit DelegateVotesChanged(dst, oldWeight, newWeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- function _writeCheckpoint(
|
||||
- Checkpoint[] storage ckpts,
|
||||
- function(uint256, uint256) view returns (uint256) op,
|
||||
- uint256 delta
|
||||
- ) private returns (uint256 oldWeight, uint256 newWeight) {
|
||||
+ // HARNESS: split _writeCheckpoint() to two functions as a workaround for function pointers that cannot be managed by the tool
|
||||
+ // function _writeCheckpoint(
|
||||
+ // Checkpoint[] storage ckpts,
|
||||
+ // function(uint256, uint256) view returns (uint256) op,
|
||||
+ // uint256 delta
|
||||
+ // ) private returns (uint256 oldWeight, uint256 newWeight) {
|
||||
+ // uint256 pos = ckpts.length;
|
||||
+
|
||||
+ // unchecked {
|
||||
+ // Checkpoint memory oldCkpt = pos == 0 ? Checkpoint(0, 0) : _unsafeAccess(ckpts, pos - 1);
|
||||
+
|
||||
+ // oldWeight = oldCkpt.votes;
|
||||
+ // newWeight = op(oldWeight, delta);
|
||||
+
|
||||
+ // if (pos > 0 && oldCkpt.fromBlock == clock()) {
|
||||
+ // _unsafeAccess(ckpts, pos - 1).votes = SafeCast.toUint224(newWeight);
|
||||
+ // } else {
|
||||
+ // ckpts.push(Checkpoint({fromBlock: SafeCast.toUint32(clock()), votes: SafeCast.toUint224(newWeight)}));
|
||||
+ // }
|
||||
+ // }
|
||||
+ // }
|
||||
+
|
||||
+ function _writeCheckpointAdd(Checkpoint[] storage ckpts, uint256 delta) private returns (uint256 oldWeight, uint256 newWeight) {
|
||||
uint256 pos = ckpts.length;
|
||||
+ oldWeight = pos == 0 ? 0 : ckpts[pos - 1].votes;
|
||||
+ newWeight = _add(oldWeight, delta);
|
||||
|
||||
- unchecked {
|
||||
- Checkpoint memory oldCkpt = pos == 0 ? Checkpoint(0, 0) : _unsafeAccess(ckpts, pos - 1);
|
||||
+ if (pos > 0 && ckpts[pos - 1].fromBlock == clock()) {
|
||||
+ ckpts[pos - 1].votes = SafeCast.toUint224(newWeight);
|
||||
+ } else {
|
||||
+ ckpts.push(Checkpoint({fromBlock: SafeCast.toUint32(clock()), votes: SafeCast.toUint224(newWeight)}));
|
||||
+ }
|
||||
+ }
|
||||
|
||||
- oldWeight = oldCkpt.votes;
|
||||
- newWeight = op(oldWeight, delta);
|
||||
+ function _writeCheckpointSub(Checkpoint[] storage ckpts, uint256 delta) private returns (uint256 oldWeight, uint256 newWeight) {
|
||||
+ uint256 pos = ckpts.length;
|
||||
+ oldWeight = pos == 0 ? 0 : ckpts[pos - 1].votes;
|
||||
+ newWeight = _subtract(oldWeight, delta);
|
||||
|
||||
- if (pos > 0 && oldCkpt.fromBlock == clock()) {
|
||||
- _unsafeAccess(ckpts, pos - 1).votes = SafeCast.toUint224(newWeight);
|
||||
- } else {
|
||||
- ckpts.push(Checkpoint({fromBlock: SafeCast.toUint32(clock()), votes: SafeCast.toUint224(newWeight)}));
|
||||
- }
|
||||
+ if (pos > 0 && ckpts[pos - 1].fromBlock == clock()) {
|
||||
+ ckpts[pos - 1].votes = SafeCast.toUint224(newWeight);
|
||||
+ } else {
|
||||
+ ckpts.push(Checkpoint({fromBlock: SafeCast.toUint32(clock()), votes: SafeCast.toUint224(newWeight)}));
|
||||
}
|
||||
}
|
||||
|
||||
diff -druN token/ERC20/extensions/ERC20Wrapper.sol token/ERC20/extensions/ERC20Wrapper.sol
|
||||
--- token/ERC20/extensions/ERC20Wrapper.sol 2023-02-27 10:59:32.655891529 +0100
|
||||
+++ token/ERC20/extensions/ERC20Wrapper.sol 2023-02-28 16:49:10.421059488 +0100
|
||||
@@ -62,7 +62,7 @@
|
||||
* @dev Mint wrapped token to cover any underlyingTokens that would have been transferred by mistake. Internal
|
||||
* function that can be exposed with access control if desired.
|
||||
*/
|
||||
- function _recover(address account) internal virtual returns (uint256) {
|
||||
+ function _recover(address account) public virtual returns (uint256) { // HARNESS: internal -> public
|
||||
uint256 value = _underlying.balanceOf(address(this)) - totalSupply();
|
||||
_mint(account, value);
|
||||
return value;
|
||||
diff -druN token/ERC721/extensions/ERC721Votes.sol token/ERC721/extensions/ERC721Votes.sol
|
||||
--- token/ERC721/extensions/ERC721Votes.sol 2023-02-27 10:59:32.655891529 +0100
|
||||
+++ token/ERC721/extensions/ERC721Votes.sol 2023-02-28 16:49:10.421059488 +0100
|
||||
@@ -35,7 +35,7 @@
|
||||
/**
|
||||
* @dev Returns the balance of `account`.
|
||||
*/
|
||||
- function _getVotingUnits(address account) internal view virtual override returns (uint256) {
|
||||
+ function _getVotingUnits(address account) public view virtual override returns (uint256) { // HARNESS: internal -> public
|
||||
return balanceOf(account);
|
||||
}
|
||||
}
|
||||
diff -druN utils/Address.sol utils/Address.sol
|
||||
--- utils/Address.sol 2023-02-27 10:59:32.659224903 +0100
|
||||
+++ utils/Address.sol 2023-02-28 16:49:10.421059488 +0100
|
||||
@@ -197,7 +197,7 @@
|
||||
bool success,
|
||||
bytes memory returndata,
|
||||
string memory errorMessage
|
||||
- ) internal view returns (bytes memory) {
|
||||
+ ) internal view returns (bytes memory val) { // MUNGED undeterministic return causes error for Prover
|
||||
if (success) {
|
||||
if (returndata.length == 0) {
|
||||
// only check isContract if the call was successful and the return data is empty
|
||||
@@ -220,7 +220,7 @@
|
||||
bool success,
|
||||
bytes memory returndata,
|
||||
string memory errorMessage
|
||||
- ) internal pure returns (bytes memory) {
|
||||
+ ) internal pure returns (bytes memory val) { // MUNGED undeterministic return causes error for Prover
|
||||
if (success) {
|
||||
return returndata;
|
||||
} else {
|
||||
diff -druN utils/Checkpoints.sol utils/Checkpoints.sol
|
||||
--- utils/Checkpoints.sol 2023-02-27 10:59:32.659224903 +0100
|
||||
+++ utils/Checkpoints.sol 2023-02-28 16:49:10.424392833 +0100
|
||||
@@ -84,13 +84,13 @@
|
||||
*
|
||||
* Returns previous value and new value.
|
||||
*/
|
||||
- function push(
|
||||
- History storage self,
|
||||
- function(uint256, uint256) view returns (uint256) op,
|
||||
- uint256 delta
|
||||
- ) internal returns (uint256, uint256) {
|
||||
- return push(self, op(latest(self), delta));
|
||||
- }
|
||||
+ // function push(
|
||||
+ // History storage self,
|
||||
+ // function(uint256, uint256) view returns (uint256) op,
|
||||
+ // uint256 delta
|
||||
+ // ) internal returns (uint256, uint256) {
|
||||
+ // return push(self, op(latest(self), delta));
|
||||
+ // }
|
||||
|
||||
/**
|
||||
* @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints.
|
||||
97
certora/diff/access_manager_AccessManager.sol.patch
Normal file
97
certora/diff/access_manager_AccessManager.sol.patch
Normal file
@ -0,0 +1,97 @@
|
||||
--- access/manager/AccessManager.sol 2023-10-05 12:17:09.694051809 -0300
|
||||
+++ access/manager/AccessManager.sol 2023-10-05 12:26:18.498688718 -0300
|
||||
@@ -6,7 +6,6 @@
|
||||
import {IAccessManaged} from "./IAccessManaged.sol";
|
||||
import {Address} from "../../utils/Address.sol";
|
||||
import {Context} from "../../utils/Context.sol";
|
||||
-import {Multicall} from "../../utils/Multicall.sol";
|
||||
import {Math} from "../../utils/math/Math.sol";
|
||||
import {Time} from "../../utils/types/Time.sol";
|
||||
|
||||
@@ -57,7 +56,8 @@
|
||||
* mindful of the danger associated with functions such as {{Ownable-renounceOwnership}} or
|
||||
* {{AccessControl-renounceRole}}.
|
||||
*/
|
||||
-contract AccessManager is Context, Multicall, IAccessManager {
|
||||
+// NOTE: The FV version of this contract doesn't include Multicall because CVL HAVOCs on any `delegatecall`.
|
||||
+contract AccessManager is Context, IAccessManager {
|
||||
using Time for *;
|
||||
|
||||
// Structure that stores the details for a target contract.
|
||||
@@ -105,7 +105,7 @@
|
||||
|
||||
// Used to identify operations that are currently being executed via {execute}.
|
||||
// This should be transient storage when supported by the EVM.
|
||||
- bytes32 private _executionId;
|
||||
+ bytes32 internal _executionId; // private → internal for FV
|
||||
|
||||
/**
|
||||
* @dev Check that the caller is authorized to perform the operation, following the restrictions encoded in
|
||||
@@ -253,6 +253,11 @@
|
||||
_setGrantDelay(roleId, newDelay);
|
||||
}
|
||||
|
||||
+ // Exposed for FV
|
||||
+ function _getTargetAdminDelayFull(address target) internal view virtual returns (uint32, uint32, uint48) {
|
||||
+ return _targets[target].adminDelay.getFull();
|
||||
+ }
|
||||
+
|
||||
/**
|
||||
* @dev Internal version of {grantRole} without access control. Returns true if the role was newly granted.
|
||||
*
|
||||
@@ -287,6 +292,11 @@
|
||||
return newMember;
|
||||
}
|
||||
|
||||
+ // Exposed for FV
|
||||
+ function _getRoleGrantDelayFull(uint64 roleId) internal view virtual returns (uint32, uint32, uint48) {
|
||||
+ return _roles[roleId].grantDelay.getFull();
|
||||
+ }
|
||||
+
|
||||
/**
|
||||
* @dev Internal version of {revokeRole} without access control. This logic is also used by {renounceRole}.
|
||||
* Returns true if the role was previously granted.
|
||||
@@ -586,7 +596,7 @@
|
||||
/**
|
||||
* @dev Check if the current call is authorized according to admin logic.
|
||||
*/
|
||||
- function _checkAuthorized() private {
|
||||
+ function _checkAuthorized() internal virtual { // private → internal virtual for FV
|
||||
address caller = _msgSender();
|
||||
(bool immediate, uint32 delay) = _canCallSelf(caller, _msgData());
|
||||
if (!immediate) {
|
||||
@@ -609,7 +619,7 @@
|
||||
*/
|
||||
function _getAdminRestrictions(
|
||||
bytes calldata data
|
||||
- ) private view returns (bool restricted, uint64 roleAdminId, uint32 executionDelay) {
|
||||
+ ) internal view returns (bool restricted, uint64 roleAdminId, uint32 executionDelay) { // private → internal for FV
|
||||
if (data.length < 4) {
|
||||
return (false, 0, 0);
|
||||
}
|
||||
@@ -662,7 +672,7 @@
|
||||
address caller,
|
||||
address target,
|
||||
bytes calldata data
|
||||
- ) private view returns (bool immediate, uint32 delay) {
|
||||
+ ) internal view returns (bool immediate, uint32 delay) { // private → internal for FV
|
||||
if (target == address(this)) {
|
||||
return _canCallSelf(caller, data);
|
||||
} else {
|
||||
@@ -716,14 +726,14 @@
|
||||
/**
|
||||
* @dev Extracts the selector from calldata. Panics if data is not at least 4 bytes
|
||||
*/
|
||||
- function _checkSelector(bytes calldata data) private pure returns (bytes4) {
|
||||
+ function _checkSelector(bytes calldata data) internal pure returns (bytes4) { // private → internal for FV
|
||||
return bytes4(data[0:4]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Hashing function for execute protection
|
||||
*/
|
||||
- function _hashExecutionId(address target, bytes4 selector) private pure returns (bytes32) {
|
||||
+ function _hashExecutionId(address target, bytes4 selector) internal pure returns (bytes32) { // private → internal for FV
|
||||
return keccak256(abi.encode(target, selector));
|
||||
}
|
||||
}
|
||||
46
certora/harnesses/AccessControlDefaultAdminRulesHarness.sol
Normal file
46
certora/harnesses/AccessControlDefaultAdminRulesHarness.sol
Normal file
@ -0,0 +1,46 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {AccessControlDefaultAdminRules} from "../patched/access/extensions/AccessControlDefaultAdminRules.sol";
|
||||
|
||||
contract AccessControlDefaultAdminRulesHarness is AccessControlDefaultAdminRules {
|
||||
uint48 private _delayIncreaseWait;
|
||||
|
||||
constructor(
|
||||
uint48 initialDelay,
|
||||
address initialDefaultAdmin,
|
||||
uint48 delayIncreaseWait
|
||||
) AccessControlDefaultAdminRules(initialDelay, initialDefaultAdmin) {
|
||||
_delayIncreaseWait = delayIncreaseWait;
|
||||
}
|
||||
|
||||
// FV
|
||||
function pendingDefaultAdmin_() external view returns (address) {
|
||||
(address newAdmin, ) = pendingDefaultAdmin();
|
||||
return newAdmin;
|
||||
}
|
||||
|
||||
function pendingDefaultAdminSchedule_() external view returns (uint48) {
|
||||
(, uint48 schedule) = pendingDefaultAdmin();
|
||||
return schedule;
|
||||
}
|
||||
|
||||
function pendingDelay_() external view returns (uint48) {
|
||||
(uint48 newDelay, ) = pendingDefaultAdminDelay();
|
||||
return newDelay;
|
||||
}
|
||||
|
||||
function pendingDelaySchedule_() external view returns (uint48) {
|
||||
(, uint48 schedule) = pendingDefaultAdminDelay();
|
||||
return schedule;
|
||||
}
|
||||
|
||||
function delayChangeWait_(uint48 newDelay) external view returns (uint48) {
|
||||
return _delayChangeWait(newDelay);
|
||||
}
|
||||
|
||||
// Overrides
|
||||
function defaultAdminDelayIncreaseWait() public view override returns (uint48) {
|
||||
return _delayIncreaseWait;
|
||||
}
|
||||
}
|
||||
@ -1,8 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControl.sol)
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../munged/access/AccessControl.sol";
|
||||
import {AccessControl} from "../patched/access/AccessControl.sol";
|
||||
|
||||
contract AccessControlHarness is AccessControl {}
|
||||
|
||||
58
certora/harnesses/DoubleEndedQueueHarness.sol
Normal file
58
certora/harnesses/DoubleEndedQueueHarness.sol
Normal file
@ -0,0 +1,58 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {DoubleEndedQueue} from "../patched/utils/structs/DoubleEndedQueue.sol";
|
||||
|
||||
contract DoubleEndedQueueHarness {
|
||||
using DoubleEndedQueue for DoubleEndedQueue.Bytes32Deque;
|
||||
|
||||
DoubleEndedQueue.Bytes32Deque private _deque;
|
||||
|
||||
function pushFront(bytes32 value) external {
|
||||
_deque.pushFront(value);
|
||||
}
|
||||
|
||||
function pushBack(bytes32 value) external {
|
||||
_deque.pushBack(value);
|
||||
}
|
||||
|
||||
function popFront() external returns (bytes32 value) {
|
||||
return _deque.popFront();
|
||||
}
|
||||
|
||||
function popBack() external returns (bytes32 value) {
|
||||
return _deque.popBack();
|
||||
}
|
||||
|
||||
function clear() external {
|
||||
_deque.clear();
|
||||
}
|
||||
|
||||
function begin() external view returns (uint128) {
|
||||
return _deque._begin;
|
||||
}
|
||||
|
||||
function end() external view returns (uint128) {
|
||||
return _deque._end;
|
||||
}
|
||||
|
||||
function length() external view returns (uint256) {
|
||||
return _deque.length();
|
||||
}
|
||||
|
||||
function empty() external view returns (bool) {
|
||||
return _deque.empty();
|
||||
}
|
||||
|
||||
function front() external view returns (bytes32 value) {
|
||||
return _deque.front();
|
||||
}
|
||||
|
||||
function back() external view returns (bytes32 value) {
|
||||
return _deque.back();
|
||||
}
|
||||
|
||||
function at_(uint256 index) external view returns (bytes32 value) {
|
||||
return _deque.at(index);
|
||||
}
|
||||
}
|
||||
@ -1,5 +0,0 @@
|
||||
import "../../munged/token/ERC1155/extensions/ERC1155Burnable.sol";
|
||||
|
||||
contract ERC1155BurnableHarness is ERC1155Burnable {
|
||||
constructor(string memory uri_) ERC1155(uri_) {}
|
||||
}
|
||||
@ -1,41 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.2;
|
||||
import "../../munged/token/ERC1155/ERC1155.sol";
|
||||
|
||||
contract ERC1155Harness is ERC1155 {
|
||||
constructor(string memory uri_) ERC1155(uri_) {}
|
||||
|
||||
function burn(
|
||||
address from,
|
||||
uint256 id,
|
||||
uint256 amount
|
||||
) public virtual {
|
||||
_burn(from, id, amount);
|
||||
}
|
||||
|
||||
function burnBatch(
|
||||
address from,
|
||||
uint256[] memory ids,
|
||||
uint256[] memory amounts
|
||||
) public virtual {
|
||||
_burnBatch(from, ids, amounts);
|
||||
}
|
||||
|
||||
function mint(
|
||||
address to,
|
||||
uint256 id,
|
||||
uint256 amount,
|
||||
bytes memory data
|
||||
) public virtual {
|
||||
_mint(to, id, amount, data);
|
||||
}
|
||||
|
||||
function mintBatch(
|
||||
address to,
|
||||
uint256[] memory ids,
|
||||
uint256[] memory amounts,
|
||||
bytes memory data
|
||||
) public virtual {
|
||||
_mintBatch(to, ids, amounts, data);
|
||||
}
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
import "../../munged/token/ERC1155/extensions/ERC1155Pausable.sol";
|
||||
|
||||
contract ERC1155PausableHarness is ERC1155Pausable {
|
||||
constructor(string memory uri_) ERC1155(uri_) {}
|
||||
|
||||
function pause() public {
|
||||
_pause();
|
||||
}
|
||||
|
||||
function unpause() public {
|
||||
_unpause();
|
||||
}
|
||||
|
||||
function onlyWhenPausedMethod() public whenPaused {}
|
||||
|
||||
function onlyWhenNotPausedMethod() public whenNotPaused {}
|
||||
}
|
||||
@ -1,65 +0,0 @@
|
||||
import "../../munged/token/ERC1155/extensions/ERC1155Supply.sol";
|
||||
|
||||
contract ERC1155SupplyHarness is ERC1155Supply {
|
||||
address public owner;
|
||||
|
||||
constructor(string memory uri_) ERC1155(uri_) {
|
||||
owner = msg.sender;
|
||||
}
|
||||
|
||||
// workaround for problem caused by `exists` being a CVL keyword
|
||||
function exists_wrapper(uint256 id) public view virtual returns (bool) {
|
||||
return exists(id);
|
||||
}
|
||||
|
||||
// These rules were not implemented in the base but there are changes in supply
|
||||
// that are affected by the internal contracts so we implemented them. We assume
|
||||
// only the owner can call any of these functions to be able to test them but also
|
||||
// limit false positives.
|
||||
|
||||
modifier onlyOwner() {
|
||||
require(msg.sender == owner);
|
||||
_;
|
||||
}
|
||||
|
||||
function burn(
|
||||
address from,
|
||||
uint256 id,
|
||||
uint256 amount
|
||||
) public virtual onlyOwner {
|
||||
_burn(from, id, amount);
|
||||
}
|
||||
|
||||
function burnBatch(
|
||||
address from,
|
||||
uint256[] memory ids,
|
||||
uint256[] memory amounts
|
||||
) public virtual onlyOwner {
|
||||
_burnBatch(from, ids, amounts);
|
||||
}
|
||||
|
||||
function mint(
|
||||
address to,
|
||||
uint256 id,
|
||||
uint256 amount,
|
||||
bytes memory data
|
||||
) public virtual onlyOwner {
|
||||
_mint(to, id, amount, data);
|
||||
}
|
||||
|
||||
function mintBatch(
|
||||
address to,
|
||||
uint256[] memory ids,
|
||||
uint256[] memory amounts,
|
||||
bytes memory data
|
||||
) public virtual onlyOwner {
|
||||
_mintBatch(to, ids, amounts, data);
|
||||
}
|
||||
|
||||
// In order to check the invariant that zero address never holds any tokens, we need to remove the require
|
||||
// from this function.
|
||||
function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {
|
||||
// require(account != address(0), "ERC1155: address zero is not a valid owner");
|
||||
return _balances[id][account];
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,36 @@
|
||||
import "../munged/token/ERC20/extensions/ERC20FlashMint.sol";
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
contract ERC20FlashMintHarness is ERC20FlashMint {
|
||||
constructor(string memory name, string memory symbol) ERC20(name, symbol) {}
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import "../patched/token/ERC20/ERC20.sol";
|
||||
import "../patched/token/ERC20/extensions/ERC20Permit.sol";
|
||||
import "../patched/token/ERC20/extensions/ERC20FlashMint.sol";
|
||||
|
||||
contract ERC20FlashMintHarness is ERC20, ERC20Permit, ERC20FlashMint {
|
||||
uint256 someFee;
|
||||
address someFeeReceiver;
|
||||
|
||||
constructor(string memory name, string memory symbol) ERC20(name, symbol) ERC20Permit(name) {}
|
||||
|
||||
function mint(address account, uint256 amount) external {
|
||||
_mint(account, amount);
|
||||
}
|
||||
|
||||
function burn(address account, uint256 amount) external {
|
||||
_burn(account, amount);
|
||||
}
|
||||
|
||||
// public accessor
|
||||
function flashFeeReceiver() public view returns (address) {
|
||||
return someFeeReceiver;
|
||||
}
|
||||
|
||||
// internal hook
|
||||
function _flashFee(address, uint256) internal view override returns (uint256) {
|
||||
return someFee;
|
||||
}
|
||||
|
||||
function _flashFeeReceiver() internal view override returns (address) {
|
||||
return someFeeReceiver;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,16 @@
|
||||
import "../munged/token/ERC20/extensions/draft-ERC20Permit.sol";
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
contract ERC20PermitHarness is ERC20, ERC20Permit {
|
||||
import {ERC20Permit, ERC20} from "../patched/token/ERC20/extensions/ERC20Permit.sol";
|
||||
|
||||
contract ERC20PermitHarness is ERC20Permit {
|
||||
constructor(string memory name, string memory symbol) ERC20(name, symbol) ERC20Permit(name) {}
|
||||
|
||||
function mint(address account, uint256 amount) external {
|
||||
_mint(account, amount);
|
||||
}
|
||||
|
||||
function burn(address account, uint256 amount) external {
|
||||
_burn(account, amount);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,26 +0,0 @@
|
||||
import "../munged/token/ERC20/extensions/ERC20Votes.sol";
|
||||
|
||||
contract ERC20VotesHarness is ERC20Votes {
|
||||
constructor(string memory name, string memory symbol) ERC20(name, symbol) ERC20Permit(name) {}
|
||||
|
||||
function ckptFromBlock(address account, uint32 pos) public view returns (uint32) {
|
||||
return _checkpoints[account][pos].fromBlock;
|
||||
}
|
||||
|
||||
function ckptVotes(address account, uint32 pos) public view returns (uint224) {
|
||||
return _checkpoints[account][pos].fromBlock;
|
||||
}
|
||||
|
||||
function unsafeNumCheckpoints(address account) public view returns (uint256) {
|
||||
return _checkpoints[account].length;
|
||||
}
|
||||
|
||||
function delegateBySig(
|
||||
address delegatee,
|
||||
uint256 nonce,
|
||||
uint256 expiry,
|
||||
uint8 v,
|
||||
bytes32 r,
|
||||
bytes32 s
|
||||
) public virtual override {}
|
||||
}
|
||||
@ -1,11 +1,16 @@
|
||||
import "../munged/token/ERC20/extensions/ERC20Wrapper.sol";
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
contract ERC20WrapperHarness is ERC20Wrapper {
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {ERC20Permit} from "../patched/token/ERC20/extensions/ERC20Permit.sol";
|
||||
import {ERC20Wrapper, IERC20, ERC20} from "../patched/token/ERC20/extensions/ERC20Wrapper.sol";
|
||||
|
||||
contract ERC20WrapperHarness is ERC20Permit, ERC20Wrapper {
|
||||
constructor(
|
||||
IERC20 _underlying,
|
||||
string memory _name,
|
||||
string memory _symbol
|
||||
) ERC20(_name, _symbol) ERC20Wrapper(_underlying) {}
|
||||
) ERC20(_name, _symbol) ERC20Permit(_name) ERC20Wrapper(_underlying) {}
|
||||
|
||||
function underlyingTotalSupply() public view returns (uint256) {
|
||||
return underlying().totalSupply();
|
||||
@ -14,4 +19,16 @@ contract ERC20WrapperHarness is ERC20Wrapper {
|
||||
function underlyingBalanceOf(address account) public view returns (uint256) {
|
||||
return underlying().balanceOf(account);
|
||||
}
|
||||
|
||||
function underlyingAllowanceToThis(address account) public view returns (uint256) {
|
||||
return underlying().allowance(account, address(this));
|
||||
}
|
||||
|
||||
function recover(address account) public returns (uint256) {
|
||||
return _recover(account);
|
||||
}
|
||||
|
||||
function decimals() public view override(ERC20Wrapper, ERC20) returns (uint8) {
|
||||
return super.decimals();
|
||||
}
|
||||
}
|
||||
|
||||
13
certora/harnesses/ERC3156FlashBorrowerHarness.sol
Normal file
13
certora/harnesses/ERC3156FlashBorrowerHarness.sol
Normal file
@ -0,0 +1,13 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import {IERC3156FlashBorrower} from "../patched/interfaces/IERC3156FlashBorrower.sol";
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
contract ERC3156FlashBorrowerHarness is IERC3156FlashBorrower {
|
||||
bytes32 somethingToReturn;
|
||||
|
||||
function onFlashLoan(address, address, uint256, uint256, bytes calldata) external view override returns (bytes32) {
|
||||
return somethingToReturn;
|
||||
}
|
||||
}
|
||||
33
certora/harnesses/ERC721Harness.sol
Normal file
33
certora/harnesses/ERC721Harness.sol
Normal file
@ -0,0 +1,33 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {ERC721} from "../patched/token/ERC721/ERC721.sol";
|
||||
|
||||
contract ERC721Harness is ERC721 {
|
||||
constructor(string memory name, string memory symbol) ERC721(name, symbol) {}
|
||||
|
||||
function mint(address account, uint256 tokenId) external {
|
||||
_mint(account, tokenId);
|
||||
}
|
||||
|
||||
function safeMint(address to, uint256 tokenId) external {
|
||||
_safeMint(to, tokenId);
|
||||
}
|
||||
|
||||
function safeMint(address to, uint256 tokenId, bytes memory data) external {
|
||||
_safeMint(to, tokenId, data);
|
||||
}
|
||||
|
||||
function burn(uint256 tokenId) external {
|
||||
_burn(tokenId);
|
||||
}
|
||||
|
||||
function unsafeOwnerOf(uint256 tokenId) external view returns (address) {
|
||||
return _ownerOf(tokenId);
|
||||
}
|
||||
|
||||
function unsafeGetApproved(uint256 tokenId) external view returns (address) {
|
||||
return _getApproved(tokenId);
|
||||
}
|
||||
}
|
||||
11
certora/harnesses/ERC721ReceiverHarness.sol
Normal file
11
certora/harnesses/ERC721ReceiverHarness.sol
Normal file
@ -0,0 +1,11 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import "../patched/interfaces/IERC721Receiver.sol";
|
||||
|
||||
contract ERC721ReceiverHarness is IERC721Receiver {
|
||||
function onERC721Received(address, address, uint256, bytes calldata) external pure returns (bytes4) {
|
||||
return this.onERC721Received.selector;
|
||||
}
|
||||
}
|
||||
@ -1,26 +0,0 @@
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../munged/token/ERC721/extensions/draft-ERC721Votes.sol";
|
||||
|
||||
contract ERC721VotesHarness is ERC721Votes {
|
||||
constructor(string memory name, string memory symbol) ERC721(name, symbol) EIP712(name, symbol) {}
|
||||
|
||||
function delegateBySig(
|
||||
address delegatee,
|
||||
uint256 nonce,
|
||||
uint256 expiry,
|
||||
uint8 v,
|
||||
bytes32 r,
|
||||
bytes32 s
|
||||
) public virtual override {
|
||||
assert(true);
|
||||
}
|
||||
|
||||
function mint(address account, uint256 tokenID) public {
|
||||
_mint(account, tokenID);
|
||||
}
|
||||
|
||||
function burn(uint256 tokenID) public {
|
||||
_burn(tokenID);
|
||||
}
|
||||
}
|
||||
55
certora/harnesses/EnumerableMapHarness.sol
Normal file
55
certora/harnesses/EnumerableMapHarness.sol
Normal file
@ -0,0 +1,55 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {EnumerableMap} from "../patched/utils/structs/EnumerableMap.sol";
|
||||
|
||||
contract EnumerableMapHarness {
|
||||
using EnumerableMap for EnumerableMap.Bytes32ToBytes32Map;
|
||||
|
||||
EnumerableMap.Bytes32ToBytes32Map private _map;
|
||||
|
||||
function set(bytes32 key, bytes32 value) public returns (bool) {
|
||||
return _map.set(key, value);
|
||||
}
|
||||
|
||||
function remove(bytes32 key) public returns (bool) {
|
||||
return _map.remove(key);
|
||||
}
|
||||
|
||||
function contains(bytes32 key) public view returns (bool) {
|
||||
return _map.contains(key);
|
||||
}
|
||||
|
||||
function length() public view returns (uint256) {
|
||||
return _map.length();
|
||||
}
|
||||
|
||||
function key_at(uint256 index) public view returns (bytes32) {
|
||||
(bytes32 key,) = _map.at(index);
|
||||
return key;
|
||||
}
|
||||
|
||||
function value_at(uint256 index) public view returns (bytes32) {
|
||||
(,bytes32 value) = _map.at(index);
|
||||
return value;
|
||||
}
|
||||
|
||||
function tryGet_contains(bytes32 key) public view returns (bool) {
|
||||
(bool contained,) = _map.tryGet(key);
|
||||
return contained;
|
||||
}
|
||||
|
||||
function tryGet_value(bytes32 key) public view returns (bytes32) {
|
||||
(,bytes32 value) = _map.tryGet(key);
|
||||
return value;
|
||||
}
|
||||
|
||||
function get(bytes32 key) public view returns (bytes32) {
|
||||
return _map.get(key);
|
||||
}
|
||||
|
||||
function _indexOf(bytes32 key) public view returns (uint256) {
|
||||
return _map._keys._inner._indexes[key];
|
||||
}
|
||||
}
|
||||
35
certora/harnesses/EnumerableSetHarness.sol
Normal file
35
certora/harnesses/EnumerableSetHarness.sol
Normal file
@ -0,0 +1,35 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {EnumerableSet} from "../patched/utils/structs/EnumerableSet.sol";
|
||||
|
||||
contract EnumerableSetHarness {
|
||||
using EnumerableSet for EnumerableSet.Bytes32Set;
|
||||
|
||||
EnumerableSet.Bytes32Set private _set;
|
||||
|
||||
function add(bytes32 value) public returns (bool) {
|
||||
return _set.add(value);
|
||||
}
|
||||
|
||||
function remove(bytes32 value) public returns (bool) {
|
||||
return _set.remove(value);
|
||||
}
|
||||
|
||||
function contains(bytes32 value) public view returns (bool) {
|
||||
return _set.contains(value);
|
||||
}
|
||||
|
||||
function length() public view returns (uint256) {
|
||||
return _set.length();
|
||||
}
|
||||
|
||||
function at_(uint256 index) public view returns (bytes32) {
|
||||
return _set.at(index);
|
||||
}
|
||||
|
||||
function _indexOf(bytes32 value) public view returns (uint256) {
|
||||
return _set._inner._indexes[value];
|
||||
}
|
||||
}
|
||||
@ -1,206 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.2;
|
||||
|
||||
import "../munged/governance/Governor.sol";
|
||||
import "../munged/governance/extensions/GovernorCountingSimple.sol";
|
||||
import "../munged/governance/extensions/GovernorPreventLateQuorum.sol";
|
||||
import "../munged/governance/extensions/GovernorTimelockControl.sol";
|
||||
import "../munged/governance/extensions/GovernorVotes.sol";
|
||||
import "../munged/governance/extensions/GovernorVotesQuorumFraction.sol";
|
||||
import "../munged/token/ERC20/extensions/ERC20Votes.sol";
|
||||
|
||||
contract GovernorFullHarness is
|
||||
Governor,
|
||||
GovernorCountingSimple,
|
||||
GovernorTimelockControl,
|
||||
GovernorPreventLateQuorum,
|
||||
GovernorVotes,
|
||||
GovernorVotesQuorumFraction
|
||||
{
|
||||
using Checkpoints for Checkpoints.Trace224;
|
||||
|
||||
constructor(
|
||||
IVotes _token,
|
||||
TimelockController _timelock,
|
||||
uint64 initialVoteExtension,
|
||||
uint256 quorumNumeratorValue
|
||||
)
|
||||
Governor("Harness")
|
||||
GovernorPreventLateQuorum(initialVoteExtension)
|
||||
GovernorTimelockControl(_timelock)
|
||||
GovernorVotes(_token)
|
||||
GovernorVotesQuorumFraction(quorumNumeratorValue)
|
||||
{}
|
||||
|
||||
mapping(uint256 => uint256) public ghost_sum_vote_power_by_id;
|
||||
|
||||
// Harness from Votes //
|
||||
|
||||
function getPastTotalSupply(uint256 blockNumber) public view returns(uint256) {
|
||||
return token.getPastTotalSupply(blockNumber);
|
||||
}
|
||||
// Harness from GovernorVotesQuorumFraction //
|
||||
|
||||
function getQuorumNumeratorLength() public view returns(uint256) {
|
||||
return _quorumNumeratorHistory._checkpoints.length;
|
||||
}
|
||||
|
||||
function getQuorumNumeratorLatest() public view returns(uint256) {
|
||||
return _quorumNumeratorHistory.latest();
|
||||
}
|
||||
|
||||
function getDeprecatedQuorumNumerator() public view returns(uint256) {
|
||||
return _quorumNumerator;
|
||||
}
|
||||
|
||||
// Harness from GovernorPreventLateQuorum //
|
||||
|
||||
function getVoteExtension() public view returns (uint64) {
|
||||
return _voteExtension;
|
||||
}
|
||||
|
||||
function getExtendedDeadline(uint256 proposalId) public view returns (uint64) {
|
||||
return _extendedDeadlines[proposalId];
|
||||
}
|
||||
|
||||
// Harness from GovernorCountingSimple //
|
||||
|
||||
function getAgainstVotes(uint256 proposalId) public view returns (uint256) {
|
||||
ProposalVote storage proposalvote = _proposalVotes[proposalId];
|
||||
return proposalvote.againstVotes;
|
||||
}
|
||||
|
||||
function getAbstainVotes(uint256 proposalId) public view returns (uint256) {
|
||||
ProposalVote storage proposalvote = _proposalVotes[proposalId];
|
||||
return proposalvote.abstainVotes;
|
||||
}
|
||||
|
||||
function getForVotes(uint256 proposalId) public view returns (uint256) {
|
||||
ProposalVote storage proposalvote = _proposalVotes[proposalId];
|
||||
return proposalvote.forVotes;
|
||||
}
|
||||
|
||||
function quorumReached(uint256 proposalId) public view returns (bool) {
|
||||
return _quorumReached(proposalId);
|
||||
}
|
||||
|
||||
function voteSucceeded(uint256 proposalId) public view returns (bool) {
|
||||
return _voteSucceeded(proposalId);
|
||||
}
|
||||
|
||||
// Harness from Governor //
|
||||
|
||||
function getExecutor() public view returns (address) {
|
||||
return _executor();
|
||||
}
|
||||
|
||||
function proposalProposer(uint256 proposalId) public view returns (address) {
|
||||
return _proposalProposer(proposalId);
|
||||
}
|
||||
|
||||
function isExecuted(uint256 proposalId) public view returns (bool) {
|
||||
return _proposals[proposalId].executed;
|
||||
}
|
||||
|
||||
function isCanceled(uint256 proposalId) public view returns (bool) {
|
||||
return _proposals[proposalId].canceled;
|
||||
}
|
||||
|
||||
// The following functions are overrides required by Solidity added by Certora. //
|
||||
|
||||
function proposalDeadline(uint256 proposalId)
|
||||
public
|
||||
view
|
||||
virtual
|
||||
override(Governor, GovernorPreventLateQuorum, IGovernor)
|
||||
returns (uint256)
|
||||
{
|
||||
return super.proposalDeadline(proposalId);
|
||||
}
|
||||
|
||||
function _castVote(
|
||||
uint256 proposalId,
|
||||
address account,
|
||||
uint8 support,
|
||||
string memory reason,
|
||||
bytes memory params
|
||||
) internal virtual override(Governor, GovernorPreventLateQuorum) returns (uint256) {
|
||||
// added to run GovernorCountingSimple.spec
|
||||
uint256 deltaWeight = super._castVote(proposalId, account, support, reason, params);
|
||||
ghost_sum_vote_power_by_id[proposalId] += deltaWeight;
|
||||
|
||||
return deltaWeight;
|
||||
}
|
||||
|
||||
function lateQuorumVoteExtension() public view virtual override returns (uint64) {
|
||||
return super.lateQuorumVoteExtension();
|
||||
}
|
||||
|
||||
function setLateQuorumVoteExtension(uint64 newVoteExtension) public virtual override onlyGovernance {
|
||||
super.setLateQuorumVoteExtension(newVoteExtension);
|
||||
}
|
||||
|
||||
// The following functions are overrides required by Solidity added by OZ Wizard. //
|
||||
|
||||
function votingDelay() public pure override returns (uint256) {
|
||||
return 1; // 1 block
|
||||
}
|
||||
|
||||
function votingPeriod() public pure override returns (uint256) {
|
||||
return 45818; // 1 week
|
||||
}
|
||||
|
||||
function quorum(uint256 blockNumber)
|
||||
public
|
||||
view
|
||||
override(IGovernor, GovernorVotesQuorumFraction)
|
||||
returns (uint256)
|
||||
{
|
||||
return super.quorum(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, 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);
|
||||
}
|
||||
}
|
||||
@ -1,154 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.2;
|
||||
|
||||
import "../munged/governance/Governor.sol";
|
||||
import "../munged/governance/extensions/GovernorCountingSimple.sol";
|
||||
import "../munged/governance/extensions/GovernorTimelockControl.sol";
|
||||
import "../munged/governance/extensions/GovernorVotes.sol";
|
||||
import "../munged/governance/extensions/GovernorVotesQuorumFraction.sol";
|
||||
import "../munged/token/ERC20/extensions/ERC20Votes.sol";
|
||||
|
||||
contract GovernorHarness is
|
||||
Governor,
|
||||
GovernorCountingSimple,
|
||||
GovernorVotes,
|
||||
GovernorVotesQuorumFraction,
|
||||
GovernorTimelockControl
|
||||
{
|
||||
constructor(
|
||||
IVotes _token,
|
||||
TimelockController _timelock,
|
||||
uint64 initialVoteExtension,
|
||||
uint256 quorumNumeratorValue
|
||||
)
|
||||
Governor("Harness")
|
||||
GovernorVotes(_token)
|
||||
GovernorVotesQuorumFraction(quorumNumeratorValue)
|
||||
GovernorTimelockControl(_timelock)
|
||||
{}
|
||||
|
||||
mapping(uint256 => uint256) public ghost_sum_vote_power_by_id;
|
||||
|
||||
// Harness from GovernorCountingSimple //
|
||||
|
||||
function getAgainstVotes(uint256 proposalId) public view returns (uint256) {
|
||||
ProposalVote storage proposalvote = _proposalVotes[proposalId];
|
||||
return proposalvote.againstVotes;
|
||||
}
|
||||
|
||||
function getAbstainVotes(uint256 proposalId) public view returns (uint256) {
|
||||
ProposalVote storage proposalvote = _proposalVotes[proposalId];
|
||||
return proposalvote.abstainVotes;
|
||||
}
|
||||
|
||||
function getForVotes(uint256 proposalId) public view returns (uint256) {
|
||||
ProposalVote storage proposalvote = _proposalVotes[proposalId];
|
||||
return proposalvote.forVotes;
|
||||
}
|
||||
|
||||
function quorumReached(uint256 proposalId) public view returns (bool) {
|
||||
return _quorumReached(proposalId);
|
||||
}
|
||||
|
||||
function voteSucceeded(uint256 proposalId) public view returns (bool) {
|
||||
return _voteSucceeded(proposalId);
|
||||
}
|
||||
|
||||
// Harness from Governor //
|
||||
|
||||
function getExecutor() public view returns (address) {
|
||||
return _executor();
|
||||
}
|
||||
|
||||
function proposalProposer(uint256 proposalId) public view returns (address) {
|
||||
return _proposalProposer(proposalId);
|
||||
}
|
||||
|
||||
function isExecuted(uint256 proposalId) public view returns (bool) {
|
||||
return _proposals[proposalId].executed;
|
||||
}
|
||||
|
||||
function isCanceled(uint256 proposalId) public view returns (bool) {
|
||||
return _proposals[proposalId].canceled;
|
||||
}
|
||||
|
||||
// The following functions are overrides required by Solidity added by Certora. //
|
||||
|
||||
function _castVote(
|
||||
uint256 proposalId,
|
||||
address account,
|
||||
uint8 support,
|
||||
string memory reason,
|
||||
bytes memory params
|
||||
) internal virtual override returns (uint256) {
|
||||
// added to run GovernorCountingSimple.spec
|
||||
uint256 deltaWeight = super._castVote(proposalId, account, support, reason, params);
|
||||
ghost_sum_vote_power_by_id[proposalId] += deltaWeight;
|
||||
|
||||
return deltaWeight;
|
||||
}
|
||||
|
||||
// The following functions are overrides required by Solidity added by OZ Wizard. //
|
||||
|
||||
function votingDelay() public pure override returns (uint256) {
|
||||
return 1; // 1 block
|
||||
}
|
||||
|
||||
function votingPeriod() public pure override returns (uint256) {
|
||||
return 45818; // 1 week
|
||||
}
|
||||
|
||||
function quorum(uint256 blockNumber)
|
||||
public
|
||||
view
|
||||
override(IGovernor, GovernorVotesQuorumFraction)
|
||||
returns (uint256)
|
||||
{
|
||||
return super.quorum(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, 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);
|
||||
}
|
||||
}
|
||||
@ -1,20 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC3156FlashBorrower.sol)
|
||||
|
||||
import "../munged/interfaces/IERC3156FlashBorrower.sol";
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract IERC3156FlashBorrowerHarness is IERC3156FlashBorrower {
|
||||
bytes32 somethingToReturn;
|
||||
|
||||
function onFlashLoan(
|
||||
address initiator,
|
||||
address token,
|
||||
uint256 amount,
|
||||
uint256 fee,
|
||||
bytes calldata data
|
||||
) external override returns (bytes32) {
|
||||
return somethingToReturn;
|
||||
}
|
||||
}
|
||||
@ -1,80 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.2;
|
||||
|
||||
import "../munged/proxy/utils/Initializable.sol";
|
||||
|
||||
contract InitializableBasicHarness is Initializable {
|
||||
uint256 public val;
|
||||
uint256 public a;
|
||||
uint256 public b;
|
||||
|
||||
modifier version1() {
|
||||
require(_initialized == 1);
|
||||
_;
|
||||
}
|
||||
|
||||
modifier versionN(uint8 n) {
|
||||
require(_initialized == n);
|
||||
_;
|
||||
}
|
||||
|
||||
function initialize(
|
||||
uint256 _val,
|
||||
uint256 _a,
|
||||
uint256 _b
|
||||
) public initializer {
|
||||
a = _a;
|
||||
b = _b;
|
||||
val = _val;
|
||||
}
|
||||
|
||||
function reinitialize(
|
||||
uint256 _val,
|
||||
uint256 _a,
|
||||
uint256 _b,
|
||||
uint8 n
|
||||
) public reinitializer(n) {
|
||||
a = _a;
|
||||
b = _b;
|
||||
val = _val;
|
||||
}
|
||||
|
||||
// Versioned return functions for testing
|
||||
|
||||
function returnsV1() public view version1 returns (uint256) {
|
||||
return val;
|
||||
}
|
||||
|
||||
function returnsVN(uint8 n) public view versionN(n) returns (uint256) {
|
||||
return val;
|
||||
}
|
||||
|
||||
function returnsAV1() public view version1 returns (uint256) {
|
||||
return a;
|
||||
}
|
||||
|
||||
function returnsAVN(uint8 n) public view versionN(n) returns (uint256) {
|
||||
return a;
|
||||
}
|
||||
|
||||
function returnsBV1() public view version1 returns (uint256) {
|
||||
return b;
|
||||
}
|
||||
|
||||
function returnsBVN(uint8 n) public view versionN(n) returns (uint256) {
|
||||
return b;
|
||||
}
|
||||
|
||||
// Harness //
|
||||
function initialized() public view returns (uint8) {
|
||||
return _initialized;
|
||||
}
|
||||
|
||||
function initializing() public view returns (bool) {
|
||||
return _initializing;
|
||||
}
|
||||
|
||||
function thisIsContract() public view returns (bool) {
|
||||
return !Address.isContract(address(this));
|
||||
}
|
||||
}
|
||||
@ -1,92 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.2;
|
||||
|
||||
import "../munged/proxy/utils/Initializable.sol";
|
||||
|
||||
contract InitializableA is Initializable {
|
||||
uint256 public a;
|
||||
|
||||
modifier version1() {
|
||||
require(_initialized == 1);
|
||||
_;
|
||||
}
|
||||
|
||||
modifier versionN(uint8 n) {
|
||||
require(_initialized == n);
|
||||
_;
|
||||
}
|
||||
|
||||
function __InitializableA_init(uint256 _a) internal onlyInitializing {
|
||||
a = _a;
|
||||
}
|
||||
|
||||
function returnsAV1() public view version1 returns (uint256) {
|
||||
return a;
|
||||
}
|
||||
|
||||
function returnsAVN(uint8 n) public view versionN(n) returns (uint256) {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
contract InitializableB is Initializable, InitializableA {
|
||||
uint256 public b;
|
||||
|
||||
function __InitializableB_init(uint256 _b) internal onlyInitializing {
|
||||
b = _b;
|
||||
}
|
||||
|
||||
function returnsBV1() public view version1 returns (uint256) {
|
||||
return b;
|
||||
}
|
||||
|
||||
function returnsBVN(uint8 n) public view versionN(n) returns (uint256) {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
contract InitializableComplexHarness is Initializable, InitializableB {
|
||||
uint256 public val;
|
||||
|
||||
function initialize(
|
||||
uint256 _val,
|
||||
uint256 _a,
|
||||
uint256 _b
|
||||
) public initializer {
|
||||
val = _val;
|
||||
__InitializableA_init(_a);
|
||||
__InitializableB_init(_b);
|
||||
}
|
||||
|
||||
function reinitialize(
|
||||
uint256 _val,
|
||||
uint256 _a,
|
||||
uint256 _b,
|
||||
uint8 n
|
||||
) public reinitializer(n) {
|
||||
val = _val;
|
||||
__InitializableA_init(_a);
|
||||
__InitializableB_init(_b);
|
||||
}
|
||||
|
||||
function returnsV1() public view version1 returns (uint256) {
|
||||
return val;
|
||||
}
|
||||
|
||||
function returnsVN(uint8 n) public view versionN(n) returns (uint256) {
|
||||
return val;
|
||||
}
|
||||
|
||||
// Harness //
|
||||
function initialized() public view returns (uint8) {
|
||||
return _initialized;
|
||||
}
|
||||
|
||||
function initializing() public view returns (bool) {
|
||||
return _initializing;
|
||||
}
|
||||
|
||||
function thisIsContract() public view returns (bool) {
|
||||
return !Address.isContract(address(this));
|
||||
}
|
||||
}
|
||||
23
certora/harnesses/InitializableHarness.sol
Normal file
23
certora/harnesses/InitializableHarness.sol
Normal file
@ -0,0 +1,23 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {Initializable} from "../patched/proxy/utils/Initializable.sol";
|
||||
|
||||
contract InitializableHarness is Initializable {
|
||||
function initialize() public initializer {}
|
||||
function reinitialize(uint64 n) public reinitializer(n) {}
|
||||
function disable() public { _disableInitializers(); }
|
||||
|
||||
function nested_init_init() public initializer { initialize(); }
|
||||
function nested_init_reinit(uint64 m) public initializer { reinitialize(m); }
|
||||
function nested_reinit_init(uint64 n) public reinitializer(n) { initialize(); }
|
||||
function nested_reinit_reinit(uint64 n, uint64 m) public reinitializer(n) { reinitialize(m); }
|
||||
|
||||
function version() public view returns (uint64) {
|
||||
return _getInitializedVersion();
|
||||
}
|
||||
|
||||
function initializing() public view returns (bool) {
|
||||
return _isInitializing();
|
||||
}
|
||||
}
|
||||
10
certora/harnesses/Ownable2StepHarness.sol
Normal file
10
certora/harnesses/Ownable2StepHarness.sol
Normal file
@ -0,0 +1,10 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {Ownable2Step, Ownable} from "../patched/access/Ownable2Step.sol";
|
||||
|
||||
contract Ownable2StepHarness is Ownable2Step {
|
||||
constructor(address initialOwner) Ownable(initialOwner) {}
|
||||
|
||||
function restricted() external onlyOwner {}
|
||||
}
|
||||
10
certora/harnesses/OwnableHarness.sol
Normal file
10
certora/harnesses/OwnableHarness.sol
Normal file
@ -0,0 +1,10 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {Ownable} from "../patched/access/Ownable.sol";
|
||||
|
||||
contract OwnableHarness is Ownable {
|
||||
constructor(address initialOwner) Ownable(initialOwner) {}
|
||||
|
||||
function restricted() external onlyOwner {}
|
||||
}
|
||||
18
certora/harnesses/PausableHarness.sol
Normal file
18
certora/harnesses/PausableHarness.sol
Normal file
@ -0,0 +1,18 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {Pausable} from "../patched/utils/Pausable.sol";
|
||||
|
||||
contract PausableHarness is Pausable {
|
||||
function pause() external {
|
||||
_pause();
|
||||
}
|
||||
|
||||
function unpause() external {
|
||||
_unpause();
|
||||
}
|
||||
|
||||
function onlyWhenPaused() external whenPaused {}
|
||||
|
||||
function onlyWhenNotPaused() external whenNotPaused {}
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
pragma solidity ^0.8.0;
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import "../munged/governance/TimelockController.sol";
|
||||
import {TimelockController} from "../patched/governance/TimelockController.sol";
|
||||
|
||||
contract TimelockControllerHarness is TimelockController {
|
||||
constructor(
|
||||
|
||||
@ -1,159 +0,0 @@
|
||||
// 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";
|
||||
import "../munged/token/ERC20/extensions/ERC20Votes.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 virtual override 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, Governor)
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -1,154 +0,0 @@
|
||||
// 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";
|
||||
import "../munged/token/ERC20/extensions/ERC20Votes.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 virtual override 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 virtual override returns (uint256) {
|
||||
// HARNESS: pure -> view
|
||||
return _votingDelay; // HARNESS: parametric
|
||||
}
|
||||
|
||||
function votingPeriod() public view virtual override 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, Governor)
|
||||
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);
|
||||
}
|
||||
}
|
||||
160
certora/run.js
Executable file
160
certora/run.js
Executable file
@ -0,0 +1,160 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// USAGE:
|
||||
// node certora/run.js [[CONTRACT_NAME:]SPEC_NAME]* [--all] [--options OPTIONS...] [--specs PATH]
|
||||
// EXAMPLES:
|
||||
// node certora/run.js --all
|
||||
// node certora/run.js AccessControl
|
||||
// node certora/run.js AccessControlHarness:AccessControl
|
||||
|
||||
const proc = require('child_process');
|
||||
const { PassThrough } = require('stream');
|
||||
const events = require('events');
|
||||
|
||||
const argv = require('yargs')
|
||||
.env('')
|
||||
.options({
|
||||
all: {
|
||||
alias: 'a',
|
||||
type: 'boolean',
|
||||
},
|
||||
spec: {
|
||||
alias: 's',
|
||||
type: 'string',
|
||||
default: __dirname + '/specs.json',
|
||||
},
|
||||
parallel: {
|
||||
alias: 'p',
|
||||
type: 'number',
|
||||
default: 4,
|
||||
},
|
||||
verbose: {
|
||||
alias: 'v',
|
||||
type: 'count',
|
||||
default: 0,
|
||||
},
|
||||
options: {
|
||||
alias: 'o',
|
||||
type: 'array',
|
||||
default: [],
|
||||
},
|
||||
}).argv;
|
||||
|
||||
function match(entry, request) {
|
||||
const [reqSpec, reqContract] = request.split(':').reverse();
|
||||
return entry.spec == reqSpec && (!reqContract || entry.contract == reqContract);
|
||||
}
|
||||
|
||||
const specs = require(argv.spec).filter(s => argv.all || argv._.some(r => match(s, r)));
|
||||
const limit = require('p-limit')(argv.parallel);
|
||||
|
||||
if (argv._.length == 0 && !argv.all) {
|
||||
console.error(`Warning: No specs requested. Did you forgot to toggle '--all'?`);
|
||||
}
|
||||
|
||||
for (const r of argv._) {
|
||||
if (!specs.some(s => match(s, r))) {
|
||||
console.error(`Error: Requested spec '${r}' not found in ${argv.spec}`);
|
||||
process.exitCode = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (process.exitCode) {
|
||||
process.exit(process.exitCode);
|
||||
}
|
||||
|
||||
for (const { spec, contract, files, options = [] } of specs) {
|
||||
limit(
|
||||
runCertora,
|
||||
spec,
|
||||
contract,
|
||||
files,
|
||||
[...options, ...argv.options].flatMap(opt => opt.split(' ')),
|
||||
);
|
||||
}
|
||||
|
||||
// Run certora, aggregate the output and print it at the end
|
||||
async function runCertora(spec, contract, files, options = []) {
|
||||
const args = [...files, '--verify', `${contract}:certora/specs/${spec}.spec`, ...options];
|
||||
if (argv.verbose) {
|
||||
console.log('Running:', args.join(' '));
|
||||
}
|
||||
const child = proc.spawn('certoraRun', args);
|
||||
|
||||
const stream = new PassThrough();
|
||||
const output = collect(stream);
|
||||
|
||||
child.stdout.pipe(stream, { end: false });
|
||||
child.stderr.pipe(stream, { end: false });
|
||||
|
||||
// as soon as we have a job id, print the output link
|
||||
stream.on('data', function logStatusUrl(data) {
|
||||
const { '-DjobId': jobId, '-DuserId': userId } = Object.fromEntries(
|
||||
data
|
||||
.toString('utf8')
|
||||
.match(/-D\S+=\S+/g)
|
||||
?.map(s => s.split('=')) || [],
|
||||
);
|
||||
|
||||
if (jobId && userId) {
|
||||
console.error(`[${spec}] https://prover.certora.com/output/${userId}/${jobId}/`);
|
||||
stream.off('data', logStatusUrl);
|
||||
}
|
||||
});
|
||||
|
||||
// wait for process end
|
||||
const [code, signal] = await events.once(child, 'exit');
|
||||
|
||||
// error
|
||||
if (code || signal) {
|
||||
console.error(`[${spec}] Exited with code ${code || signal}`);
|
||||
process.exitCode = 1;
|
||||
}
|
||||
|
||||
// get all output
|
||||
stream.end();
|
||||
|
||||
// write results in markdown format
|
||||
writeEntry(spec, contract, code || signal, (await output).match(/https:\/\/prover.certora.com\/output\/\S*/)?.[0]);
|
||||
|
||||
// write all details
|
||||
console.error(`+ certoraRun ${args.join(' ')}\n` + (await output));
|
||||
}
|
||||
|
||||
// Collects stream data into a string
|
||||
async function collect(stream) {
|
||||
const buffers = [];
|
||||
for await (const data of stream) {
|
||||
const buf = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
||||
buffers.push(buf);
|
||||
}
|
||||
return Buffer.concat(buffers).toString('utf8');
|
||||
}
|
||||
|
||||
// Formatting
|
||||
let hasHeader = false;
|
||||
|
||||
function formatRow(...array) {
|
||||
return ['', ...array, ''].join(' | ');
|
||||
}
|
||||
|
||||
function writeHeader() {
|
||||
console.log(formatRow('spec', 'contract', 'result', 'status', 'output'));
|
||||
console.log(formatRow('-', '-', '-', '-', '-'));
|
||||
}
|
||||
|
||||
function writeEntry(spec, contract, success, url) {
|
||||
if (!hasHeader) {
|
||||
hasHeader = true;
|
||||
writeHeader();
|
||||
}
|
||||
console.log(
|
||||
formatRow(
|
||||
spec,
|
||||
contract,
|
||||
success ? ':x:' : ':heavy_check_mark:',
|
||||
url ? `[link](${url?.replace('/output/', '/jobStatus/')})` : 'error',
|
||||
url ? `[link](${url})` : 'error',
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
certoraRun \
|
||||
certora/harnesses/ERC20VotesHarness.sol certora/harnesses/WizardControlFirstPriority.sol \
|
||||
--verify WizardControlFirstPriority:certora/specs/GovernorBase.spec \
|
||||
--link WizardControlFirstPriority:token=ERC20VotesHarness \
|
||||
--solc solc \
|
||||
--optimistic_loop \
|
||||
--disableLocalTypeChecking \
|
||||
--settings -copyLoopUnroll=4 \
|
||||
$@
|
||||
@ -1,13 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
certoraRun \
|
||||
certora/harnesses/ERC20VotesHarness.sol certora/harnesses/WizardFirstTry.sol \
|
||||
--verify WizardFirstTry:certora/specs/GovernorBase.spec \
|
||||
--link WizardFirstTry:token=ERC20VotesHarness \
|
||||
--solc solc \
|
||||
--optimistic_loop \
|
||||
--disableLocalTypeChecking \
|
||||
--settings -copyLoopUnroll=4 \
|
||||
$@
|
||||
@ -1,37 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
for contract in certora/harnesses/Wizard*.sol;
|
||||
do
|
||||
for spec in certora/specs/Governor*.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 solc \
|
||||
--optimistic_loop \
|
||||
--disableLocalTypeChecking \
|
||||
--settings -copyLoopUnroll=4 \
|
||||
--msg "checking $specFile on ${contractFile%.*}"
|
||||
else
|
||||
certoraRun \
|
||||
certora/harnesses/ERC20VotesHarness.sol certora/harnesses/$contractFile \
|
||||
--verify ${contractFile%.*}:certora/specs/$specFile "$@" \
|
||||
--solc solc \
|
||||
--optimistic_loop \
|
||||
--disableLocalTypeChecking \
|
||||
--settings -copyLoopUnroll=4 \
|
||||
--msg "checking $specFile on ${contractFile%.*}"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
done
|
||||
@ -1,34 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
# 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 solc \
|
||||
# --optimistic_loop \
|
||||
# --settings -copyLoopUnroll=4 \
|
||||
# --msg "checking sanity on ${file%.*}"
|
||||
# done
|
||||
|
||||
# TimelockController
|
||||
certoraRun \
|
||||
certora/harnesses/TimelockControllerHarness.sol \
|
||||
--verify TimelockControllerHarness:certora/specs/sanity.spec \
|
||||
--solc solc \
|
||||
--optimistic_loop \
|
||||
--msg "sanity and keccak check"
|
||||
|
||||
# Votes
|
||||
# certoraRun \
|
||||
# certora/harnesses/VotesHarness.sol \
|
||||
# --verify VotesHarness:certora/specs/sanity.spec \
|
||||
# --solc solc \
|
||||
# --optimistic_loop \
|
||||
# --settings -strictDecompiler=false,-assumeUnwindCond \
|
||||
# --msg "sanityVotes"
|
||||
@ -1,16 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
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 solc \
|
||||
--optimistic_loop \
|
||||
--settings -copyLoopUnroll=4 \
|
||||
--msg "checking sanity on ${file%.*}"
|
||||
done
|
||||
@ -1,16 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
for f in certora/harnesses/ERC20{Votes,Permit,Wrapper}Harness.sol
|
||||
do
|
||||
echo "Processing $f"
|
||||
file=$(basename $f)
|
||||
echo ${file%.*}
|
||||
certoraRun certora/harnesses/$file \
|
||||
--verify ${file%.*}:certora/specs/sanity.spec "$@" \
|
||||
--solc solc \
|
||||
--optimistic_loop \
|
||||
--settings -copyLoopUnroll=4,-strictDecompiler=false \
|
||||
--msg "checking sanity on ${file%.*}"
|
||||
done
|
||||
@ -1,9 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
certoraRun \
|
||||
certora/harnesses/AccessControlHarness.sol \
|
||||
--verify AccessControlHarness:certora/specs/AccessControl.spec \
|
||||
--optimistic_loop \
|
||||
$@
|
||||
@ -1,10 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
certoraRun \
|
||||
certora/harnesses/ERC1155/ERC1155Harness.sol \
|
||||
--verify ERC1155Harness:certora/specs/ERC1155.spec \
|
||||
--optimistic_loop \
|
||||
--loop_iter 3 \
|
||||
$@
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user