Compare commits

...

115 Commits

Author SHA1 Message Date
dbb6104ce8 Release v5.0.2 (#4928)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-02-29 17:44:22 +01:00
26b4b60999 Port Base64 tests to truffle (#4926)
Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
2024-02-29 17:40:36 +01:00
d4ec2782b7 List every contract in each API doc section (#4848)
Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
2024-01-23 12:04:51 -06:00
f7bb9881a8 Replace Defender Admin with Transaction Proposals (#4804)
Co-authored-by: Ernesto García <ernestognw@gmail.com>
2023-12-22 15:54:15 -06:00
e53f81b704 Remove Governor's guide ERC6372 disclaimer for Tally (#4801) 2023-12-19 22:01:28 +01:00
01ef448981 Release v5.0.1 (#4785)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-12-07 15:54:32 -06:00
9ce0340466 Make Multicall context-aware 2023-12-07 15:43:53 -06:00
4eb67a408c Close access-control.adoc code block (#4726) (#4727) 2023-11-09 16:35:42 +00:00
83330a6e4c Add AccessManager guide (#4691) (#4724)
Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
Co-authored-by: Eric Lau <ericglau@outlook.com>
Co-authored-by: Zack Reneau-Wedeen <z.reneau.wedeen@gmail.com>
2023-11-09 16:03:11 +00:00
ab967b8639 Update the "utilities" documentation page (#4678)
Co-authored-by: ernestognw <ernestognw@gmail.com>
2023-10-12 11:12:29 -06:00
a34d986eca Add note about SafeMath.sol remaining functions moved to Math.sol (#4676)
(cherry picked from commit faa83c693a)
Signed-off-by: Hadrien Croubois <hadrien.croubois@gmail.com>
2023-10-12 11:26:15 +02:00
5161a4dc8a Document ERC1155 event differences (#4666)
(cherry picked from commit 793d92a333)
2023-10-06 17:06:16 -03:00
932fddf69a Release v5.0.0 (#4662)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Francisco Giordano <fg@frang.io>
2023-10-05 14:58:30 -03:00
73995884f3 Remove v5.0 release candidate note and add audit (#4663)
Co-authored-by: Francisco Giordano <fg@frang.io>
(cherry picked from commit a754936a47)
2023-10-05 14:47:47 -03:00
12735415d6 Exit release candidate 2023-10-05 16:12:00 +00:00
d27635fc67 Document AccessManager functions and events in IAccessManager (#4660)
Co-authored-by: Francisco <fg@frang.io>
Co-authored-by: Ernesto García <ernestognw@gmail.com>
(cherry picked from commit e78628bfcf)
2023-10-05 12:59:00 -03:00
cff043486b Classify v5.0.0 changelog and improve migration guide (#4653)
Co-authored-by: Francisco <fg@frang.io>
2023-10-05 12:21:32 -03:00
6a0cfcedf0 Update "Using with Upgrades" page for 5.0 (#4659)
(cherry picked from commit 0f89a7e5f8)
2023-10-05 11:17:59 -04:00
bd25a0a26f Fix guides for 5.0 (#4654)
Co-authored-by: Ernesto García <ernestognw@gmail.com>
(cherry picked from commit e12511b53e)
2023-10-04 22:39:47 -03:00
228013d232 Improve GovernorTimelockAccess tests (#4642)
Co-authored-by: Francisco <fg@frang.io>
(cherry picked from commit 655bd58487)
2023-10-04 22:39:47 -03:00
a874080fc1 Reset Hardhat Network before each test suite (#4652)
(cherry picked from commit f92dce51ed)
2023-10-04 22:39:47 -03:00
3e45ab2d51 Improve AccessManaged and AuthorityUtils tests (#4632)
Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
Co-authored-by: Francisco Giordano <fg@frang.io>
(cherry picked from commit 0560576c7a)
2023-10-04 22:39:47 -03:00
37f0b3b2ce Improve AccessManager tests (#4613)
Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
Co-authored-by: Francisco Giordano <fg@frang.io>
(cherry picked from commit baf0e91279)
2023-10-04 22:39:47 -03:00
e49fcbeb56 Ensure constant getters show in docs (#4649)
(cherry picked from commit 39400b78ba)
2023-10-04 14:35:23 -03:00
21ef8130c8 Fix coverage analysis (#4648)
(cherry picked from commit 2c6b859dd0)
2023-10-03 17:43:29 -03:00
d6954f17b5 Fix release tagging (#4646)
(cherry picked from commit 5d43060cdc)
2023-10-03 15:46:36 -03:00
51191d3152 Fix typos
(cherry picked from commit b4a9c47e9b)
2023-10-02 17:44:16 -03:00
a14d8149ed Release v5.0.0 (rc) (#4645)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-10-02 17:04:47 -03:00
7a4064d886 Make AccessManager.execute/schedule more conservative when delay is 0 (#4644)
(cherry picked from commit b849906ce4)
2023-10-02 16:48:32 -03:00
bf629d4ea7 Update remappings.txt for upgradeable contracts and set up submodule (#4639)
Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
Co-authored-by: Ernesto García <ernestognw@gmail.com>
(cherry picked from commit abba0d047a)
2023-10-02 16:48:24 -03:00
aef22bddc9 Update eth-gas-reporter (#4643)
(cherry picked from commit 5ed5a86d1d)
2023-10-02 16:48:20 -03:00
bc96591f65 Release v5.0.0 (rc) (#4636)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-09-28 20:40:34 -03:00
fb2aec6946 Fix upgradeable patch in release branches (#4637)
(cherry picked from commit ef3e7771a7)
2023-09-28 19:43:51 -03:00
322df4226d Enable partial transpilation for upgradeable package (#4628)
Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
(cherry picked from commit 58463a9823)
2023-09-28 18:34:20 -03:00
4ce98d75bf Update solidity-coverage (#4623)
(cherry picked from commit bd4169bb15)
2023-09-28 18:33:36 -03:00
3a1e1bd336 Add version to custom Solhint plugin
(cherry picked from commit ce7e6042a8)
2023-09-28 18:33:31 -03:00
57c84f6bb8 Update lockfile (#4556)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Francisco Giordano <fg@frang.io>
(cherry picked from commit da04f40e98)
2023-09-28 18:33:23 -03:00
8f3f4f7f17 Add changesets for #4624 (#4635)
(cherry picked from commit 970a7184ad)
2023-09-28 18:33:01 -03:00
621fc0fe99 Fix warning format in the readme (#4634)
(cherry picked from commit dee645e914)
2023-09-28 17:08:50 -03:00
011c8bb034 Add named return parameters and _checkSelector function to AccessManager (#4624)
(cherry picked from commit 57865f8b20)
2023-09-28 16:53:00 -03:00
53f2721e8c Improve documentation about backwards compatibility (#4627)
Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
Co-authored-by: Ernesto García <ernestognw@gmail.com>
(cherry picked from commit 2472e51e80)
2023-09-28 12:55:19 -03:00
b805cc82d3 Update readme for release candidate (#4618)
(cherry picked from commit 181d518609)
2023-09-22 19:23:06 -03:00
33894d2a5b Fix docs updates on prereleases
(cherry picked from commit f0316a4cef)
2023-09-19 17:25:13 -03:00
9aaca67aa6 Enable docs generation for prereleases
(cherry picked from commit ae986db608)
2023-09-19 16:18:12 -03:00
abcec9e4a3 Update docs-utils to support prereleases
(cherry picked from commit 31aa460467)
2023-09-19 16:16:03 -03:00
b55b47d421 Release v5.0.0 (rc) (#4614)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-09-19 09:16:30 -06:00
0d6703b852 Start release candidate 2023-09-19 15:08:33 +00:00
f7db0bea31 Merge branch 'feat/access-manager' 2023-09-19 11:38:22 -03:00
64da2c10a4 Fix AccessManager._checkAuthorized in execute context (#4612)
Co-authored-by: Francisco <fg@frang.io>
2023-09-19 11:35:42 -03:00
68204769a1 Fix function documentation in Nonces (#4597)
Co-authored-by: Francisco <fg@frang.io>
2023-09-18 11:30:25 -03:00
652d0c5fb3 Fix minor mistake in GovernorTimelockAccess documentation (#4609) 2023-09-18 10:56:38 -03:00
2215d9fd5e Remove Time.Delay *At functions (#4606)
Co-authored-by: Francisco Giordano <fg@frang.io>
2023-09-15 12:23:28 -03:00
618304cc01 Update linters (major) (#4563)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Francisco Giordano <fg@frang.io>
2023-09-14 17:39:27 -03:00
af06fdcfd4 Fix various documentation errors (#4601) 2023-09-14 17:32:47 -03:00
d555464c53 AccessManager: Avoid resetting nonce when consuming a scheduled operation (#4603)
Co-authored-by: Francisco <fg@frang.io>
2023-09-14 17:26:14 -03:00
a714fe6dbd Wrap docstrings to 120 chars (#4600) 2023-09-14 15:28:24 -03:00
05205ab2e1 Remove deprecated 'ERC20FailedDecreaseAllowance' error (#4604)
Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
2023-09-14 10:49:04 -06:00
224c23b38f Rename ProposalCore.eta to etaSeconds (#4599) 2023-09-14 09:54:43 +02:00
80b2d1df38 Improve GovernorTimelockAccess (#4591)
Co-authored-by: Francisco <fg@frang.io>
2023-09-13 20:25:35 -03:00
3bd9ed377e Better context on _spendAllowance NatSpec (#4568)
Co-authored-by: Francisco <fg@frang.io>
Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
2023-09-13 16:22:05 -03:00
75eb7c2d49 Merge branch 'feat/access-manager' into audit/wip/2a-2b 2023-09-13 16:07:43 -03:00
e48f8fd0d2 Merge branch 'master' into feat/access-manager 2023-09-13 16:02:48 -03:00
6f1685c3eb Merge branch 'master' into audit/wip/2a-2b 2023-09-13 11:14:09 +02:00
60e3ffe6a3 Remove non-standard increaseAllowance and decreaseAllowance from ERC20 (#4585)
Co-authored-by: Francisco <fg@frang.io>
2023-09-12 11:59:48 -03:00
63851f8de5 Fix typographical errors & comments (#4595)
Co-authored-by: Francisco <fg@frang.io>
2023-09-11 18:44:28 -03:00
36bf1e46fa Migrate FV specs to CVL2 (#4527)
Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
2023-09-11 17:15:51 -03:00
b6111faac8 Use namespaced storage for upgradeable contracts (#4534) 2023-09-11 16:32:10 -03:00
095c8e120c Remove SafeERC20.safePermit (#4582)
Co-authored-by: Francisco <fg@frang.io>
2023-09-11 12:07:25 -03:00
9e09e0653a Fix flaky test in AccessManager (#4593) 2023-09-11 12:07:06 -03:00
a07f28b00c Improve AccessManager docs (#4586) 2023-09-11 15:54:22 +02:00
bba33516b1 Remove unused return value and reuse helper function (#4588)
Co-authored-by: Francisco Giordano <fg@frang.io>
2023-09-08 18:24:23 -03:00
01659449d4 Make Solidity pragma consistent (#4589) 2023-09-08 18:24:06 -03:00
7ae7f3ef4b Remove unused import (#4590) 2023-09-08 18:05:26 -03:00
26c22169f0 Rename custom error AleadyInitialized → InvalidInitialization (#4592) 2023-09-08 18:05:00 -03:00
6f80048ce9 Improve natspec documentation and comments (#4581)
Co-authored-by: Francisco Giordano <fg@frang.io>
2023-09-07 22:10:28 -03:00
d54f4ac4b7 Rename AccessManager groups to roles (#4580) 2023-09-07 20:58:50 -03:00
a05a529049 Rename AccessManager.relay to execute (#4578)
Co-authored-by: Francisco Giordano <fg@frang.io>
2023-09-07 10:08:45 +02:00
25c416d01c Rename internal variables in EnumerableSet for improved readability (#4577)
Co-authored-by: Francisco Giordano <fg@frang.io>
2023-09-06 23:10:19 -03:00
5a77c9995f Make isConsumingScheduleOp return bytes4 to mitigate clashes (#4575)
Co-authored-by: Francisco Giordano <fg@frang.io>
2023-09-06 20:54:44 -03:00
e2a9353dea Remove unused named return variables (#4573)
Co-authored-by: Francisco <fg@frang.io>
2023-09-06 11:35:07 +02:00
87f7a2cd42 Refactor Time library to use valueBefore/valueAfter (#4555)
Co-authored-by: Francisco <fg@frang.io>
2023-09-05 23:19:21 -03:00
bb7ca7d151 Prevent setting address(0) as the initialAdmin in AccessManager (#4570)
Co-authored-by: Francisco <fg@frang.io>
2023-09-05 18:47:05 -03:00
5abbd04933 Improve Initializable readability using intermediate variables (#4576)
Co-authored-by: Francisco <fg@frang.io>
2023-09-05 18:46:14 -03:00
ff9d089dad Add a boolean to AccessManager.GrantGroup (#4569) 2023-09-05 11:50:56 -03:00
33cab7cd25 AccessManager: Remove classes (#4562) 2023-09-05 11:49:54 -03:00
9ef69c03d1 Update actions/checkout action to v4 (#4572)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Francisco Giordano <fg@frang.io>
2023-09-04 21:38:01 +00:00
1523a4f071 Fix accuracy of docs for ERC20._burn (#4574)
Co-authored-by: Francisco <fg@frang.io>
2023-09-04 18:05:42 -03:00
e7ba2f7784 Move beneficiary zero address check to Ownable (#4531)
Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
Co-authored-by: Francisco <fg@frang.io>
2023-09-04 20:17:16 +00:00
f154bc31d4 Fix some spelling issues in AccessManager.sol & Time.sol (#4571)
Co-authored-by: Francisco <fg@frang.io>
2023-09-04 13:54:28 -03:00
9d2adccf87 Add a minimum delay on all admin update operations (#4557)
Co-authored-by: Francisco <fg@frang.io>
2023-09-04 13:47:51 -03:00
630844ef50 Merge branch 'feat/access-manager' into audit/wip/2a-2b 2023-09-04 15:58:56 +02:00
e891ec587d Merge branch 'master' into feat/access-manager 2023-09-04 15:55:53 +02:00
9612083826 Refactor ERC721 _requireMinted and ownerOf (#4566) 2023-09-04 15:54:21 +02:00
a503ba1a0a Avoid overflow on empty multiproof (#4564) 2023-09-04 10:17:03 +02:00
c0545f741b Delete unused variable (#4565) 2023-09-04 10:16:23 +02:00
98b83dfbaa Move security directory contents to utils (#4551) 2023-09-04 10:11:30 +02:00
424149a682 Stop cleaning up token specific data on ERC-721 burn (#4561)
Co-authored-by: Francisco Giordano <fg@frang.io>
2023-09-02 01:59:00 -03:00
b7da617d8d Define ERC-4906 interfaceId in a private constant (#4560)
Co-authored-by: Francisco Giordano <fg@frang.io>
2023-09-02 01:31:59 -03:00
00c5da2034 Allow setting tokenURI for non-existent token (#4559)
Co-authored-by: Francisco <fg@frang.io>
2023-09-02 01:24:05 -03:00
10e00c8ef5 Missing view keyword IAccessManager interface (#4558) 2023-09-01 19:07:20 -03:00
8186c07a83 Follow _approve overrides in ERC721._update (#4552) 2023-08-31 11:23:40 -03:00
8a0b7bed82 Update ERC-7201 location for Initializable (#4554) 2023-08-31 11:02:05 +02:00
3266bca150 Revert memory pointer to storage pointer (#4550) 2023-08-30 19:58:51 +00:00
cd67894914 Use Trace208 in Votes to support ERC6372 clocks (#4539)
Co-authored-by: Francisco <fg@frang.io>
2023-08-30 17:25:17 +00:00
812404cee8 Use leading underscore solhint rule for private constants (#4542)
Co-authored-by: Francisco Giordano <fg@frang.io>
2023-08-29 18:25:35 -03:00
a5ed318634 Refactor access to Checkpoint struct without using memory (#4512) 2023-08-25 20:17:32 -03:00
b2e7bab920 caching result of reading storage variable to save gas (#4535) 2023-08-25 19:49:34 +02:00
98203a72a6 Fix blog link (#4532) 2023-08-25 14:14:49 -03:00
adbb8c9d27 Add Governor module connecting with AccessManager (#4523)
Co-authored-by: Ernesto García <ernestognw@gmail.com>
2023-08-16 02:33:49 -03:00
fab65cd08b Merge branch 'master' into feat/access-manager 2023-08-16 02:23:53 -03:00
9e3f4d60c5 Use the _update mechanism in ERC721 (#4377)
Co-authored-by: Francisco Giordano <fg@frang.io>
Co-authored-by: Ernesto García <ernestognw@gmail.com>
2023-08-09 11:03:27 -06:00
8643fd45fd Update remappings and install instructions for Foundry on docs site (#4498)
Co-authored-by: ernestognw <ernestognw@gmail.com>
2023-08-08 23:22:57 -03:00
cb0ffefe2f Use named arguments in mapping types (#4433)
Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
2023-08-08 22:48:56 -03:00
48b860124c Remove outdated warning from ERC2771Forwarder (#4519) 2023-08-07 22:29:48 -03:00
70578bbb44 Allow Initializable versions greater than 256 (#4460)
Co-authored-by: Francisco <fg@frang.io>
2023-08-07 18:59:19 -03:00
381 changed files with 12739 additions and 18627 deletions

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
`ERC1155Receiver`: Removed in favor of `ERC1155Holder`.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
`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))

View File

@ -1,4 +0,0 @@
---
'openzeppelin-solidity': major
---
Use `abi.encodeCall` in place of `abi.encodeWithSelector` and `abi.encodeWithSignature` for improved type-checking of parameters

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
`ERC2771Forwarder`: Added `deadline` for expiring transactions, batching, and more secure handling of `msg.value`.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': minor
---
`Math`: Make `ceilDiv` to revert on 0 division even if the numerator is 0

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
`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.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
`ERC20`, `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))

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
`ERC1155Supply`: add 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 .

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
`Ownable`: Add an `initialOwner` parameter to the constructor, making the ownership initialization explicit.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': minor
---
`Proxy`: Removed redundant `receive` function.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': patch
---
Optimize `Strings.equal`

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
`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.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
`Address`: Removed the ability to customize error messages. A common custom error is always used if the underlying revert reason cannot be bubbled up.

View File

@ -1,7 +0,0 @@
---
'openzeppelin-solidity': minor
---
Replace some uses of `abi.encodePacked` with clearer alternatives (e.g. `bytes.concat`, `string.concat`). (#4504)[https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4504]
pr: #4296

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': minor
---
`Arrays`: Optimize `findUpperBound` by removing redundant SLOAD.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': patch
---
`ECDSA`: Use unchecked arithmetic for the `tryRecover` function that receives the `r` and `vs` short-signature fields separately.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
`Checkpoints`: library moved from `utils` to `utils/structs`

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
`Governor`: Optimized use of storage for proposal data

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
`ERC1967Utils`: Refactor the `ERC1967Upgrade` abstract contract as a library.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
`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`.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
`VestingWallet`: Use `Ownable` instead of an immutable `beneficiary`.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
`ERC20`: Remove `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.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
Move the logic to validate ERC-1822 during an upgrade from `ERC1967Utils` to `UUPSUpgradeable`.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': patch
---
`VestingWallet`: Fix revert during 1 second time window when duration is 0.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': minor
---
`Arrays`: Add `unsafeMemoryAccess` helpers to read from a memory array without checking the length.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
`MessageHashUtils`: Add 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.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': minor
---
`GovernorTimelockControl`: Clean up timelock id on execution for gas refund.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': minor
---
`EIP712`: Add internal getters for the name and version strings

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': minor
---
`TimelockController`: Add a state getter that returns an `OperationState` enum.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
Replace revert strings and require statements with custom errors.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
`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))

View File

@ -1,6 +0,0 @@
---
'openzeppelin-solidity': patch
---
`Governor`: Add validation in ERC1155 and ERC721 receiver hooks to ensure Governor is the executor.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
Switched to using explicit Solidity import statements. Some previously available symbols may now have to be separately imported.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': patch
---
`Math`: Optimized stack operations in `mulDiv`.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
`Governor`: Add 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.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': patch
---
`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.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
`GovernorTimelockControl`: Add the Governor instance address as part of the TimelockController operation `salt` to avoid operation id collisions between governors using the same TimelockController.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': minor
---
`AccessManager`: Added a new contract for managing access control of complex systems in a consolidated location.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
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`.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
`ProxyAdmin`: Removed `getProxyAdmin` and `getProxyImplementation` getters. ([#3820](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3820))

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': patch
---
`ERC1155`: Optimize array allocation.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
Bump minimum compiler version required to 0.8.20

View File

@ -1,7 +0,0 @@
---
'openzeppelin-solidity': major
---
`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.
pr: #3816

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
`Governor`: Add `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.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
`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))

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
`ERC1155`: Remove check for address zero in `balanceOf`.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
`access`: Move `AccessControl` extensions to a dedicated directory.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': patch
---
`ERC721Consecutive`: Add a `_firstConsecutiveId` internal function that can be overridden to change the id of the first token minted through `_mintConsecutive`.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
`DoubleEndedQueue`: refactor internal structure to use `uint128` instead of `int128`. This has no effect on the library interface.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': patch
---
`Governor`: Add a mechanism to restrict the address of the proposer using a suffix in the description.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': minor
---
`Governor`, `Initializable`, and `UUPSUpgradeable`: Use internal functions in modifiers to optimize bytecode size.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
`Strings`: Rename `toString(int256)` to `toStringSigned(int256)`.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
`BeaconProxy`: Reject value in initialization unless a payable function is explicitly invoked.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': minor
---
`ERC1155`: Bubble errors triggered in the `onERC1155Received` and `onERC1155BatchReceived` hooks.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': patch
---
`ERC1155`: Optimize array accesses by skipping bounds checking when unnecessary.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': minor
---
`AccessControl`: Add a boolean return value to the internal `_grantRole` and `_revokeRole` functions indicating whether the role was granted or revoked.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': patch
---
`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.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': minor
---
Remove the `override` specifier from functions that only override a single interface function.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': patch
---
`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.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
`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.

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
`Math`: Renamed members of `Rounding` enum, and added a new rounding mode for "away from zero".

View File

@ -1,5 +0,0 @@
---
'openzeppelin-solidity': major
---
`SafeERC20`: Refactor `safeDecreaseAllowance` and `safeIncreaseAllowance` to support USDT-like tokens.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -20,7 +20,7 @@ jobs:
lint:
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
@ -31,7 +31,7 @@ jobs:
FORCE_COLOR: 1
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
@ -51,11 +51,15 @@ jobs:
env:
FORCE_COLOR: 1
steps:
- uses: actions/checkout@v3
- 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
@ -65,26 +69,25 @@ jobs:
- 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:
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
@ -95,7 +98,7 @@ jobs:
slither:
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
@ -106,7 +109,7 @@ jobs:
codespell:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Run CodeSpell
uses: codespell-project/actions-codespell@v2.0
with:

View File

@ -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

View File

@ -20,7 +20,7 @@ jobs:
apply-diff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Apply patches
run: make -C certora apply
@ -28,7 +28,7 @@ jobs:
runs-on: ubuntu-latest
if: github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'formal-verification')
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up environment

View File

@ -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
@ -195,7 +191,7 @@ jobs:
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

View File

@ -11,20 +11,24 @@ jobs:
environment: push-upgradeable
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
repository: OpenZeppelin/openzeppelin-contracts-upgradeable
fetch-depth: 0
token: ${{ secrets.GH_TOKEN_UPGRADEABLE }}
- name: Fetch current non-upgradeable branch
run: |
git fetch "https://github.com/${{ github.repository }}.git" "$REF"
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 }}

1
.gitignore vendored
View File

@ -63,6 +63,7 @@ contracts-exposed
# Foundry
/out
/cache_forge
# Certora
.certora*

View File

@ -10,5 +10,6 @@
"singleQuote": false
}
}
]
],
"plugins": ["prettier-plugin-solidity"]
}

View File

@ -1,12 +1,35 @@
# Changelog
## Unreleased
> **Warning** Version 5.0 is under active development and should not be used. Install the releases from npm or use the version tags in the repository.
## 5.0.2 (2024-02-29)
### Removals
- `Base64`: Fix issue where dirty memory located just after the input buffer is affecting the result. ([#4926](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4926))
The following contracts, libraries and functions were removed:
## 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`
@ -30,39 +53,236 @@ The following contracts, libraries and functions were removed:
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)
### How to upgrade from 4.x
### 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. Any customization made through those hooks should now be done overriding the new `_update` function instead.
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. `_mint` and `_burn` are no longer virtual (meaning they are not overridable) to guard against possible inconsistencies.
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);
}
-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);
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.

View File

@ -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 {

View File

@ -1,6 +1,3 @@
> **Warning**
> Version 5.0 is under active development. The code in this branch is not recommended for use.
# <img src="logo.svg" alt="OpenZeppelin" height="40px">
[![NPM Package](https://img.shields.io/npm/v/@openzeppelin/contracts.svg)](https://www.npmjs.org/package/@openzeppelin/contracts)
@ -17,7 +14,10 @@
:mage: **Not sure how to get started?** Check out [Contracts Wizard](https://wizard.openzeppelin.com/) — an interactive smart contract generator.
: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.
:building_construction: **Want to scale your decentralized application?** Check out [OpenZeppelin Defender](https://openzeppelin.com/defender) — a mission-critical developer security platform to code, audit, deploy, monitor, and operate with confidence.
> [!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
@ -29,13 +29,13 @@
$ 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)
> **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]
> 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.
> [!WARNING]
> Foundry installs the latest version initially, but subsequent `forge update` commands will use the `master` branch.
```
$ forge install OpenZeppelin/openzeppelin-contracts
@ -72,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 Hitchhikers 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.

View File

@ -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

View File

@ -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.

BIN
audits/2023-10-v5.0.pdf Normal file

Binary file not shown.

View File

@ -2,6 +2,7 @@
| 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) |

View 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));
}
}

View File

@ -1,14 +0,0 @@
--- token/ERC721/ERC721.sol 2023-03-07 10:48:47.736822221 +0100
+++ token/ERC721/ERC721.sol 2023-03-09 19:49:39.669338673 +0100
@@ -199,6 +199,11 @@
return _owners[tokenId];
}
+ // FV
+ function _getApproved(uint256 tokenId) internal view returns (address) {
+ return _tokenApprovals[tokenId];
+ }
+
/**
* @dev Returns whether `tokenId` exists.
*

View File

@ -1,8 +1,7 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "../patched/access/AccessControlDefaultAdminRules.sol";
import {AccessControlDefaultAdminRules} from "../patched/access/extensions/AccessControlDefaultAdminRules.sol";
contract AccessControlDefaultAdminRulesHarness is AccessControlDefaultAdminRules {
uint48 private _delayIncreaseWait;

View File

@ -1,7 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "../patched/access/AccessControl.sol";
import {AccessControl} from "../patched/access/AccessControl.sol";
contract AccessControlHarness is AccessControl {}

View File

@ -1,8 +1,7 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "../patched/utils/structs/DoubleEndedQueue.sol";
import {DoubleEndedQueue} from "../patched/utils/structs/DoubleEndedQueue.sol";
contract DoubleEndedQueueHarness {
using DoubleEndedQueue for DoubleEndedQueue.Bytes32Deque;

View File

@ -1,8 +1,7 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "../patched/token/ERC20/extensions/ERC20Permit.sol";
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) {}

View File

@ -2,10 +2,15 @@
pragma solidity ^0.8.20;
import "../patched/token/ERC20/extensions/ERC20Wrapper.sol";
import {ERC20Permit} from "../patched/token/ERC20/extensions/ERC20Permit.sol";
import {ERC20Wrapper, IERC20, ERC20} from "../patched/token/ERC20/extensions/ERC20Wrapper.sol";
contract ERC20WrapperHarness is ERC20Wrapper {
constructor(IERC20 _underlying, string memory _name, string memory _symbol) ERC20(_name, _symbol) ERC20Wrapper(_underlying) {}
contract ERC20WrapperHarness is ERC20Permit, ERC20Wrapper {
constructor(
IERC20 _underlying,
string memory _name,
string memory _symbol
) ERC20(_name, _symbol) ERC20Permit(_name) ERC20Wrapper(_underlying) {}
function underlyingTotalSupply() public view returns (uint256) {
return underlying().totalSupply();
@ -22,4 +27,8 @@ contract ERC20WrapperHarness is ERC20Wrapper {
function recover(address account) public returns (uint256) {
return _recover(account);
}
function decimals() public view override(ERC20Wrapper, ERC20) returns (uint8) {
return super.decimals();
}
}

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
import "../patched/interfaces/IERC3156FlashBorrower.sol";
import {IERC3156FlashBorrower} from "../patched/interfaces/IERC3156FlashBorrower.sol";
pragma solidity ^0.8.20;

View File

@ -2,7 +2,7 @@
pragma solidity ^0.8.20;
import "../patched/token/ERC721/ERC721.sol";
import {ERC721} from "../patched/token/ERC721/ERC721.sol";
contract ERC721Harness is ERC721 {
constructor(string memory name, string memory symbol) ERC721(name, symbol) {}
@ -23,10 +23,6 @@ contract ERC721Harness is ERC721 {
_burn(tokenId);
}
function tokenExists(uint256 tokenId) external view returns (bool) {
return _exists(tokenId);
}
function unsafeOwnerOf(uint256 tokenId) external view returns (address) {
return _ownerOf(tokenId);
}

View File

@ -2,7 +2,7 @@
pragma solidity ^0.8.20;
import "../patched/utils/structs/EnumerableMap.sol";
import {EnumerableMap} from "../patched/utils/structs/EnumerableMap.sol";
contract EnumerableMapHarness {
using EnumerableMap for EnumerableMap.Bytes32ToBytes32Map;

View File

@ -2,7 +2,7 @@
pragma solidity ^0.8.20;
import "../patched/utils/structs/EnumerableSet.sol";
import {EnumerableSet} from "../patched/utils/structs/EnumerableSet.sol";
contract EnumerableSetHarness {
using EnumerableSet for EnumerableSet.Bytes32Set;

View File

@ -1,19 +1,19 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "../patched/proxy/utils/Initializable.sol";
import {Initializable} from "../patched/proxy/utils/Initializable.sol";
contract InitializableHarness is Initializable {
function initialize() public initializer {}
function reinitialize(uint8 n) public reinitializer(n) {}
function disable() public { _disableInitializers(); }
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(uint8 m) public initializer { reinitialize(m); }
function nested_reinit_init(uint8 n) public reinitializer(n) { initialize(); }
function nested_reinit_reinit(uint8 n, uint8 m) public reinitializer(n) { reinitialize(m); }
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 (uint8) {
function version() public view returns (uint64) {
return _getInitializedVersion();
}

View File

@ -1,9 +1,10 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "../patched/access/Ownable2Step.sol";
import {Ownable2Step, Ownable} from "../patched/access/Ownable2Step.sol";
contract Ownable2StepHarness is Ownable2Step {
function restricted() external onlyOwner {}
constructor(address initialOwner) Ownable(initialOwner) {}
function restricted() external onlyOwner {}
}

View File

@ -1,9 +1,10 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "../patched/access/Ownable.sol";
import {Ownable} from "../patched/access/Ownable.sol";
contract OwnableHarness is Ownable {
function restricted() external onlyOwner {}
constructor(address initialOwner) Ownable(initialOwner) {}
function restricted() external onlyOwner {}
}

View File

@ -1,8 +1,7 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "../patched/security/Pausable.sol";
import {Pausable} from "../patched/utils/Pausable.sol";
contract PausableHarness is Pausable {
function pause() external {

View File

@ -1,6 +1,7 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "../patched/governance/TimelockController.sol";
import {TimelockController} from "../patched/governance/TimelockController.sol";
contract TimelockControllerHarness is TimelockController {
constructor(

View File

@ -64,7 +64,13 @@ if (process.exitCode) {
}
for (const { spec, contract, files, options = [] } of specs) {
limit(runCertora, spec, contract, files, [...options.flatMap(opt => opt.split(' ')), ...argv.options]);
limit(
runCertora,
spec,
contract,
files,
[...options, ...argv.options].flatMap(opt => opt.split(' ')),
);
}
// Run certora, aggregate the output and print it at the end

View File

@ -1,126 +1,119 @@
import "helpers/helpers.spec"
import "methods/IAccessControl.spec"
/*
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
Definitions
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
*/
definition DEFAULT_ADMIN_ROLE() returns bytes32 = 0x0000000000000000000000000000000000000000000000000000000000000000;
/*
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
Identify entrypoints: only grantRole, revokeRole and renounceRole can alter permissions
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
*/
rule onlyGrantCanGrant(env e, method f, bytes32 role, address account) {
calldataarg args;
bool hasRoleBefore = hasRole(role, account);
f(e, args);
bool hasRoleAfter = hasRole(role, account);
assert (
!hasRoleBefore &&
hasRoleAfter
) => (
f.selector == grantRole(bytes32, address).selector
);
assert (
hasRoleBefore &&
!hasRoleAfter
) => (
f.selector == revokeRole(bytes32, address).selector ||
f.selector == renounceRole(bytes32, address).selector
);
}
/*
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
Function correctness: grantRole only affects the specified user/role combo
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
*/
rule grantRoleEffect(env e, bytes32 role) {
require nonpayable(e);
bytes32 otherRole;
address account;
address otherAccount;
bool isCallerAdmin = hasRole(getRoleAdmin(role), e.msg.sender);
bool hasOtherRoleBefore = hasRole(otherRole, otherAccount);
grantRole@withrevert(e, role, account);
bool success = !lastReverted;
bool hasOtherRoleAfter = hasRole(otherRole, otherAccount);
// liveness
assert success <=> isCallerAdmin;
// effect
assert success => hasRole(role, account);
// no side effect
assert hasOtherRoleBefore != hasOtherRoleAfter => (role == otherRole && account == otherAccount);
}
/*
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
Function correctness: revokeRole only affects the specified user/role combo
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
*/
rule revokeRoleEffect(env e, bytes32 role) {
require nonpayable(e);
bytes32 otherRole;
address account;
address otherAccount;
bool isCallerAdmin = hasRole(getRoleAdmin(role), e.msg.sender);
bool hasOtherRoleBefore = hasRole(otherRole, otherAccount);
revokeRole@withrevert(e, role, account);
bool success = !lastReverted;
bool hasOtherRoleAfter = hasRole(otherRole, otherAccount);
// liveness
assert success <=> isCallerAdmin;
// effect
assert success => !hasRole(role, account);
// no side effect
assert hasOtherRoleBefore != hasOtherRoleAfter => (role == otherRole && account == otherAccount);
}
/*
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
Function correctness: renounceRole only affects the specified user/role combo
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
*/
rule renounceRoleEffect(env e, bytes32 role) {
require nonpayable(e);
bytes32 otherRole;
address account;
address otherAccount;
bool hasOtherRoleBefore = hasRole(otherRole, otherAccount);
renounceRole@withrevert(e, role, account);
bool success = !lastReverted;
bool hasOtherRoleAfter = hasRole(otherRole, otherAccount);
// liveness
assert success <=> account == e.msg.sender;
// effect
assert success => !hasRole(role, account);
// no side effect
assert hasOtherRoleBefore != hasOtherRoleAfter => (role == otherRole && account == otherAccount);
}
import "helpers/helpers.spec";
import "methods/IAccessControl.spec";
/*
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
Identify entrypoints: only grantRole, revokeRole and renounceRole can alter permissions
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
*/
rule onlyGrantCanGrant(env e, method f, bytes32 role, address account) {
calldataarg args;
bool hasRoleBefore = hasRole(role, account);
f(e, args);
bool hasRoleAfter = hasRole(role, account);
assert (
!hasRoleBefore &&
hasRoleAfter
) => (
f.selector == sig:grantRole(bytes32, address).selector
);
assert (
hasRoleBefore &&
!hasRoleAfter
) => (
f.selector == sig:revokeRole(bytes32, address).selector ||
f.selector == sig:renounceRole(bytes32, address).selector
);
}
/*
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
Function correctness: grantRole only affects the specified user/role combo
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
*/
rule grantRoleEffect(env e, bytes32 role) {
require nonpayable(e);
bytes32 otherRole;
address account;
address otherAccount;
bool isCallerAdmin = hasRole(getRoleAdmin(role), e.msg.sender);
bool hasOtherRoleBefore = hasRole(otherRole, otherAccount);
grantRole@withrevert(e, role, account);
bool success = !lastReverted;
bool hasOtherRoleAfter = hasRole(otherRole, otherAccount);
// liveness
assert success <=> isCallerAdmin;
// effect
assert success => hasRole(role, account);
// no side effect
assert hasOtherRoleBefore != hasOtherRoleAfter => (role == otherRole && account == otherAccount);
}
/*
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
Function correctness: revokeRole only affects the specified user/role combo
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
*/
rule revokeRoleEffect(env e, bytes32 role) {
require nonpayable(e);
bytes32 otherRole;
address account;
address otherAccount;
bool isCallerAdmin = hasRole(getRoleAdmin(role), e.msg.sender);
bool hasOtherRoleBefore = hasRole(otherRole, otherAccount);
revokeRole@withrevert(e, role, account);
bool success = !lastReverted;
bool hasOtherRoleAfter = hasRole(otherRole, otherAccount);
// liveness
assert success <=> isCallerAdmin;
// effect
assert success => !hasRole(role, account);
// no side effect
assert hasOtherRoleBefore != hasOtherRoleAfter => (role == otherRole && account == otherAccount);
}
/*
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
Function correctness: renounceRole only affects the specified user/role combo
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
*/
rule renounceRoleEffect(env e, bytes32 role) {
require nonpayable(e);
bytes32 otherRole;
address account;
address otherAccount;
bool hasOtherRoleBefore = hasRole(otherRole, otherAccount);
renounceRole@withrevert(e, role, account);
bool success = !lastReverted;
bool hasOtherRoleAfter = hasRole(otherRole, otherAccount);
// liveness
assert success <=> account == e.msg.sender;
// effect
assert success => !hasRole(role, account);
// no side effect
assert hasOtherRoleBefore != hasOtherRoleAfter => (role == otherRole && account == otherAccount);
}

View File

@ -1,28 +1,28 @@
import "helpers/helpers.spec"
import "methods/IAccessControlDefaultAdminRules.spec"
import "methods/IAccessControl.spec"
import "AccessControl.spec"
import "helpers/helpers.spec";
import "methods/IAccessControlDefaultAdminRules.spec";
import "methods/IAccessControl.spec";
import "AccessControl.spec";
use rule onlyGrantCanGrant filtered {
f -> f.selector != acceptDefaultAdminTransfer().selector
f -> f.selector != sig:acceptDefaultAdminTransfer().selector
}
/*
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
Helpers
Definitions
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
*/
definition timeSanity(env e) returns bool =
e.block.timestamp > 0 && e.block.timestamp + defaultAdminDelay(e) < max_uint48();
e.block.timestamp > 0 && e.block.timestamp + defaultAdminDelay(e) < max_uint48;
definition delayChangeWaitSanity(env e, uint48 newDelay) returns bool =
e.block.timestamp + delayChangeWait_(e, newDelay) < max_uint48();
e.block.timestamp + delayChangeWait_(e, newDelay) < max_uint48;
definition isSet(uint48 schedule) returns bool =
schedule != 0;
definition hasPassed(env e, uint48 schedule) returns bool =
schedule < e.block.timestamp;
assert_uint256(schedule) < e.block.timestamp;
definition increasingDelaySchedule(env e, uint48 newDelay) returns mathint =
e.block.timestamp + min(newDelay, defaultAdminDelayIncreaseWait());
@ -63,7 +63,7 @@ invariant singleDefaultAdmin(address account, address another)
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
*/
invariant defaultAdminRoleAdminConsistency()
getRoleAdmin(DEFAULT_ADMIN_ROLE()) == DEFAULT_ADMIN_ROLE()
getRoleAdmin(DEFAULT_ADMIN_ROLE()) == DEFAULT_ADMIN_ROLE();
/*
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
@ -71,7 +71,7 @@ invariant defaultAdminRoleAdminConsistency()
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
*/
invariant ownerConsistency()
defaultAdmin() == owner()
defaultAdmin() == owner();
/*
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
@ -136,7 +136,7 @@ rule renounceRoleEffect(env e, bytes32 role) {
account == e.msg.sender &&
(
role != DEFAULT_ADMIN_ROLE() ||
account != adminBefore ||
account != adminBefore ||
(
pendingAdminBefore == 0 &&
isSet(scheduleBefore) &&
@ -185,8 +185,8 @@ rule noDefaultAdminChange(env e, method f, calldataarg args) {
address adminAfter = defaultAdmin();
assert adminBefore != adminAfter => (
f.selector == acceptDefaultAdminTransfer().selector ||
f.selector == renounceRole(bytes32,address).selector
f.selector == sig:acceptDefaultAdminTransfer().selector ||
f.selector == sig:renounceRole(bytes32,address).selector
),
"default admin is only affected by accepting an admin transfer or renoucing";
}
@ -199,19 +199,19 @@ rule noDefaultAdminChange(env e, method f, calldataarg args) {
*/
rule noPendingDefaultAdminChange(env e, method f, calldataarg args) {
address pendingAdminBefore = pendingDefaultAdmin_();
address scheduleBefore = pendingDefaultAdminSchedule_();
uint48 scheduleBefore = pendingDefaultAdminSchedule_();
f(e, args);
address pendingAdminAfter = pendingDefaultAdmin_();
address scheduleAfter = pendingDefaultAdminSchedule_();
uint48 scheduleAfter = pendingDefaultAdminSchedule_();
assert (
pendingAdminBefore != pendingAdminAfter ||
scheduleBefore != scheduleAfter
) => (
f.selector == beginDefaultAdminTransfer(address).selector ||
f.selector == acceptDefaultAdminTransfer().selector ||
f.selector == cancelDefaultAdminTransfer().selector ||
f.selector == renounceRole(bytes32,address).selector
f.selector == sig:beginDefaultAdminTransfer(address).selector ||
f.selector == sig:acceptDefaultAdminTransfer().selector ||
f.selector == sig:cancelDefaultAdminTransfer().selector ||
f.selector == sig:renounceRole(bytes32,address).selector
),
"pending admin and its schedule is only affected by beginning, completing, or cancelling an admin transfer";
}
@ -241,8 +241,8 @@ rule noPendingDefaultAdminDelayChange(env e, method f, calldataarg args) {
uint48 pendingDelayAfter = pendingDelay_(e);
assert pendingDelayBefore != pendingDelayAfter => (
f.selector == changeDefaultAdminDelay(uint48).selector ||
f.selector == rollbackDefaultAdminDelay().selector
f.selector == sig:changeDefaultAdminDelay(uint48).selector ||
f.selector == sig:rollbackDefaultAdminDelay().selector
),
"pending delay is only affected by changeDefaultAdminDelay or rollbackDefaultAdminDelay";
}
@ -282,7 +282,7 @@ rule beginDefaultAdminTransfer(env e, address newAdmin) {
// effect
assert success => pendingDefaultAdmin_() == newAdmin,
"pending default admin is set";
assert success => pendingDefaultAdminSchedule_() == e.block.timestamp + defaultAdminDelay(e),
assert success => to_mathint(pendingDefaultAdminSchedule_()) == e.block.timestamp + defaultAdminDelay(e),
"pending default admin delay is set";
}
@ -307,7 +307,7 @@ rule pendingDefaultAdminDelayEnforced(env e1, env e2, method f, calldataarg args
// change can only happen towards the newAdmin, with the delay
assert adminAfter != adminBefore => (
adminAfter == newAdmin &&
e2.block.timestamp >= e1.block.timestamp + delayBefore
to_mathint(e2.block.timestamp) >= e1.block.timestamp + delayBefore
),
"The admin can only change after the enforced delay and to the previously scheduled new admin";
}
@ -393,7 +393,7 @@ rule changeDefaultAdminDelay(env e, uint48 newDelay) {
"pending delay is set";
assert success => (
pendingDelaySchedule_(e) > e.block.timestamp ||
assert_uint256(pendingDelaySchedule_(e)) > e.block.timestamp ||
delayBefore == newDelay || // Interpreted as decreasing, x - x = 0
defaultAdminDelayIncreaseWait() == 0
),
@ -419,7 +419,7 @@ rule pendingDelayWaitEnforced(env e1, env e2, method f, calldataarg args, uint48
assert delayAfter != delayBefore => (
delayAfter == newDelay &&
e2.block.timestamp >= delayWait
to_mathint(e2.block.timestamp) >= delayWait
),
"A delay can only change after the applied schedule";
}
@ -433,9 +433,9 @@ rule pendingDelayWait(env e, uint48 newDelay) {
uint48 oldDelay = defaultAdminDelay(e);
changeDefaultAdminDelay(e, newDelay);
assert newDelay > oldDelay => pendingDelaySchedule_(e) == increasingDelaySchedule(e, newDelay),
assert newDelay > oldDelay => to_mathint(pendingDelaySchedule_(e)) == increasingDelaySchedule(e, newDelay),
"Delay wait is the minimum between the new delay and a threshold when the delay is increased";
assert newDelay <= oldDelay => pendingDelaySchedule_(e) == decreasingDelaySchedule(e, newDelay),
assert newDelay <= oldDelay => to_mathint(pendingDelaySchedule_(e)) == decreasingDelaySchedule(e, newDelay),
"Delay wait is the difference between the current and the new delay when the delay is decreased";
}

View File

@ -1,15 +1,11 @@
import "helpers/helpers.spec"
import "methods/IERC20.spec"
import "methods/IERC2612.spec"
import "helpers/helpers.spec";
import "methods/IERC20.spec";
import "methods/IERC2612.spec";
methods {
// non standard ERC20 functions
increaseAllowance(address,uint256) returns (bool)
decreaseAllowance(address,uint256) returns (bool)
// exposed for FV
mint(address,uint256)
burn(address,uint256)
function mint(address,uint256) external;
function burn(address,uint256) external;
}
/*
@ -17,12 +13,22 @@ methods {
Ghost & hooks: sum of all balances
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
*/
ghost sumOfBalances() returns uint256 {
init_state axiom sumOfBalances() == 0;
ghost mathint sumOfBalances {
init_state axiom sumOfBalances == 0;
}
// Because `balance` has a uint256 type, any balance addition in CVL1 behaved as a `require_uint256()` casting,
// leaving out the possibility of overflow. This is not the case in CVL2 where casting became more explicit.
// A counterexample in CVL2 is having an initial state where Alice initial balance is larger than totalSupply, which
// overflows Alice's balance when receiving a transfer. This is not possible unless the contract is deployed into an
// already used address (or upgraded from corrupted state).
// We restrict such behavior by making sure no balance is greater than the sum of balances.
hook Sload uint256 balance _balances[KEY address addr] STORAGE {
require sumOfBalances >= to_mathint(balance);
}
hook Sstore _balances[KEY address addr] uint256 newValue (uint256 oldValue) STORAGE {
havoc sumOfBalances assuming sumOfBalances@new() == sumOfBalances@old() + newValue - oldValue;
sumOfBalances = sumOfBalances - oldValue + newValue;
}
/*
@ -31,7 +37,7 @@ hook Sstore _balances[KEY address addr] uint256 newValue (uint256 oldValue) STOR
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
*/
invariant totalSupplyIsSumOfBalances()
totalSupply() == sumOfBalances()
to_mathint(totalSupply()) == sumOfBalances;
/*
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
@ -39,7 +45,7 @@ invariant totalSupplyIsSumOfBalances()
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
*/
invariant zeroAddressNoBalance()
balanceOf(0) == 0
balanceOf(0) == 0;
/*
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
@ -56,8 +62,8 @@ rule noChangeTotalSupply(env e) {
f(e, args);
uint256 totalSupplyAfter = totalSupply();
assert totalSupplyAfter > totalSupplyBefore => f.selector == mint(address,uint256).selector;
assert totalSupplyAfter < totalSupplyBefore => f.selector == burn(address,uint256).selector;
assert totalSupplyAfter > totalSupplyBefore => f.selector == sig:mint(address,uint256).selector;
assert totalSupplyAfter < totalSupplyBefore => f.selector == sig:burn(address,uint256).selector;
}
/*
@ -80,9 +86,9 @@ rule onlyAuthorizedCanTransfer(env e) {
assert (
balanceAfter < balanceBefore
) => (
f.selector == burn(address,uint256).selector ||
f.selector == sig:burn(address,uint256).selector ||
e.msg.sender == account ||
balanceBefore - balanceAfter <= allowanceBefore
balanceBefore - balanceAfter <= to_mathint(allowanceBefore)
);
}
@ -106,18 +112,16 @@ rule onlyHolderOfSpenderCanChangeAllowance(env e) {
assert (
allowanceAfter > allowanceBefore
) => (
(f.selector == approve(address,uint256).selector && e.msg.sender == holder) ||
(f.selector == increaseAllowance(address,uint256).selector && e.msg.sender == holder) ||
(f.selector == permit(address,address,uint256,uint256,uint8,bytes32,bytes32).selector)
(f.selector == sig:approve(address,uint256).selector && e.msg.sender == holder) ||
(f.selector == sig:permit(address,address,uint256,uint256,uint8,bytes32,bytes32).selector)
);
assert (
allowanceAfter < allowanceBefore
) => (
(f.selector == transferFrom(address,address,uint256).selector && e.msg.sender == spender) ||
(f.selector == approve(address,uint256).selector && e.msg.sender == holder ) ||
(f.selector == decreaseAllowance(address,uint256).selector && e.msg.sender == holder ) ||
(f.selector == permit(address,address,uint256,uint256,uint8,bytes32,bytes32).selector)
(f.selector == sig:transferFrom(address,address,uint256).selector && e.msg.sender == spender) ||
(f.selector == sig:approve(address,uint256).selector && e.msg.sender == holder ) ||
(f.selector == sig:permit(address,address,uint256,uint256,uint8,bytes32,bytes32).selector)
);
}
@ -147,8 +151,8 @@ rule mint(env e) {
assert to == 0 || totalSupplyBefore + amount > max_uint256;
} else {
// updates balance and totalSupply
assert balanceOf(to) == toBalanceBefore + amount;
assert totalSupply() == totalSupplyBefore + amount;
assert to_mathint(balanceOf(to)) == toBalanceBefore + amount;
assert to_mathint(totalSupply()) == totalSupplyBefore + amount;
// no other balance is modified
assert balanceOf(other) != otherBalanceBefore => other == to;
@ -181,8 +185,8 @@ rule burn(env e) {
assert from == 0 || fromBalanceBefore < amount;
} else {
// updates balance and totalSupply
assert balanceOf(from) == fromBalanceBefore - amount;
assert totalSupply() == totalSupplyBefore - amount;
assert to_mathint(balanceOf(from)) == fromBalanceBefore - amount;
assert to_mathint(totalSupply()) == totalSupplyBefore - amount;
// no other balance is modified
assert balanceOf(other) != otherBalanceBefore => other == from;
@ -216,8 +220,8 @@ rule transfer(env e) {
assert holder == 0 || recipient == 0 || amount > holderBalanceBefore;
} else {
// balances of holder and recipient are updated
assert balanceOf(holder) == holderBalanceBefore - (holder == recipient ? 0 : amount);
assert balanceOf(recipient) == recipientBalanceBefore + (holder == recipient ? 0 : amount);
assert to_mathint(balanceOf(holder)) == holderBalanceBefore - (holder == recipient ? 0 : amount);
assert to_mathint(balanceOf(recipient)) == recipientBalanceBefore + (holder == recipient ? 0 : amount);
// no other balance is modified
assert balanceOf(other) != otherBalanceBefore => (other == holder || other == recipient);
@ -254,11 +258,11 @@ rule transferFrom(env e) {
} else {
// allowance is valid & updated
assert allowanceBefore >= amount;
assert allowance(holder, spender) == (allowanceBefore == max_uint256 ? to_uint256(max_uint256) : allowanceBefore - amount);
assert to_mathint(allowance(holder, spender)) == (allowanceBefore == max_uint256 ? max_uint256 : allowanceBefore - amount);
// balances of holder and recipient are updated
assert balanceOf(holder) == holderBalanceBefore - (holder == recipient ? 0 : amount);
assert balanceOf(recipient) == recipientBalanceBefore + (holder == recipient ? 0 : amount);
assert to_mathint(balanceOf(holder)) == holderBalanceBefore - (holder == recipient ? 0 : amount);
assert to_mathint(balanceOf(recipient)) == recipientBalanceBefore + (holder == recipient ? 0 : amount);
// no other balance is modified
assert balanceOf(other) != otherBalanceBefore => (other == holder || other == recipient);
@ -297,72 +301,6 @@ rule approve(env e) {
}
}
/*
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
Rule: increaseAllowance behavior and side effects
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
*/
rule increaseAllowance(env e) {
require nonpayable(e);
address holder = e.msg.sender;
address spender;
address otherHolder;
address otherSpender;
uint256 amount;
// cache state
uint256 allowanceBefore = allowance(holder, spender);
uint256 otherAllowanceBefore = allowance(otherHolder, otherSpender);
// run transaction
increaseAllowance@withrevert(e, spender, amount);
// check outcome
if (lastReverted) {
assert holder == 0 || spender == 0 || allowanceBefore + amount > max_uint256;
} else {
// allowance is updated
assert allowance(holder, spender) == allowanceBefore + amount;
// other allowances are untouched
assert allowance(otherHolder, otherSpender) != otherAllowanceBefore => (otherHolder == holder && otherSpender == spender);
}
}
/*
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
Rule: decreaseAllowance behavior and side effects
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
*/
rule decreaseAllowance(env e) {
require nonpayable(e);
address holder = e.msg.sender;
address spender;
address otherHolder;
address otherSpender;
uint256 amount;
// cache state
uint256 allowanceBefore = allowance(holder, spender);
uint256 otherAllowanceBefore = allowance(otherHolder, otherSpender);
// run transaction
decreaseAllowance@withrevert(e, spender, amount);
// check outcome
if (lastReverted) {
assert holder == 0 || spender == 0 || allowanceBefore < amount;
} else {
// allowance is updated
assert allowance(holder, spender) == allowanceBefore - amount;
// other allowances are untouched
assert allowance(otherHolder, otherSpender) != otherAllowanceBefore => (otherHolder == holder && otherSpender == spender);
}
}
/*
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
Rule: permit behavior and side effects
@ -402,7 +340,7 @@ rule permit(env e) {
} else {
// allowance and nonce are updated
assert allowance(holder, spender) == amount;
assert nonces(holder) == nonceBefore + 1;
assert to_mathint(nonces(holder)) == nonceBefore + 1;
// deadline was respected
assert deadline >= e.block.timestamp;

View File

@ -1,15 +1,14 @@
import "helpers/helpers.spec"
import "methods/IERC20.spec"
import "methods/IERC3156.spec"
import "helpers/helpers.spec";
import "methods/IERC20.spec";
import "methods/IERC3156FlashLender.spec";
import "methods/IERC3156FlashBorrower.spec";
methods {
// non standard ERC3156 functions
flashFeeReceiver() returns (address) envfree
function flashFeeReceiver() external returns (address) envfree;
// function summaries below
_mint(address account, uint256 amount) => specMint(account, amount)
_burn(address account, uint256 amount) => specBurn(account, amount)
_transfer(address from, address to, uint256 amount) => specTransfer(from, to, amount)
function _._update(address from, address to, uint256 amount) internal => specUpdate(from, to, amount) expect void ALL;
}
/*
@ -17,13 +16,21 @@ methods {
Ghost: track mint and burns in the CVL
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
*/
ghost mapping(address => uint256) trackedMintAmount;
ghost mapping(address => uint256) trackedBurnAmount;
ghost mapping(address => mapping(address => uint256)) trackedTransferedAmount;
ghost mapping(address => mathint) trackedMintAmount;
ghost mapping(address => mathint) trackedBurnAmount;
ghost mapping(address => mapping(address => mathint)) trackedTransferedAmount;
function specMint(address account, uint256 amount) returns bool { trackedMintAmount[account] = amount; return true; }
function specBurn(address account, uint256 amount) returns bool { trackedBurnAmount[account] = amount; return true; }
function specTransfer(address from, address to, uint256 amount) returns bool { trackedTransferedAmount[from][to] = amount; return true; }
function specUpdate(address from, address to, uint256 amount) {
if (from == 0 && to == 0) { assert(false); } // defensive
if (from == 0) {
trackedMintAmount[to] = amount;
} else if (to == 0) {
trackedBurnAmount[from] = amount;
} else {
trackedTransferedAmount[from][to] = amount;
}
}
/*
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
@ -42,7 +49,7 @@ rule checkMintAndBurn(env e) {
flashLoan(e, receiver, token, amount, data);
assert trackedMintAmount[receiver] == amount;
assert trackedBurnAmount[receiver] == amount + (recipient == 0 ? fees : 0);
assert (fees > 0 && recipient != 0) => trackedTransferedAmount[receiver][recipient] == fees;
assert trackedMintAmount[receiver] == to_mathint(amount);
assert trackedBurnAmount[receiver] == amount + to_mathint(recipient == 0 ? fees : 0);
assert (fees > 0 && recipient != 0) => trackedTransferedAmount[receiver][recipient] == to_mathint(fees);
}

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