Browse Source

Merge branch 'master' into next-v5.0

JulissaDantes 2 years ago
parent
commit
6ff283bebc
100 changed files with 2323 additions and 738 deletions
  1. 1 0
      .codecov.yml
  2. 28 0
      .github/workflows/changelog.yml
  3. 26 14
      .github/workflows/checks.yml
  4. 3 0
      .gitmodules
  5. 58 8
      CHANGELOG.md
  6. 15 16
      certora/specs/GovernorBase.spec
  7. 57 0
      contracts/access/Ownable2Step.sol
  8. 0 1
      contracts/crosschain/arbitrum/LibArbitrumL1.sol
  9. 1 1
      contracts/finance/VestingWallet.sol
  10. 4 3
      contracts/governance/Governor.sol
  11. 1 1
      contracts/governance/IGovernor.sol
  12. 2 2
      contracts/governance/README.adoc
  13. 20 14
      contracts/governance/TimelockController.sol
  14. 3 3
      contracts/governance/compatibility/GovernorCompatibilityBravo.sol
  15. 1 1
      contracts/governance/extensions/GovernorVotesQuorumFraction.sol
  16. 3 3
      contracts/governance/utils/Votes.sol
  17. 20 0
      contracts/interfaces/IERC2309.sol
  18. 2 2
      contracts/interfaces/IERC4626.sol
  19. 6 0
      contracts/interfaces/README.adoc
  20. 1 1
      contracts/metatx/MinimalForwarder.sol
  21. 1 1
      contracts/mocks/AccessControlCrossChainMock.sol
  22. 0 19
      contracts/mocks/ArraysImpl.sol
  23. 51 0
      contracts/mocks/ArraysMock.sol
  24. 0 27
      contracts/mocks/CheckpointsImpl.sol
  25. 120 0
      contracts/mocks/CheckpointsMock.sol
  26. 1 1
      contracts/mocks/ERC1155PausableMock.sol
  27. 1 1
      contracts/mocks/ERC1155SupplyMock.sol
  28. 1 1
      contracts/mocks/ERC1155URIStorageMock.sol
  29. 1 1
      contracts/mocks/ERC165/ERC165ReturnBomb.sol
  30. 1 1
      contracts/mocks/ERC20DecimalsMock.sol
  31. 2 2
      contracts/mocks/ERC2771ContextMock.sol
  32. 39 1
      contracts/mocks/ERC4626Mock.sol
  33. 55 0
      contracts/mocks/ERC721ConsecutiveEnumerableMock.sol
  34. 86 0
      contracts/mocks/ERC721ConsecutiveMock.sol
  35. 1 1
      contracts/mocks/ERC721EnumerableMock.sol
  36. 1 1
      contracts/mocks/ERC721URIStorageMock.sol
  37. 1 1
      contracts/mocks/ERC721VotesMock.sol
  38. 1 0
      contracts/mocks/EnumerableMapMock.sol
  39. 1 0
      contracts/mocks/EnumerableSetMock.sol
  40. 6 9
      contracts/mocks/GovernorCompatibilityBravoMock.sol
  41. 1 1
      contracts/mocks/GovernorMock.sol
  42. 3 4
      contracts/mocks/GovernorPreventLateQuorumMock.sol
  43. 3 5
      contracts/mocks/GovernorTimelockCompoundMock.sol
  44. 4 11
      contracts/mocks/GovernorTimelockControlMock.sol
  45. 2 2
      contracts/mocks/GovernorWithParamsMock.sol
  46. 12 0
      contracts/mocks/MathMock.sol
  47. 1 1
      contracts/mocks/MulticallTest.sol
  48. 2 2
      contracts/mocks/MultipleInheritanceInitializableMocks.sol
  49. 7 0
      contracts/mocks/Ownable2StepMock.sol
  50. 8 0
      contracts/mocks/ReentrancyMock.sol
  51. 1 0
      contracts/mocks/SafeCastMock.sol
  52. 2 2
      contracts/mocks/SafeERC20Helper.sol
  53. 4 4
      contracts/mocks/StringsMock.sol
  54. 2 2
      contracts/mocks/UUPS/UUPSLegacy.sol
  55. 3 3
      contracts/mocks/UUPS/UUPSUpgradeableMock.sol
  56. 1 1
      contracts/mocks/VotesMock.sol
  57. 19 17
      contracts/proxy/Clones.sol
  58. 1 1
      contracts/proxy/README.adoc
  59. 17 4
      contracts/proxy/utils/Initializable.sol
  60. 9 1
      contracts/security/ReentrancyGuard.sol
  61. 7 5
      contracts/token/ERC20/extensions/ERC20FlashMint.sol
  62. 44 13
      contracts/token/ERC20/extensions/ERC20Votes.sol
  63. 60 9
      contracts/token/ERC20/extensions/ERC4626.sol
  64. 1 1
      contracts/token/ERC20/utils/SafeERC20.sol
  65. 65 26
      contracts/token/ERC721/ERC721.sol
  66. 3 1
      contracts/token/ERC721/IERC721.sol
  67. 3 0
      contracts/token/ERC721/README.adoc
  68. 142 0
      contracts/token/ERC721/extensions/ERC721Consecutive.sol
  69. 11 15
      contracts/token/ERC721/extensions/ERC721Enumerable.sol
  70. 3 2
      contracts/token/ERC721/extensions/ERC721Pausable.sol
  71. 2 2
      contracts/token/ERC721/extensions/ERC721Royalty.sol
  72. 40 0
      contracts/token/ERC721/extensions/ERC721Votes.sol
  73. 3 35
      contracts/token/ERC721/extensions/draft-ERC721Votes.sol
  74. 3 2
      contracts/token/ERC721/presets/ERC721PresetMinterPauserAutoId.sol
  75. 1 1
      contracts/token/ERC777/ERC777.sol
  76. 1 1
      contracts/utils/Address.sol
  77. 59 2
      contracts/utils/Arrays.sol
  78. 483 25
      contracts/utils/Checkpoints.sol
  79. 23 6
      contracts/utils/Create2.sol
  80. 24 29
      contracts/utils/Strings.sol
  81. 21 10
      contracts/utils/cryptography/MerkleProof.sol
  82. 0 1
      contracts/utils/cryptography/SignatureChecker.sol
  83. 2 2
      contracts/utils/introspection/ERC165Checker.sol
  84. 157 38
      contracts/utils/math/Math.sol
  85. 1 0
      contracts/utils/math/SafeCast.sol
  86. 1 1
      contracts/utils/math/SignedMath.sol
  87. 8 5
      contracts/utils/structs/EnumerableMap.sol
  88. 6 3
      contracts/utils/structs/EnumerableSet.sol
  89. 82 41
      contracts/vendor/arbitrum/IArbSys.sol
  90. 76 34
      contracts/vendor/arbitrum/IBridge.sol
  91. 15 0
      contracts/vendor/arbitrum/IDelayedMessageProvider.sol
  92. 124 65
      contracts/vendor/arbitrum/IInbox.sol
  93. 0 26
      contracts/vendor/arbitrum/IMessageProvider.sol
  94. 101 32
      contracts/vendor/arbitrum/IOutbox.sol
  95. 21 0
      docs/config.js
  96. 0 91
      docs/contract.hbs
  97. 0 10
      docs/helpers.js
  98. 1 1
      docs/modules/ROOT/pages/access-control.adoc
  99. 3 3
      docs/modules/ROOT/pages/crosschain.adoc
  100. 2 2
      docs/modules/ROOT/pages/erc1155.adoc

+ 1 - 0
.codecov.yml

@@ -6,6 +6,7 @@ coverage:
     patch:
       default:
         target: 95%
+        only_pulls: true
     project:
       default:
         threshold: 1%

+ 28 - 0
.github/workflows/changelog.yml

@@ -0,0 +1,28 @@
+name: changelog
+
+on:
+  pull_request:
+    types:
+      - opened
+      - synchronize
+      - labeled
+      - unlabeled
+
+concurrency:
+  group: changelog-${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  check:
+    runs-on: ubuntu-latest
+    if: ${{ !contains(github.event.pull_request.labels.*.name, 'ignore-changelog') }}
+    steps:
+      - uses: actions/checkout@v3
+      - name: Check diff
+        run: |
+          git fetch origin ${{ github.base_ref }} --depth=1
+          if git diff --exit-code origin/${{ github.base_ref }} -- CHANGELOG.md ; then
+            echo 'Missing changelog entry'
+            exit 1
+          fi
+

+ 26 - 14
.github/workflows/checks.yml

@@ -14,19 +14,6 @@ concurrency:
   cancel-in-progress: true
 
 jobs:
-  changelog:
-    if: github.event_name == 'pull_request' && github.repository != 'OpenZeppelin/openzeppelin-contracts-upgradeable'
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v3
-      - name: Check diff
-        run: |
-          git fetch origin ${{ github.base_ref }} --depth=1
-          if git diff --exit-code origin/${{ github.base_ref }} -- CHANGELOG.md ; then
-            echo 'Missing changelog entry'
-            exit 1
-          fi
-
   lint:
     if: github.repository != 'OpenZeppelin/openzeppelin-contracts-upgradeable'
     runs-on: ubuntu-latest
@@ -57,6 +44,20 @@ jobs:
         with:
           token: ${{ github.token }}
 
+  foundry-tests:
+    if: github.repository != 'OpenZeppelin/openzeppelin-contracts-upgradeable'
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v3
+        with:
+          submodules: recursive
+      - name: Install Foundry
+        uses: foundry-rs/foundry-toolchain@v1
+        with:
+          version: nightly
+      - name: Run tests
+        run: forge test -vv
+
   coverage:
     if: github.repository != 'OpenZeppelin/openzeppelin-contracts-upgradeable'
     runs-on: ubuntu-latest
@@ -76,4 +77,15 @@ jobs:
       - uses: actions/checkout@v3
       - name: Set up environment
         uses: ./.github/actions/setup
-      - uses: crytic/slither-action@v0.1.1
+      - uses: crytic/slither-action@v0.2.0
+
+  codespell:
+    if: github.repository != 'OpenZeppelin/openzeppelin-contracts-upgradeable'
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v3
+      - name: Run CodeSpell
+        uses: codespell-project/actions-codespell@v1.0
+        with:
+          check_filenames: true
+          skip: package-lock.json

+ 3 - 0
.gitmodules

@@ -0,0 +1,3 @@
+[submodule "lib/forge-std"]
+	path = lib/forge-std
+	url = https://github.com/foundry-rs/forge-std

+ 58 - 8
CHANGELOG.md

@@ -2,21 +2,62 @@
 
 ## Unreleased
 
+ * `ReentrancyGuard`: Add a `_reentrancyGuardEntered` function to expose the guard status. ([#3714](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3714))
+ * `ERC20Votes`: optimize by using unchecked arithmetic. ([#3748](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3748))
+
+## Unreleased
+
+ * `TimelockController`: Added a new `admin` constructor parameter that is assigned the admin role instead of the deployer account. ([#3722](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3722))
  * `Initializable`: add internal functions `_getInitializedVersion` and `_isInitializing` ([#3598](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3598))
  * `ERC165Checker`: add `supportsERC165InterfaceUnchecked` for consulting individual interfaces without the full ERC165 protocol. ([#3339](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3339))
  * `Address`: optimize `functionCall` by calling `functionCallWithValue` directly. ([#3468](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3468))
  * `Address`: optimize `functionCall` functions by checking contract size only if there is no returned data. ([#3469](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3469))
+ * `Governor`: make the `relay` function payable, and add support for EOA payments. ([#3730](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3730))
  * `GovernorCompatibilityBravo`: remove unused `using` statements. ([#3506](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3506))
  * `ERC20`: optimize `_transfer`, `_mint` and `_burn` by using `unchecked` arithmetic when possible. ([#3513](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3513))
+ * `ERC20Votes`, `ERC721Votes`: optimize `getPastVotes` for looking up recent checkpoints. ([#3673](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3673))
  * `ERC20FlashMint`: add an internal `_flashFee` function for overriding. ([#3551](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3551))
+ * `ERC4626`: use the same `decimals()` as the underlying asset by default (if available). ([#3639](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3639))
+ * `ERC4626`: add internal `_initialConvertToShares` and `_initialConvertToAssets` functions to customize empty vaults behavior. ([#3639](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3639))
  * `ERC721`: optimize transfers by making approval clearing implicit instead of emitting an event. ([#3481](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3481))
  * `ERC721`: optimize burn by making approval clearing implicit instead of emitting an event. ([#3538](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3538))
  * `ERC721`: Fix balance accounting when a custom `_beforeTokenTransfer` hook results in a transfer of the token under consideration. ([#3611](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3611))
+ * `ERC721`: use unchecked arithmetic for balance updates. ([#3524](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3524))
+ * `ERC721Consecutive`: Implementation of EIP-2309 that allows batch minting of ERC721 tokens during construction. ([#3311](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3311))
  * `ReentrancyGuard`: Reduce code size impact of the modifier by using internal functions. ([#3515](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3515))
  * `SafeCast`: optimize downcasting of signed integers. ([#3565](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3565))
- * `VestingWallet`: remove unused library `Math.sol`. ([#3605](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3605))
  * `ECDSA`: Remove redundant check on the `v` value. ([#3591](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3591))
  * `VestingWallet`: add `releasable` getters. ([#3580](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3580))
+ * `VestingWallet`: remove unused library `Math.sol`. ([#3605](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3605))
+ * `VestingWallet`: make constructor payable. ([#3665](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3665))
+ * `Create2`: optimize address computation by using assembly instead of `abi.encodePacked`. ([#3600](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3600))
+ * `Clones`: optimized the assembly to use only the scratch space during deployments, and optimized `predictDeterministicAddress` to use fewer operations. ([#3640](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3640))
+ * `Checkpoints`: Use procedural generation to support multiple key/value lengths. ([#3589](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3589))
+ * `Checkpoints`: Add new lookup mechanisms. ([#3589](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3589))
+ * `Arrays`: Add `unsafeAccess` functions that allow reading and writing to an element in a storage array bypassing Solidity's "out-of-bounds" check. ([#3589](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3589))
+ * `Strings`: optimize `toString`. ([#3573](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3573))
+ * `Ownable2Step`: extension of `Ownable` that makes the ownership transfers a two step process. ([#3620](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3620))
+ * `Math` and `SignedMath`: optimize function `max` by using `>` instead of `>=`. ([#3679](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3679))
+ * `Math`: Add `log2`, `log10` and `log256`. ([#3670](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3670))
+ * Arbitrum: Update the vendored arbitrum contracts to match the nitro upgrade. ([#3692](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3692))
+ * `Math`: optimize `log256` rounding check. ([#3745](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3745))
+
+### Breaking changes
+
+ * `ERC721`: In order to add support for batch minting via `ERC721Consecutive` it was necessary to make a minor breaking change in the internal interface of `ERC721`. Namely, the hooks `_beforeTokenTransfer` and `_afterTokenTransfer` have one additional argument that may need to be added to overrides:
+
+```diff
+ function _beforeTokenTransfer(
+     address from,
+     address to,
+     uint256 tokenId,
++    uint256 batchSize
+ ) internal virtual override
+```
+
+ * `ERC4626`: Conversion from shares to assets (and vice-versa) in an empty vault used to consider the possible mismatch between the underlying asset's and the vault's decimals. This initial conversion rate is now set to 1-to-1 irrespective of decimals, which are meant for usability purposes only. The vault now uses the assets decimals by default, so off-chain the numbers should appear the same. Developers overriding the vault decimals to a value that does not match the underlying asset may want to override the `_initialConvertToShares` and `_initialConvertToAssets` to replicate the previous behavior.
+
+ * `TimelockController`: During deployment, the TimelockController used to grant the `TIMELOCK_ADMIN_ROLE` to the deployer and to the timelock itself. The deployer was then expected to renounce this role once configuration of the timelock is over. Failing to renounce that role allows the deployer to change the timelock permissions (but not to bypass the delay for any time-locked actions). The role is no longer given to the deployer by default. A new parameter `admin` can be set to a non-zero address to grant the admin role during construction (to the deployer or any other address). Just like previously, this admin role should be renounced after configuration. If this param is given `address(0)`, the role is not allocated and doesn't need to be revoked. In any case, the timelock itself continues to have this role.
 
 ### Deprecations
 
@@ -27,10 +68,19 @@
 +import "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
 ```
 
-### Compatibility Note
+ * `ERC721Votes`: Added the file `ERC721Votes.sol` and deprecated `draft-ERC721Votes.sol` since it no longer depends on a Draft EIP (EIP-712). Developers are encouraged to update their imports. ([#3699](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3699))
+
+```diff
+-import "@openzeppelin/contracts/token/ERC721/extensions/draft-ERC721Votes.sol";
++import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Votes.sol";
+```
+
+### ERC-721 Compatibility Note
 
 ERC-721 integrators that interpret contract state from events should make sure that they implement the clearing of approval that is implicit in every transfer according to the EIP. Previous versions of OpenZeppelin Contracts emitted an explicit `Approval` event even though it was not required by the specification, and this is no longer the case.
 
+With the new `ERC721Consecutive` extension, the internal workings of `ERC721` are slightly changed. Custom extensions to ERC721 should be reviewed to ensure they remain correct. The internal functions that should be considered are `_ownerOf` (new), `_beforeTokenTransfer`, and `_afterTokenTransfer`.
+
 ## 4.7.3
 
 ### Breaking changes
@@ -103,7 +153,7 @@ ERC-721 integrators that interpret contract state from events should make sure t
 ### Breaking changes
 
 * `Governor`: Adds internal virtual `_getVotes` method that must be implemented; this is a breaking change for existing concrete extensions to `Governor`. To fix this on an existing voting module extension, rename `getVotes` to `_getVotes` and add a `bytes memory` argument. ([#3043](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3043))
-* `Governor`: Adds `params` parameter to internal virtual `_countVote ` method; this is a breaking change for existing concrete extensions to `Governor`. To fix this on an existing counting module extension, add a `bytes memory` argument to `_countVote`. ([#3043](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3043))
+* `Governor`: Adds `params` parameter to internal virtual `_countVote` method; this is a breaking change for existing concrete extensions to `Governor`. To fix this on an existing counting module extension, add a `bytes memory` argument to `_countVote`. ([#3043](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3043))
 * `Governor`: Does not emit `VoteCast` event when params data is non-empty; instead emits `VoteCastWithParams` event. To fix this on an integration that consumes the `VoteCast` event, also fetch/monitor `VoteCastWithParams` events. ([#3043](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3043))
 * `Votes`: The internal virtual function `_getVotingUnits` was made `view` (which was accidentally missing). Any overrides should now be updated so they are `view` as well.
 
@@ -126,7 +176,7 @@ ERC-721 integrators that interpret contract state from events should make sure t
  * `ERC777`: do not update allowance on `transferFrom` when allowance is `type(uint256).max`. ([#3085](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3085))
  * `ERC777`: add a `_spendAllowance` internal function. ([#3170](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3170))
  * `SignedMath`: a new signed version of the Math library with `max`, `min`,  and `average`. ([#2686](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2686))
- * `SignedMath`: add a `abs(int256)` method that returns the unsigned absolute value of a signed value. ([#2984](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2984))
+ * `SignedMath`: add an `abs(int256)` method that returns the unsigned absolute value of a signed value. ([#2984](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2984))
  * `ERC1967Upgrade`: Refactor the secure upgrade to use `ERC1822` instead of the previous rollback mechanism. This reduces code complexity and attack surface with similar security guarantees. ([#3021](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3021))
  * `UUPSUpgradeable`: Add `ERC1822` compliance to support the updated secure upgrade mechanism. ([#3021](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3021))
  * Some more functions have been made virtual to customize them via overrides. In many cases this will not imply that other functions in the contract will automatically adapt to the overridden definitions. People who wish to override should consult the source code to understand the impact and if they need to override any additional functions to achieve the desired behavior.
@@ -176,8 +226,8 @@ It is no longer possible to call an `initializer`-protected function from within
  * `ECDSA`: add a variant of `toEthSignedMessageHash` for arbitrary length message hashing. ([#2865](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2865))
  * `MerkleProof`: add a `processProof` function that returns the rebuilt root hash given a leaf and a proof. ([#2841](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2841))
  * `VestingWallet`: new contract that handles the vesting of Ether and ERC20 tokens following a customizable vesting schedule. ([#2748](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2748))
- * `Governor`: enable receiving Ether when a Timelock contract is not used. ([#2748](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2849))
- * `GovernorTimelockCompound`: fix ability to use Ether stored in the Timelock contract. ([#2748](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2849))
+ * `Governor`: enable receiving Ether when a Timelock contract is not used. ([#2849](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2849))
+ * `GovernorTimelockCompound`: fix ability to use Ether stored in the Timelock contract. ([#2849](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2849))
 
 ## 4.3.3
 
@@ -230,7 +280,7 @@ It is no longer possible to call an `initializer`-protected function from within
  * `SignatureChecker`: add a signature verification library that supports both EOA and ERC1271 compliant contracts as signers. ([#2532](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2532))
  * `Multicall`: add abstract contract with `multicall(bytes[] calldata data)` function to bundle multiple calls together ([#2608](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2608))
  * `ECDSA`: add support for ERC2098 short-signatures. ([#2582](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2582))
- * `AccessControl`: add a `onlyRole` modifier to restrict specific function to callers bearing a specific role. ([#2609](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2609))
+ * `AccessControl`: add an `onlyRole` modifier to restrict specific function to callers bearing a specific role. ([#2609](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2609))
  * `StorageSlot`: add a library for reading and writing primitive types to specific storage slots. ([#2542](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2542))
  * UUPS Proxies: add `UUPSUpgradeable` to implement the UUPS proxy pattern together with `EIP1967Proxy`. ([#2542](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2542))
 
@@ -548,7 +598,7 @@ Refer to the table below to adjust your inheritance list.
  * Now conforming to a 4-space indentation code style. ([1508](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1508))
  * `ERC20`: more gas efficient due to removed redundant `require`s. ([#1409](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1409))
  * `ERC721`: fixed a bug that prevented internal data structures from being properly cleaned, missing potential gas refunds. ([#1539](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1539) and [#1549](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1549))
- * `ERC721`: general gas savings on `transferFrom`, `_mint` and `_burn`, due to redudant `require`s and `SSTORE`s. ([#1549](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1549))
+ * `ERC721`: general gas savings on `transferFrom`, `_mint` and `_burn`, due to redundant `require`s and `SSTORE`s. ([#1549](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1549))
 
 ### Bugfixes
 

+ 15 - 16
certora/specs/GovernorBase.spec

@@ -98,26 +98,26 @@ function helperFunctionsWithRevert(uint256 proposalId, method f, env e) {
  // To use env with general preserved block disable type checking [--disableLocalTypeChecking]
 invariant startAndEndDatesNonZero(uint256 pId)
         proposalSnapshot(pId) != 0 <=> proposalDeadline(pId) != 0
-        { preserved with (env e){   
+        { preserved with (env e){
                 require e.block.number > 0;
         }}
-        
+
 
 /*
- * If a proposal is canceled it must have a start and an end date 
+ * If a proposal is canceled it must have a start and an end date
  */
  // To use env with general preserved block disable type checking [--disableLocalTypeChecking]
 invariant canceledImplyStartAndEndDateNonZero(uint pId)
         isCanceled(pId) => proposalSnapshot(pId) != 0
-        {preserved with (env e){               
+        {preserved with (env e){
                 require e.block.number > 0;
         }}
 
 
 /*
- * If a proposal is executed it must have a start and an end date 
+ * If a proposal is executed it must have a start and an end date
  */
- // To use env with general preserved block disable type checking [--disableLocalTypeChecking] 
+ // To use env with general preserved block disable type checking [--disableLocalTypeChecking]
 invariant executedImplyStartAndEndDateNonZero(uint pId)
         isExecuted(pId) => proposalSnapshot(pId) != 0
         { preserved with (env e){
@@ -143,7 +143,7 @@ invariant voteStartBeforeVoteEnd(uint256 pId)
 /*
  * A proposal cannot be both executed and canceled simultaneously.
  */
-invariant noBothExecutedAndCanceled(uint256 pId) 
+invariant noBothExecutedAndCanceled(uint256 pId)
         !isExecuted(pId) || !isCanceled(pId)
 
 
@@ -154,10 +154,10 @@ rule executionOnlyIfQuoromReachedAndVoteSucceeded(uint256 pId, env e, method f){
     bool isExecutedBefore = isExecuted(pId);
     bool quorumReachedBefore = _quorumReached(e, pId);
     bool voteSucceededBefore = _voteSucceeded(pId);
-    
+
     calldataarg args;
     f(e, args);
-    
+
     bool isExecutedAfter = isExecuted(pId);
     assert (!isExecutedBefore && isExecutedAfter) => (quorumReachedBefore && voteSucceededBefore), "quorum was changed";
 }
@@ -177,16 +177,16 @@ rule executionOnlyIfQuoromReachedAndVoteSucceeded(uint256 pId, env e, method f){
  // the fact that the 3 functions themselves makes no changes, but rather call an internal function to execute.
  // That means that we do not check those 3 functions directly, however for castVote & castVoteWithReason it is quite trivial
  // to understand why this is ok. For castVoteBySig we basically assume that the signature referendum is correct without checking it.
- // We could check each function separately and pass the rule, but that would have uglyfied the code with no concrete 
+ // We could check each function separately and pass the rule, but that would have uglyfied the code with no concrete
  // benefit, as it is evident that nothing is happening in the first 2 functions (calling a view function), and we do not desire to check the signature verification.
 rule doubleVoting(uint256 pId, uint8 sup, method f) {
     env e;
-    address user = e.msg.sender;        
+    address user = e.msg.sender;
     bool votedCheck = hasVoted(e, pId, user);
 
     castVote@withrevert(e, pId, sup);
 
-    assert votedCheck => lastReverted, "double voting accured";
+    assert votedCheck => lastReverted, "double voting occurred";
 }
 
 
@@ -207,7 +207,7 @@ rule immutableFieldsAfterProposalCreation(uint256 pId, method f) {
     uint256 _voteEnd = proposalDeadline(pId);
 
     require proposalCreated(pId); // startDate > 0
-    
+
     env e; calldataarg arg;
     f(e, arg);
 
@@ -226,7 +226,7 @@ rule noStartBeforeCreation(uint256 pId) {
     // This line makes sure that we see only cases where start date is changed from 0, i.e. creation of proposal
     // We proved in immutableFieldsAfterProposalCreation that once dates set for proposal, it cannot be changed
     require !proposalCreated(pId); // previousStart == 0;
-    
+
     env e; calldataarg args;
     propose(e, args);
 
@@ -273,7 +273,7 @@ rule noExecuteOrCancelBeforeDeadline(uint256 pId, method f){
  * All proposal specific (non-view) functions should revert if proposal is executed
  */
  // In this rule we show that if a function is executed, i.e. execute() was called on the proposal ID,
- // non of the proposal specific functions can make changes again. In executedOnlyAfterExecuteFunc 
+ // non of the proposal specific functions can make changes again. In executedOnlyAfterExecuteFunc
  // we connected the executed attribute to the execute() function, showing that only execute() can
  // change it, and that it will always change it.
 rule allFunctionsRevertIfExecuted(method f) filtered { f ->
@@ -331,4 +331,3 @@ rule executedOnlyAfterExecuteFunc(address[] targets, uint256[] values, bytes[] c
     bool executedAfter = isExecuted(pId);
     assert(executedAfter != executedBefore => f.selector == execute(address[], uint256[], bytes[], bytes32).selector, "isExecuted only changes in the execute method");
 }
-

+ 57 - 0
contracts/access/Ownable2Step.sol

@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
+
+pragma solidity ^0.8.0;
+
+import "./Ownable.sol";
+
+/**
+ * @dev Contract module which provides access control mechanism, where
+ * there is an account (an owner) that can be granted exclusive access to
+ * specific functions.
+ *
+ * By default, the owner account will be the one that deploys the contract. This
+ * can later be changed with {transferOwnership} and {acceptOwnership}.
+ *
+ * This module is used through inheritance. It will make available all functions
+ * from parent (Ownable).
+ */
+abstract contract Ownable2Step is Ownable {
+    address private _pendingOwner;
+
+    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
+
+    /**
+     * @dev Returns the address of the pending owner.
+     */
+    function pendingOwner() public view virtual returns (address) {
+        return _pendingOwner;
+    }
+
+    /**
+     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
+     * Can only be called by the current owner.
+     */
+    function transferOwnership(address newOwner) public virtual override onlyOwner {
+        _pendingOwner = newOwner;
+        emit OwnershipTransferStarted(owner(), newOwner);
+    }
+
+    /**
+     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
+     * Internal function without access restriction.
+     */
+    function _transferOwnership(address newOwner) internal virtual override {
+        delete _pendingOwner;
+        super._transferOwnership(newOwner);
+    }
+
+    /**
+     * @dev The new owner accepts the ownership transfer.
+     */
+    function acceptOwnership() external {
+        address sender = _msgSender();
+        require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
+        _transferOwnership(sender);
+    }
+}

+ 0 - 1
contracts/crosschain/arbitrum/LibArbitrumL1.sol

@@ -4,7 +4,6 @@
 pragma solidity ^0.8.4;
 
 import {IBridge as ArbitrumL1_Bridge} from "../../vendor/arbitrum/IBridge.sol";
-import {IInbox as ArbitrumL1_Inbox} from "../../vendor/arbitrum/IInbox.sol";
 import {IOutbox as ArbitrumL1_Outbox} from "../../vendor/arbitrum/IOutbox.sol";
 import "../errors.sol";
 

+ 1 - 1
contracts/finance/VestingWallet.sol

@@ -33,7 +33,7 @@ contract VestingWallet is Context {
         address beneficiaryAddress,
         uint64 startTimestamp,
         uint64 durationSeconds
-    ) {
+    ) payable {
         require(beneficiaryAddress != address(0), "VestingWallet: beneficiary is zero address");
         _beneficiary = beneficiaryAddress;
         _start = startTimestamp;

+ 4 - 3
contracts/governance/Governor.sol

@@ -22,7 +22,7 @@ import "./IGovernor.sol";
  *
  * - A counting module must implement {quorum}, {_quorumReached}, {_voteSucceeded} and {_countVote}
  * - A voting module must implement {_getVotes}
- * - Additionanly, the {votingPeriod} must also be implemented
+ * - Additionally, the {votingPeriod} must also be implemented
  *
  * _Available since v4.3._
  */
@@ -544,8 +544,9 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor, IERC721Receive
         address target,
         uint256 value,
         bytes calldata data
-    ) external virtual onlyGovernance {
-        Address.functionCallWithValue(target, data, value);
+    ) external payable virtual onlyGovernance {
+        (bool success, bytes memory returndata) = target.call{value: value}(data);
+        Address.verifyCallResult(success, returndata, "Governor: relay reverted without message");
     }
 
     /**

+ 1 - 1
contracts/governance/IGovernor.sol

@@ -184,7 +184,7 @@ abstract contract IGovernor is IERC165 {
 
     /**
      * @notice module:voting
-     * @dev Returns weither `account` has cast a vote on `proposalId`.
+     * @dev Returns whether `account` has cast a vote on `proposalId`.
      */
     function hasVoted(uint256 proposalId, address account) public view virtual returns (bool);
 

+ 2 - 2
contracts/governance/README.adoc

@@ -118,7 +118,7 @@ Both operations contain:
 
 * *Target*, the address of the smart contract that the timelock should operate on.
 * *Value*, in wei, that should be sent with the transaction. Most of the time this will be 0. Ether can be deposited before-end or passed along when executing the transaction.
-* *Data*, containing the encoded function selector and parameters of the call. This can be produced using a number of tools. For example, a maintenance operation granting role `ROLE` to `ACCOUNT` can be encode using web3js as follows:
+* *Data*, containing the encoded function selector and parameters of the call. This can be produced using a number of tools. For example, a maintenance operation granting role `ROLE` to `ACCOUNT` can be encoded using web3js as follows:
 
 ```javascript
 const data = timelock.contract.methods.grantRole(ROLE, ACCOUNT).encodeABI()
@@ -153,7 +153,7 @@ Operations status can be queried using the functions:
 [[timelock-admin]]
 ===== Admin
 
-The admins are in charge of managing proposers and executors. For the timelock to be self-governed, this role should only be given to the timelock itself. Upon deployment, both the timelock and the deployer have this role. After further configuration and testing, the deployer can renounce this role such that all further maintenance operations have to go through the timelock process.
+The admins are in charge of managing proposers and executors. For the timelock to be self-governed, this role should only be given to the timelock itself. Upon deployment, the admin role can be granted to any address (in addition to the timelock itself). After further configuration and testing, this optional admin should renounce its role such that all further maintenance operations have to go through the timelock process.
 
 This role is identified by the *TIMELOCK_ADMIN_ROLE* value: `0x5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca5`
 

+ 20 - 14
contracts/governance/TimelockController.sol

@@ -62,31 +62,37 @@ contract TimelockController is AccessControl, IERC721Receiver, IERC1155Receiver
     event MinDelayChange(uint256 oldDuration, uint256 newDuration);
 
     /**
-     * @dev Initializes the contract with a given `minDelay`, and a list of
-     * initial proposers and executors. The proposers receive both the
-     * proposer and the canceller role (for backward compatibility). The
-     * executors receive the executor role.
+     * @dev Initializes the contract with the following parameters:
      *
-     * NOTE: At construction, both the deployer and the timelock itself are
-     * administrators. This helps further configuration of the timelock by the
-     * deployer. After configuration is done, it is recommended that the
-     * deployer renounces its admin position and relies on timelocked
-     * operations to perform future maintenance.
+     * - `minDelay`: initial minimum delay for operations
+     * - `proposers`: accounts to be granted proposer and canceller roles
+     * - `executors`: accounts to be granted executor role
+     * - `admin`: optional account to be granted admin role; disable with zero address
+     *
+     * IMPORTANT: The optional admin can aid with initial configuration of roles after deployment
+     * without being subject to delay, but this role should be subsequently renounced in favor of
+     * administration through timelocked proposals. Previous versions of this contract would assign
+     * this admin to the deployer automatically and should be renounced as well.
      */
     constructor(
         uint256 minDelay,
         address[] memory proposers,
-        address[] memory executors
+        address[] memory executors,
+        address admin
     ) {
         _setRoleAdmin(TIMELOCK_ADMIN_ROLE, TIMELOCK_ADMIN_ROLE);
         _setRoleAdmin(PROPOSER_ROLE, TIMELOCK_ADMIN_ROLE);
         _setRoleAdmin(EXECUTOR_ROLE, TIMELOCK_ADMIN_ROLE);
         _setRoleAdmin(CANCELLER_ROLE, TIMELOCK_ADMIN_ROLE);
 
-        // deployer + self administration
-        _setupRole(TIMELOCK_ADMIN_ROLE, _msgSender());
+        // self administration
         _setupRole(TIMELOCK_ADMIN_ROLE, address(this));
 
+        // optional admin
+        if (admin != address(0)) {
+            _setupRole(TIMELOCK_ADMIN_ROLE, admin);
+        }
+
         // register proposers and cancellers
         for (uint256 i = 0; i < proposers.length; ++i) {
             _setupRole(PROPOSER_ROLE, proposers[i]);
@@ -158,7 +164,7 @@ contract TimelockController is AccessControl, IERC721Receiver, IERC1155Receiver
     }
 
     /**
-     * @dev Returns the timestamp at with an operation becomes ready (0 for
+     * @dev Returns the timestamp at which an operation becomes ready (0 for
      * unset operations, 1 for done operations).
      */
     function getTimestamp(bytes32 id) public view virtual returns (uint256 timestamp) {
@@ -252,7 +258,7 @@ contract TimelockController is AccessControl, IERC721Receiver, IERC1155Receiver
     }
 
     /**
-     * @dev Schedule an operation that is to becomes valid after a given delay.
+     * @dev Schedule an operation that is to become valid after a given delay.
      */
     function _schedule(bytes32 id, uint256 delay) private {
         require(!isOperation(id), "TimelockController: operation already scheduled");

+ 3 - 3
contracts/governance/compatibility/GovernorCompatibilityBravo.sol

@@ -9,10 +9,10 @@ import "../Governor.sol";
 import "./IGovernorCompatibilityBravo.sol";
 
 /**
- * @dev Compatibility layer that implements GovernorBravo compatibility on to of {Governor}.
+ * @dev Compatibility layer that implements GovernorBravo compatibility on top of {Governor}.
  *
  * This compatibility layer includes a voting system and requires a {IGovernorTimelock} compatible module to be added
- * through inheritance. It does not include token bindings, not does it include any variable upgrade patterns.
+ * through inheritance. It does not include token bindings, nor does it include any variable upgrade patterns.
  *
  * NOTE: When using this module, you may need to enable the Solidity optimizer to avoid hitting the contract size limit.
  *
@@ -247,7 +247,7 @@ abstract contract GovernorCompatibilityBravo is IGovernorTimelock, IGovernorComp
     }
 
     /**
-     * @dev See {Governor-_voteSucceeded}. In this module, the forVotes must be scritly over the againstVotes.
+     * @dev See {Governor-_voteSucceeded}. In this module, the forVotes must be strictly over the againstVotes.
      */
     function _voteSucceeded(uint256 proposalId) internal view virtual override returns (bool) {
         ProposalDetails storage details = _proposalDetails[proposalId];

+ 1 - 1
contracts/governance/extensions/GovernorVotesQuorumFraction.sol

@@ -55,7 +55,7 @@ abstract contract GovernorVotesQuorumFraction is GovernorVotes {
             return latest._value;
         }
 
-        // Otherwize, do the binary search
+        // Otherwise, do the binary search
         return _quorumNumeratorHistory.getAtBlock(blockNumber);
     }
 

+ 3 - 3
contracts/governance/utils/Votes.sol

@@ -56,7 +56,7 @@ abstract contract Votes is IVotes, Context, EIP712 {
      * - `blockNumber` must have been already mined
      */
     function getPastVotes(address account, uint256 blockNumber) public view virtual override returns (uint256) {
-        return _delegateCheckpoints[account].getAtBlock(blockNumber);
+        return _delegateCheckpoints[account].getAtProbablyRecentBlock(blockNumber);
     }
 
     /**
@@ -72,7 +72,7 @@ abstract contract Votes is IVotes, Context, EIP712 {
      */
     function getPastTotalSupply(uint256 blockNumber) public view virtual override returns (uint256) {
         require(blockNumber < block.number, "Votes: block not yet mined");
-        return _totalCheckpoints.getAtBlock(blockNumber);
+        return _totalCheckpoints.getAtProbablyRecentBlock(blockNumber);
     }
 
     /**
@@ -122,7 +122,7 @@ abstract contract Votes is IVotes, Context, EIP712 {
     /**
      * @dev Delegate all of `account`'s voting units to `delegatee`.
      *
-     * Emits events {DelegateChanged} and {DelegateVotesChanged}.
+     * Emits events {IVotes-DelegateChanged} and {IVotes-DelegateVotesChanged}.
      */
     function _delegate(address account, address delegatee) internal virtual {
         address oldDelegate = delegates(account);

+ 20 - 0
contracts/interfaces/IERC2309.sol

@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: MIT
+
+pragma solidity ^0.8.0;
+
+/**
+ * @dev ERC-2309: ERC-721 Consecutive Transfer Extension.
+ *
+ * _Available since v4.8._
+ */
+interface IERC2309 {
+    /**
+     * @dev Emitted when the tokens from `fromTokenId` to `toTokenId` are transferred from `fromAddress` to `toAddress`.
+     */
+    event ConsecutiveTransfer(
+        uint256 indexed fromTokenId,
+        uint256 toTokenId,
+        address indexed fromAddress,
+        address indexed toAddress
+    );
+}

+ 2 - 2
contracts/interfaces/IERC4626.sol

@@ -13,10 +13,10 @@ import "../token/ERC20/extensions/IERC20Metadata.sol";
  * _Available since v4.7._
  */
 interface IERC4626 is IERC20, IERC20Metadata {
-    event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares);
+    event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);
 
     event Withdraw(
-        address indexed caller,
+        address indexed sender,
         address indexed receiver,
         address indexed owner,
         uint256 assets,

+ 6 - 0
contracts/interfaces/README.adoc

@@ -24,10 +24,12 @@ are useful to interact with third party contracts that implement them.
 - {IERC1363}
 - {IERC1820Implementer}
 - {IERC1820Registry}
+- {IERC1822Proxiable}
 - {IERC2612}
 - {IERC2981}
 - {IERC3156FlashLender}
 - {IERC3156FlashBorrower}
+- {IERC4626}
 
 == Detailed ABI
 
@@ -41,6 +43,8 @@ are useful to interact with third party contracts that implement them.
 
 {{IERC1820Registry}}
 
+{{IERC1822Proxiable}}
+
 {{IERC2612}}
 
 {{IERC2981}}
@@ -48,3 +52,5 @@ are useful to interact with third party contracts that implement them.
 {{IERC3156FlashLender}}
 
 {{IERC3156FlashBorrower}}
+
+{{IERC4626}}

+ 1 - 1
contracts/metatx/MinimalForwarder.sol

@@ -57,7 +57,7 @@ contract MinimalForwarder is EIP712 {
         );
 
         // Validate that the relayer has sent enough gas for the call.
-        // See https://ronan.eth.link/blog/ethereum-gas-dangers/
+        // See https://ronan.eth.limo/blog/ethereum-gas-dangers/
         if (gasleft() <= req.gas / 63) {
             // We explicitly trigger invalid opcode to consume all gas and bubble-up the effects, since
             // neither revert or assert consume all gas since Solidity 0.8.0

+ 1 - 1
contracts/mocks/AccessControlCrossChainMock.sol

@@ -16,7 +16,7 @@ contract AccessControlCrossChainMock is AccessControlCrossChain, CrossChainEnabl
 
     function senderProtected(bytes32 roleId) public onlyRole(roleId) {}
 
-    function crossChainRoleAlias(bytes32 role) public pure virtual returns (bytes32) {
+    function crossChainRoleAlias(bytes32 role) public pure returns (bytes32) {
         return _crossChainRoleAlias(role);
     }
 }

+ 0 - 19
contracts/mocks/ArraysImpl.sol

@@ -1,19 +0,0 @@
-// SPDX-License-Identifier: MIT
-
-pragma solidity ^0.8.0;
-
-import "../utils/Arrays.sol";
-
-contract ArraysImpl {
-    using Arrays for uint256[];
-
-    uint256[] private _array;
-
-    constructor(uint256[] memory array) {
-        _array = array;
-    }
-
-    function findUpperBound(uint256 element) external view returns (uint256) {
-        return _array.findUpperBound(element);
-    }
-}

+ 51 - 0
contracts/mocks/ArraysMock.sol

@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: MIT
+
+pragma solidity ^0.8.0;
+
+import "../utils/Arrays.sol";
+
+contract Uint256ArraysMock {
+    using Arrays for uint256[];
+
+    uint256[] private _array;
+
+    constructor(uint256[] memory array) {
+        _array = array;
+    }
+
+    function findUpperBound(uint256 element) external view returns (uint256) {
+        return _array.findUpperBound(element);
+    }
+
+    function unsafeAccess(uint256 pos) external view returns (uint256) {
+        return _array.unsafeAccess(pos).value;
+    }
+}
+
+contract AddressArraysMock {
+    using Arrays for address[];
+
+    address[] private _array;
+
+    constructor(address[] memory array) {
+        _array = array;
+    }
+
+    function unsafeAccess(uint256 pos) external view returns (address) {
+        return _array.unsafeAccess(pos).value;
+    }
+}
+
+contract Bytes32ArraysMock {
+    using Arrays for bytes32[];
+
+    bytes32[] private _array;
+
+    constructor(bytes32[] memory array) {
+        _array = array;
+    }
+
+    function unsafeAccess(uint256 pos) external view returns (bytes32) {
+        return _array.unsafeAccess(pos).value;
+    }
+}

+ 0 - 27
contracts/mocks/CheckpointsImpl.sol

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

+ 120 - 0
contracts/mocks/CheckpointsMock.sol

@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: MIT
+// This file was procedurally generated from scripts/generate/templates/CheckpointsMock.js.
+
+pragma solidity ^0.8.0;
+
+import "../utils/Checkpoints.sol";
+
+contract CheckpointsMock {
+    using Checkpoints for Checkpoints.History;
+
+    Checkpoints.History private _totalCheckpoints;
+
+    function latest() public view returns (uint256) {
+        return _totalCheckpoints.latest();
+    }
+
+    function latestCheckpoint()
+        public
+        view
+        returns (
+            bool,
+            uint256,
+            uint256
+        )
+    {
+        return _totalCheckpoints.latestCheckpoint();
+    }
+
+    function length() public view returns (uint256) {
+        return _totalCheckpoints.length();
+    }
+
+    function push(uint256 value) public returns (uint256, uint256) {
+        return _totalCheckpoints.push(value);
+    }
+
+    function getAtBlock(uint256 blockNumber) public view returns (uint256) {
+        return _totalCheckpoints.getAtBlock(blockNumber);
+    }
+
+    function getAtProbablyRecentBlock(uint256 blockNumber) public view returns (uint256) {
+        return _totalCheckpoints.getAtProbablyRecentBlock(blockNumber);
+    }
+}
+
+contract Checkpoints224Mock {
+    using Checkpoints for Checkpoints.Trace224;
+
+    Checkpoints.Trace224 private _totalCheckpoints;
+
+    function latest() public view returns (uint224) {
+        return _totalCheckpoints.latest();
+    }
+
+    function latestCheckpoint()
+        public
+        view
+        returns (
+            bool,
+            uint32,
+            uint224
+        )
+    {
+        return _totalCheckpoints.latestCheckpoint();
+    }
+
+    function length() public view returns (uint256) {
+        return _totalCheckpoints.length();
+    }
+
+    function push(uint32 key, uint224 value) public returns (uint224, uint224) {
+        return _totalCheckpoints.push(key, value);
+    }
+
+    function lowerLookup(uint32 key) public view returns (uint224) {
+        return _totalCheckpoints.lowerLookup(key);
+    }
+
+    function upperLookup(uint32 key) public view returns (uint224) {
+        return _totalCheckpoints.upperLookup(key);
+    }
+}
+
+contract Checkpoints160Mock {
+    using Checkpoints for Checkpoints.Trace160;
+
+    Checkpoints.Trace160 private _totalCheckpoints;
+
+    function latest() public view returns (uint160) {
+        return _totalCheckpoints.latest();
+    }
+
+    function latestCheckpoint()
+        public
+        view
+        returns (
+            bool,
+            uint96,
+            uint160
+        )
+    {
+        return _totalCheckpoints.latestCheckpoint();
+    }
+
+    function length() public view returns (uint256) {
+        return _totalCheckpoints.length();
+    }
+
+    function push(uint96 key, uint160 value) public returns (uint160, uint160) {
+        return _totalCheckpoints.push(key, value);
+    }
+
+    function lowerLookup(uint96 key) public view returns (uint160) {
+        return _totalCheckpoints.lowerLookup(key);
+    }
+
+    function upperLookup(uint96 key) public view returns (uint160) {
+        return _totalCheckpoints.upperLookup(key);
+    }
+}

+ 1 - 1
contracts/mocks/ERC1155PausableMock.sol

@@ -23,7 +23,7 @@ contract ERC1155PausableMock is ERC1155Mock, ERC1155Pausable {
         uint256[] memory ids,
         uint256[] memory amounts,
         bytes memory data
-    ) internal virtual override(ERC1155, ERC1155Pausable) {
+    ) internal override(ERC1155, ERC1155Pausable) {
         super._beforeTokenTransfer(operator, from, to, ids, amounts, data);
     }
 }

+ 1 - 1
contracts/mocks/ERC1155SupplyMock.sol

@@ -15,7 +15,7 @@ contract ERC1155SupplyMock is ERC1155Mock, ERC1155Supply {
         uint256[] memory ids,
         uint256[] memory amounts,
         bytes memory data
-    ) internal virtual override(ERC1155, ERC1155Supply) {
+    ) internal override(ERC1155, ERC1155Supply) {
         super._beforeTokenTransfer(operator, from, to, ids, amounts, data);
     }
 }

+ 1 - 1
contracts/mocks/ERC1155URIStorageMock.sol

@@ -8,7 +8,7 @@ import "../token/ERC1155/extensions/ERC1155URIStorage.sol";
 contract ERC1155URIStorageMock is ERC1155Mock, ERC1155URIStorage {
     constructor(string memory _uri) ERC1155Mock(_uri) {}
 
-    function uri(uint256 tokenId) public view virtual override(ERC1155, ERC1155URIStorage) returns (string memory) {
+    function uri(uint256 tokenId) public view override(ERC1155, ERC1155URIStorage) returns (string memory) {
         return ERC1155URIStorage.uri(tokenId);
     }
 

+ 1 - 1
contracts/mocks/ERC165/ERC165ReturnBomb.sol

@@ -5,7 +5,7 @@ pragma solidity ^0.8.0;
 import "../../utils/introspection/IERC165.sol";
 
 contract ERC165ReturnBombMock is IERC165 {
-    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
+    function supportsInterface(bytes4 interfaceId) public pure override returns (bool) {
         if (interfaceId == type(IERC165).interfaceId) {
             assembly {
                 mstore(0, 1)

+ 1 - 1
contracts/mocks/ERC20DecimalsMock.sol

@@ -15,7 +15,7 @@ contract ERC20DecimalsMock is ERC20 {
         _decimals = decimals_;
     }
 
-    function decimals() public view virtual override returns (uint8) {
+    function decimals() public view override returns (uint8) {
         return _decimals;
     }
 

+ 2 - 2
contracts/mocks/ERC2771ContextMock.sol

@@ -12,11 +12,11 @@ contract ERC2771ContextMock is ContextMock, ERC2771Context {
         emit Sender(_msgSender()); // _msgSender() should be accessible during construction
     }
 
-    function _msgSender() internal view virtual override(Context, ERC2771Context) returns (address) {
+    function _msgSender() internal view override(Context, ERC2771Context) returns (address) {
         return ERC2771Context._msgSender();
     }
 
-    function _msgData() internal view virtual override(Context, ERC2771Context) returns (bytes calldata) {
+    function _msgData() internal view override(Context, ERC2771Context) returns (bytes calldata) {
         return ERC2771Context._msgData();
     }
 }

+ 39 - 1
contracts/mocks/ERC4626Mock.sol

@@ -4,7 +4,6 @@ pragma solidity ^0.8.0;
 
 import "../token/ERC20/extensions/ERC4626.sol";
 
-// mock class using ERC20
 contract ERC4626Mock is ERC4626 {
     constructor(
         IERC20Metadata asset,
@@ -20,3 +19,42 @@ contract ERC4626Mock is ERC4626 {
         _burn(account, amount);
     }
 }
+
+contract ERC4626DecimalMock is ERC4626Mock {
+    using Math for uint256;
+
+    uint8 private immutable _decimals;
+
+    constructor(
+        IERC20Metadata asset,
+        string memory name,
+        string memory symbol,
+        uint8 decimalsOverride
+    ) ERC4626Mock(asset, name, symbol) {
+        _decimals = decimalsOverride;
+    }
+
+    function decimals() public view virtual override returns (uint8) {
+        return _decimals;
+    }
+
+    function _initialConvertToShares(uint256 assets, Math.Rounding rounding)
+        internal
+        view
+        virtual
+        override
+        returns (uint256 shares)
+    {
+        return assets.mulDiv(10**decimals(), 10**super.decimals(), rounding);
+    }
+
+    function _initialConvertToAssets(uint256 shares, Math.Rounding rounding)
+        internal
+        view
+        virtual
+        override
+        returns (uint256 assets)
+    {
+        return shares.mulDiv(10**super.decimals(), 10**decimals(), rounding);
+    }
+}

+ 55 - 0
contracts/mocks/ERC721ConsecutiveEnumerableMock.sol

@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: MIT
+
+pragma solidity ^0.8.0;
+
+import "../token/ERC721/extensions/ERC721Consecutive.sol";
+import "../token/ERC721/extensions/ERC721Enumerable.sol";
+
+contract ERC721ConsecutiveEnumerableMock is ERC721Consecutive, ERC721Enumerable {
+    constructor(
+        string memory name,
+        string memory symbol,
+        address[] memory receivers,
+        uint96[] memory amounts
+    ) ERC721(name, symbol) {
+        for (uint256 i = 0; i < receivers.length; ++i) {
+            _mintConsecutive(receivers[i], amounts[i]);
+        }
+    }
+
+    function supportsInterface(bytes4 interfaceId)
+        public
+        view
+        virtual
+        override(ERC721, ERC721Enumerable)
+        returns (bool)
+    {
+        return super.supportsInterface(interfaceId);
+    }
+
+    function _ownerOf(uint256 tokenId) internal view virtual override(ERC721, ERC721Consecutive) returns (address) {
+        return super._ownerOf(tokenId);
+    }
+
+    function _mint(address to, uint256 tokenId) internal virtual override(ERC721, ERC721Consecutive) {
+        super._mint(to, tokenId);
+    }
+
+    function _beforeTokenTransfer(
+        address from,
+        address to,
+        uint256 firstTokenId,
+        uint256 batchSize
+    ) internal virtual override(ERC721, ERC721Enumerable) {
+        super._beforeTokenTransfer(from, to, firstTokenId, batchSize);
+    }
+
+    function _afterTokenTransfer(
+        address from,
+        address to,
+        uint256 firstTokenId,
+        uint256 batchSize
+    ) internal virtual override(ERC721, ERC721Consecutive) {
+        super._afterTokenTransfer(from, to, firstTokenId, batchSize);
+    }
+}

+ 86 - 0
contracts/mocks/ERC721ConsecutiveMock.sol

@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: MIT
+
+pragma solidity ^0.8.0;
+
+import "../token/ERC721/extensions/ERC721Burnable.sol";
+import "../token/ERC721/extensions/ERC721Consecutive.sol";
+import "../token/ERC721/extensions/ERC721Enumerable.sol";
+import "../token/ERC721/extensions/ERC721Pausable.sol";
+import "../token/ERC721/extensions/ERC721Votes.sol";
+
+/**
+ * @title ERC721ConsecutiveMock
+ */
+contract ERC721ConsecutiveMock is ERC721Burnable, ERC721Consecutive, ERC721Pausable, ERC721Votes {
+    constructor(
+        string memory name,
+        string memory symbol,
+        address[] memory delegates,
+        address[] memory receivers,
+        uint96[] memory amounts
+    ) ERC721(name, symbol) EIP712(name, "1") {
+        for (uint256 i = 0; i < delegates.length; ++i) {
+            _delegate(delegates[i], delegates[i]);
+        }
+
+        for (uint256 i = 0; i < receivers.length; ++i) {
+            _mintConsecutive(receivers[i], amounts[i]);
+        }
+    }
+
+    function pause() external {
+        _pause();
+    }
+
+    function unpause() external {
+        _unpause();
+    }
+
+    function exists(uint256 tokenId) public view returns (bool) {
+        return _exists(tokenId);
+    }
+
+    function mint(address to, uint256 tokenId) public {
+        _mint(to, tokenId);
+    }
+
+    function mintConsecutive(address to, uint96 amount) public {
+        _mintConsecutive(to, amount);
+    }
+
+    function safeMint(address to, uint256 tokenId) public {
+        _safeMint(to, tokenId);
+    }
+
+    function _ownerOf(uint256 tokenId) internal view virtual override(ERC721, ERC721Consecutive) returns (address) {
+        return super._ownerOf(tokenId);
+    }
+
+    function _mint(address to, uint256 tokenId) internal virtual override(ERC721, ERC721Consecutive) {
+        super._mint(to, tokenId);
+    }
+
+    function _beforeTokenTransfer(
+        address from,
+        address to,
+        uint256 firstTokenId,
+        uint256 batchSize
+    ) internal virtual override(ERC721, ERC721Pausable) {
+        super._beforeTokenTransfer(from, to, firstTokenId, batchSize);
+    }
+
+    function _afterTokenTransfer(
+        address from,
+        address to,
+        uint256 firstTokenId,
+        uint256 batchSize
+    ) internal virtual override(ERC721, ERC721Votes, ERC721Consecutive) {
+        super._afterTokenTransfer(from, to, firstTokenId, batchSize);
+    }
+}
+
+contract ERC721ConsecutiveNoConstructorMintMock is ERC721Consecutive {
+    constructor(string memory name, string memory symbol) ERC721(name, symbol) {
+        _mint(msg.sender, 0);
+    }
+}

+ 1 - 1
contracts/mocks/ERC721EnumerableMock.sol

@@ -13,7 +13,7 @@ contract ERC721EnumerableMock is ERC721Enumerable {
 
     constructor(string memory name, string memory symbol) ERC721(name, symbol) {}
 
-    function _baseURI() internal view virtual override returns (string memory) {
+    function _baseURI() internal view override returns (string memory) {
         return _baseTokenURI;
     }
 

+ 1 - 1
contracts/mocks/ERC721URIStorageMock.sol

@@ -13,7 +13,7 @@ contract ERC721URIStorageMock is ERC721URIStorage {
 
     constructor(string memory name, string memory symbol) ERC721(name, symbol) {}
 
-    function _baseURI() internal view virtual override returns (string memory) {
+    function _baseURI() internal view override returns (string memory) {
         return _baseTokenURI;
     }
 

+ 1 - 1
contracts/mocks/ERC721VotesMock.sol

@@ -2,7 +2,7 @@
 
 pragma solidity ^0.8.0;
 
-import "../token/ERC721/extensions/draft-ERC721Votes.sol";
+import "../token/ERC721/extensions/ERC721Votes.sol";
 
 contract ERC721VotesMock is ERC721Votes {
     constructor(string memory name, string memory symbol) ERC721(name, symbol) EIP712(name, "1") {}

+ 1 - 0
contracts/mocks/EnumerableMapMock.sol

@@ -1,4 +1,5 @@
 // SPDX-License-Identifier: MIT
+// This file was procedurally generated from scripts/generate/templates/EnumerableMapMock.js.
 
 pragma solidity ^0.8.0;
 

+ 1 - 0
contracts/mocks/EnumerableSetMock.sol

@@ -1,4 +1,5 @@
 // SPDX-License-Identifier: MIT
+// This file was procedurally generated from scripts/generate/templates/EnumerableSetMock.js.
 
 pragma solidity ^0.8.0;
 

+ 6 - 9
contracts/mocks/GovernorCompatibilityBravoMock.sol

@@ -30,7 +30,6 @@ contract GovernorCompatibilityBravoMock is
     function supportsInterface(bytes4 interfaceId)
         public
         view
-        virtual
         override(IERC165, Governor, GovernorTimelockCompound)
         returns (bool)
     {
@@ -44,7 +43,6 @@ contract GovernorCompatibilityBravoMock is
     function state(uint256 proposalId)
         public
         view
-        virtual
         override(IGovernor, Governor, GovernorTimelockCompound)
         returns (ProposalState)
     {
@@ -54,7 +52,6 @@ contract GovernorCompatibilityBravoMock is
     function proposalEta(uint256 proposalId)
         public
         view
-        virtual
         override(IGovernorTimelock, GovernorTimelockCompound)
         returns (uint256)
     {
@@ -70,7 +67,7 @@ contract GovernorCompatibilityBravoMock is
         uint256[] memory values,
         bytes[] memory calldatas,
         string memory description
-    ) public virtual override(IGovernor, Governor, GovernorCompatibilityBravo) returns (uint256) {
+    ) public override(IGovernor, Governor, GovernorCompatibilityBravo) returns (uint256) {
         return super.propose(targets, values, calldatas, description);
     }
 
@@ -79,7 +76,7 @@ contract GovernorCompatibilityBravoMock is
         uint256[] memory values,
         bytes[] memory calldatas,
         bytes32 salt
-    ) public virtual override(IGovernorTimelock, GovernorTimelockCompound) returns (uint256) {
+    ) public override(IGovernorTimelock, GovernorTimelockCompound) returns (uint256) {
         return super.queue(targets, values, calldatas, salt);
     }
 
@@ -88,7 +85,7 @@ contract GovernorCompatibilityBravoMock is
         uint256[] memory values,
         bytes[] memory calldatas,
         bytes32 salt
-    ) public payable virtual override(IGovernor, Governor) returns (uint256) {
+    ) public payable override(IGovernor, Governor) returns (uint256) {
         return super.execute(targets, values, calldatas, salt);
     }
 
@@ -98,7 +95,7 @@ contract GovernorCompatibilityBravoMock is
         uint256[] memory values,
         bytes[] memory calldatas,
         bytes32 descriptionHash
-    ) internal virtual override(Governor, GovernorTimelockCompound) {
+    ) internal override(Governor, GovernorTimelockCompound) {
         super._execute(proposalId, targets, values, calldatas, descriptionHash);
     }
 
@@ -120,11 +117,11 @@ contract GovernorCompatibilityBravoMock is
         uint256[] memory values,
         bytes[] memory calldatas,
         bytes32 salt
-    ) internal virtual override(Governor, GovernorTimelockCompound) returns (uint256 proposalId) {
+    ) internal override(Governor, GovernorTimelockCompound) returns (uint256 proposalId) {
         return super._cancel(targets, values, calldatas, salt);
     }
 
-    function _executor() internal view virtual override(Governor, GovernorTimelockCompound) returns (address) {
+    function _executor() internal view override(Governor, GovernorTimelockCompound) returns (address) {
         return super._executor();
     }
 }

+ 1 - 1
contracts/mocks/GovernorMock.sol

@@ -44,7 +44,7 @@ contract GovernorMock is
         uint256[] memory values,
         bytes[] memory calldatas,
         string memory description
-    ) public virtual override(Governor, GovernorProposalThreshold) returns (uint256) {
+    ) public override(Governor, GovernorProposalThreshold) returns (uint256) {
         return super.propose(targets, values, calldatas, description);
     }
 }

+ 3 - 4
contracts/mocks/GovernorPreventLateQuorumMock.sol

@@ -31,21 +31,20 @@ contract GovernorPreventLateQuorumMock is
         _quorum = quorum_;
     }
 
-    function quorum(uint256) public view virtual override returns (uint256) {
+    function quorum(uint256) public view override returns (uint256) {
         return _quorum;
     }
 
     function proposalDeadline(uint256 proposalId)
         public
         view
-        virtual
         override(Governor, GovernorPreventLateQuorum)
         returns (uint256)
     {
         return super.proposalDeadline(proposalId);
     }
 
-    function proposalThreshold() public view virtual override(Governor, GovernorSettings) returns (uint256) {
+    function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) {
         return super.proposalThreshold();
     }
 
@@ -55,7 +54,7 @@ contract GovernorPreventLateQuorumMock is
         uint8 support,
         string memory reason,
         bytes memory params
-    ) internal virtual override(Governor, GovernorPreventLateQuorum) returns (uint256) {
+    ) internal override(Governor, GovernorPreventLateQuorum) returns (uint256) {
         return super._castVote(proposalId, account, support, reason, params);
     }
 }

+ 3 - 5
contracts/mocks/GovernorTimelockCompoundMock.sol

@@ -31,7 +31,6 @@ contract GovernorTimelockCompoundMock is
     function supportsInterface(bytes4 interfaceId)
         public
         view
-        virtual
         override(Governor, GovernorTimelockCompound)
         returns (bool)
     {
@@ -62,7 +61,6 @@ contract GovernorTimelockCompoundMock is
     function state(uint256 proposalId)
         public
         view
-        virtual
         override(Governor, GovernorTimelockCompound)
         returns (ProposalState)
     {
@@ -79,7 +77,7 @@ contract GovernorTimelockCompoundMock is
         uint256[] memory values,
         bytes[] memory calldatas,
         bytes32 descriptionHash
-    ) internal virtual override(Governor, GovernorTimelockCompound) {
+    ) internal override(Governor, GovernorTimelockCompound) {
         super._execute(proposalId, targets, values, calldatas, descriptionHash);
     }
 
@@ -88,11 +86,11 @@ contract GovernorTimelockCompoundMock is
         uint256[] memory values,
         bytes[] memory calldatas,
         bytes32 salt
-    ) internal virtual override(Governor, GovernorTimelockCompound) returns (uint256 proposalId) {
+    ) internal override(Governor, GovernorTimelockCompound) returns (uint256 proposalId) {
         return super._cancel(targets, values, calldatas, salt);
     }
 
-    function _executor() internal view virtual override(Governor, GovernorTimelockCompound) returns (address) {
+    function _executor() internal view override(Governor, GovernorTimelockCompound) returns (address) {
         return super._executor();
     }
 }

+ 4 - 11
contracts/mocks/GovernorTimelockControlMock.sol

@@ -31,7 +31,6 @@ contract GovernorTimelockControlMock is
     function supportsInterface(bytes4 interfaceId)
         public
         view
-        virtual
         override(Governor, GovernorTimelockControl)
         returns (bool)
     {
@@ -59,13 +58,7 @@ contract GovernorTimelockControlMock is
     /**
      * Overriding nightmare
      */
-    function state(uint256 proposalId)
-        public
-        view
-        virtual
-        override(Governor, GovernorTimelockControl)
-        returns (ProposalState)
-    {
+    function state(uint256 proposalId) public view override(Governor, GovernorTimelockControl) returns (ProposalState) {
         return super.state(proposalId);
     }
 
@@ -79,7 +72,7 @@ contract GovernorTimelockControlMock is
         uint256[] memory values,
         bytes[] memory calldatas,
         bytes32 descriptionHash
-    ) internal virtual override(Governor, GovernorTimelockControl) {
+    ) internal override(Governor, GovernorTimelockControl) {
         super._execute(proposalId, targets, values, calldatas, descriptionHash);
     }
 
@@ -88,11 +81,11 @@ contract GovernorTimelockControlMock is
         uint256[] memory values,
         bytes[] memory calldatas,
         bytes32 descriptionHash
-    ) internal virtual override(Governor, GovernorTimelockControl) returns (uint256 proposalId) {
+    ) internal override(Governor, GovernorTimelockControl) returns (uint256 proposalId) {
         return super._cancel(targets, values, calldatas, descriptionHash);
     }
 
-    function _executor() internal view virtual override(Governor, GovernorTimelockControl) returns (address) {
+    function _executor() internal view override(Governor, GovernorTimelockControl) returns (address) {
         return super._executor();
     }
 

+ 2 - 2
contracts/mocks/GovernorWithParamsMock.sol

@@ -26,7 +26,7 @@ contract GovernorWithParamsMock is GovernorVotes, GovernorCountingSimple {
         address account,
         uint256 blockNumber,
         bytes memory params
-    ) internal view virtual override(Governor, GovernorVotes) returns (uint256) {
+    ) internal view override(Governor, GovernorVotes) returns (uint256) {
         uint256 reduction = 0;
         // If the user provides parameters, we reduce the voting weight by the amount of the integer param
         if (params.length > 0) {
@@ -42,7 +42,7 @@ contract GovernorWithParamsMock is GovernorVotes, GovernorCountingSimple {
         uint8 support,
         uint256 weight,
         bytes memory params
-    ) internal virtual override(Governor, GovernorCountingSimple) {
+    ) internal override(Governor, GovernorCountingSimple) {
         if (params.length > 0) {
             (uint256 _uintParam, string memory _strParam) = abi.decode(params, (uint256, string));
             emit CountParams(_uintParam, _strParam);

+ 12 - 0
contracts/mocks/MathMock.sol

@@ -33,4 +33,16 @@ contract MathMock {
     function sqrt(uint256 a, Math.Rounding direction) public pure returns (uint256) {
         return Math.sqrt(a, direction);
     }
+
+    function log2(uint256 a, Math.Rounding direction) public pure returns (uint256) {
+        return Math.log2(a, direction);
+    }
+
+    function log10(uint256 a, Math.Rounding direction) public pure returns (uint256) {
+        return Math.log10(a, direction);
+    }
+
+    function log256(uint256 a, Math.Rounding direction) public pure returns (uint256) {
+        return Math.log256(a, direction);
+    }
 }

+ 1 - 1
contracts/mocks/MulticallTest.sol

@@ -5,7 +5,7 @@ pragma solidity ^0.8.0;
 import "./MulticallTokenMock.sol";
 
 contract MulticallTest {
-    function testReturnValues(
+    function checkReturnValues(
         MulticallTokenMock multicallToken,
         address[] calldata recipients,
         uint256[] calldata amounts

+ 2 - 2
contracts/mocks/MultipleInheritanceInitializableMocks.sol

@@ -42,7 +42,7 @@ contract SampleHuman is Initializable {
 contract SampleMother is Initializable, SampleHuman {
     uint256 public mother;
 
-    function initialize(uint256 value) public virtual initializer {
+    function initialize(uint256 value) public initializer {
         __SampleMother_init(value);
     }
 
@@ -64,7 +64,7 @@ contract SampleMother is Initializable, SampleHuman {
 contract SampleGramps is Initializable, SampleHuman {
     string public gramps;
 
-    function initialize(string memory value) public virtual initializer {
+    function initialize(string memory value) public initializer {
         __SampleGramps_init(value);
     }
 

+ 7 - 0
contracts/mocks/Ownable2StepMock.sol

@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: MIT
+
+pragma solidity ^0.8.0;
+
+import "../access/Ownable2Step.sol";
+
+contract Ownable2StepMock is Ownable2Step {}

+ 8 - 0
contracts/mocks/ReentrancyMock.sol

@@ -40,4 +40,12 @@ contract ReentrancyMock is ReentrancyGuard {
     function _count() private {
         counter += 1;
     }
+
+    function guardedCheckEntered() public nonReentrant {
+        require(_reentrancyGuardEntered());
+    }
+
+    function unguardedCheckNotEntered() public view {
+        require(!_reentrancyGuardEntered());
+    }
 }

+ 1 - 0
contracts/mocks/SafeCastMock.sol

@@ -1,4 +1,5 @@
 // SPDX-License-Identifier: MIT
+// This file was procedurally generated from scripts/generate/templates/SafeCastMock.js.
 
 pragma solidity ^0.8.0;
 

+ 2 - 2
contracts/mocks/SafeERC20Helper.sol

@@ -122,7 +122,7 @@ contract ERC20PermitNoRevertMock is
         uint8 v,
         bytes32 r,
         bytes32 s
-    ) public virtual {
+    ) public {
         super.permit(owner, spender, value, deadline, v, r, s);
     }
 
@@ -134,7 +134,7 @@ contract ERC20PermitNoRevertMock is
         uint8 v,
         bytes32 r,
         bytes32 s
-    ) public virtual override {
+    ) public override {
         try this.permitThatMayRevert(owner, spender, value, deadline, v, r, s) {
             // do nothing
         } catch {

+ 4 - 4
contracts/mocks/StringsMock.sol

@@ -5,19 +5,19 @@ pragma solidity ^0.8.0;
 import "../utils/Strings.sol";
 
 contract StringsMock {
-    function fromUint256(uint256 value) public pure returns (string memory) {
+    function toString(uint256 value) public pure returns (string memory) {
         return Strings.toString(value);
     }
 
-    function fromUint256Hex(uint256 value) public pure returns (string memory) {
+    function toHexString(uint256 value) public pure returns (string memory) {
         return Strings.toHexString(value);
     }
 
-    function fromUint256HexFixed(uint256 value, uint256 length) public pure returns (string memory) {
+    function toHexString(uint256 value, uint256 length) public pure returns (string memory) {
         return Strings.toHexString(value, length);
     }
 
-    function fromAddressHexFixed(address addr) public pure returns (string memory) {
+    function toHexString(address addr) public pure returns (string memory) {
         return Strings.toHexString(addr);
     }
 }

+ 2 - 2
contracts/mocks/UUPS/UUPSLegacy.sol

@@ -48,11 +48,11 @@ contract UUPSUpgradeableLegacyMock is UUPSUpgradeableMock {
     }
 
     // hooking into the old mechanism
-    function upgradeTo(address newImplementation) external virtual override {
+    function upgradeTo(address newImplementation) external override {
         _upgradeToAndCallSecureLegacyV1(newImplementation, bytes(""), false);
     }
 
-    function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual override {
+    function upgradeToAndCall(address newImplementation, bytes memory data) external payable override {
         _upgradeToAndCallSecureLegacyV1(newImplementation, data, false);
     }
 }

+ 3 - 3
contracts/mocks/UUPS/UUPSUpgradeableMock.sol

@@ -7,15 +7,15 @@ import "../../proxy/utils/UUPSUpgradeable.sol";
 
 contract UUPSUpgradeableMock is CountersImpl, UUPSUpgradeable {
     // Not having any checks in this function is dangerous! Do not do this outside tests!
-    function _authorizeUpgrade(address) internal virtual override {}
+    function _authorizeUpgrade(address) internal override {}
 }
 
 contract UUPSUpgradeableUnsafeMock is UUPSUpgradeableMock {
-    function upgradeTo(address newImplementation) external virtual override {
+    function upgradeTo(address newImplementation) external override {
         ERC1967Upgrade._upgradeToAndCall(newImplementation, bytes(""), false);
     }
 
-    function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual override {
+    function upgradeToAndCall(address newImplementation, bytes memory data) external payable override {
         ERC1967Upgrade._upgradeToAndCall(newImplementation, data, false);
     }
 }

+ 1 - 1
contracts/mocks/VotesMock.sol

@@ -18,7 +18,7 @@ contract VotesMock is Votes {
         return _delegate(account, newDelegation);
     }
 
-    function _getVotingUnits(address account) internal view virtual override returns (uint256) {
+    function _getVotingUnits(address account) internal view override returns (uint256) {
         return _balances[account];
     }
 

+ 19 - 17
contracts/proxy/Clones.sol

@@ -25,11 +25,12 @@ library Clones {
     function clone(address implementation) internal returns (address instance) {
         /// @solidity memory-safe-assembly
         assembly {
-            let ptr := mload(0x40)
-            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
-            mstore(add(ptr, 0x14), shl(0x60, implementation))
-            mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
-            instance := create(0, ptr, 0x37)
+            // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
+            // of the `implementation` address with the bytecode before the address.
+            mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
+            // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
+            mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
+            instance := create(0, 0x09, 0x37)
         }
         require(instance != address(0), "ERC1167: create failed");
     }
@@ -44,11 +45,12 @@ library Clones {
     function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
         /// @solidity memory-safe-assembly
         assembly {
-            let ptr := mload(0x40)
-            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
-            mstore(add(ptr, 0x14), shl(0x60, implementation))
-            mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
-            instance := create2(0, ptr, 0x37, salt)
+            // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
+            // of the `implementation` address with the bytecode before the address.
+            mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
+            // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
+            mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
+            instance := create2(0, 0x09, 0x37, salt)
         }
         require(instance != address(0), "ERC1167: create2 failed");
     }
@@ -64,13 +66,13 @@ library Clones {
         /// @solidity memory-safe-assembly
         assembly {
             let ptr := mload(0x40)
-            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
-            mstore(add(ptr, 0x14), shl(0x60, implementation))
-            mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000)
-            mstore(add(ptr, 0x38), shl(0x60, deployer))
-            mstore(add(ptr, 0x4c), salt)
-            mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))
-            predicted := keccak256(add(ptr, 0x37), 0x55)
+            mstore(add(ptr, 0x38), deployer)
+            mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)
+            mstore(add(ptr, 0x14), implementation)
+            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)
+            mstore(add(ptr, 0x58), salt)
+            mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))
+            predicted := keccak256(add(ptr, 0x43), 0x55)
         }
     }
 

+ 1 - 1
contracts/proxy/README.adoc

@@ -26,7 +26,7 @@ A different family of proxies are beacon proxies. This pattern, popularized by D
 - {BeaconProxy}: A proxy that retrieves its implementation from a beacon contract.
 - {UpgradeableBeacon}: A beacon contract with a built in admin that can upgrade the {BeaconProxy} pointing to it.
 
-In this pattern, the proxy contract doesn't hold the implementation address in storage like an ERC1967 proxy, instead the address is stored in a separate beacon contract. The `upgrade` operations that are sent to the beacon instead of to the proxy contract, and all proxies that follow that beacon are automatically upgraded.
+In this pattern, the proxy contract doesn't hold the implementation address in storage like an ERC1967 proxy. Instead, the address is stored in a separate beacon contract. The `upgrade` operations are sent to the beacon instead of to the proxy contract, and all proxies that follow that beacon are automatically upgraded.
 
 Outside the realm of upgradeability, proxies can also be useful to make cheap contract clones, such as those created by an on-chain factory contract that creates many instances of the same contract. These instances are designed to be both cheap to deploy, and cheap to call.
 

+ 17 - 4
contracts/proxy/utils/Initializable.sol

@@ -73,7 +73,12 @@ abstract contract Initializable {
 
     /**
      * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
-     * `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.
+     * `onlyInitializing` functions can be used to initialize parent contracts.
+     *
+     * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
+     * constructor.
+     *
+     * Emits an {Initialized} event.
      */
     modifier initializer() {
         bool isTopLevelCall = !_initializing;
@@ -97,12 +102,18 @@ abstract contract Initializable {
      * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
      * used to initialize parent contracts.
      *
-     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original
-     * initialization step. This is essential to configure modules that are added through upgrades and that require
-     * initialization.
+     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
+     * are added through upgrades and that require initialization.
+     *
+     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
+     * cannot be nested. If one is invoked in the context of another, execution will revert.
      *
      * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
      * a contract, executing them in the right order is up to the developer or operator.
+     *
+     * WARNING: setting the version to 255 will prevent any future reinitialization.
+     *
+     * Emits an {Initialized} event.
      */
     modifier reinitializer(uint8 version) {
         require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
@@ -127,6 +138,8 @@ abstract contract Initializable {
      * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
      * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
      * through proxies.
+     *
+     * Emits an {Initialized} event the first time it is successfully executed.
      */
     function _disableInitializers() internal virtual {
         require(!_initializing, "Initializable: contract is initializing");

+ 9 - 1
contracts/security/ReentrancyGuard.sol

@@ -54,7 +54,7 @@ abstract contract ReentrancyGuard {
     }
 
     function _nonReentrantBefore() private {
-        // On the first call to nonReentrant, _notEntered will be true
+        // On the first call to nonReentrant, _status will be _NOT_ENTERED
         require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
 
         // Any calls to nonReentrant after this point will fail
@@ -66,4 +66,12 @@ abstract contract ReentrancyGuard {
         // https://eips.ethereum.org/EIPS/eip-2200)
         _status = _NOT_ENTERED;
     }
+
+    /**
+     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
+     * `nonReentrant` function in the call stack.
+     */
+    function _reentrancyGuardEntered() internal view returns (bool) {
+        return _status == _ENTERED;
+    }
 }

+ 7 - 5
contracts/token/ERC20/extensions/ERC20FlashMint.sol

@@ -29,9 +29,9 @@ abstract contract ERC20FlashMint is ERC20, IERC3156FlashLender {
     }
 
     /**
-     * @dev Returns the fee applied when doing flash loans. By default this
-     * implementation has 0 fees. This function can be overloaded to make
-     * the flash loan mechanism deflationary.
+     * @dev Returns the fee applied when doing flash loans. This function calls
+     * the {_flashFee} function which returns the fee applied when doing flash
+     * loans.
      * @param token The token to be flash loaned.
      * @param amount The amount of tokens to be loaned.
      * @return The fees applied to the corresponding flash loan.
@@ -42,7 +42,9 @@ abstract contract ERC20FlashMint is ERC20, IERC3156FlashLender {
     }
 
     /**
-     * @dev Returns the fee applied when doing flash loans. This function calls the {flashFee} function which returns the fee applied when doing flash loans.
+     * @dev Returns the fee applied when doing flash loans. By default this
+     * implementation has 0 fees. This function can be overloaded to make
+     * the flash loan mechanism deflationary.
      * @param token The token to be flash loaned.
      * @param amount The amount of tokens to be loaned.
      * @return The fees applied to the corresponding flash loan.
@@ -71,7 +73,7 @@ abstract contract ERC20FlashMint is ERC20, IERC3156FlashLender {
      * amount + fee tokens and have them approved back to the token contract itself so
      * they can be burned.
      * @param receiver The receiver of the flash loan. Should implement the
-     * {IERC3156FlashBorrower.onFlashLoan} interface.
+     * {IERC3156FlashBorrower-onFlashLoan} interface.
      * @param token The token to be flash loaned. Only `address(this)` is
      * supported.
      * @param amount The amount of tokens to be loaned.

+ 44 - 13
contracts/token/ERC20/extensions/ERC20Votes.sol

@@ -63,7 +63,9 @@ abstract contract ERC20Votes is IVotes, ERC20Permit {
      */
     function getVotes(address account) public view virtual override returns (uint256) {
         uint256 pos = _checkpoints[account].length;
-        return pos == 0 ? 0 : _checkpoints[account][pos - 1].votes;
+        unchecked {
+            return pos == 0 ? 0 : _checkpoints[account][pos - 1].votes;
+        }
     }
 
     /**
@@ -80,7 +82,7 @@ abstract contract ERC20Votes is IVotes, ERC20Permit {
 
     /**
      * @dev Retrieve the `totalSupply` at the end of `blockNumber`. Note, this value is the sum of all balances.
-     * It is but NOT the sum of all the delegated votes!
+     * It is NOT the sum of all the delegated votes!
      *
      * Requirements:
      *
@@ -97,6 +99,7 @@ abstract contract ERC20Votes is IVotes, ERC20Permit {
     function _checkpointsLookup(Checkpoint[] storage ckpts, uint256 blockNumber) private view returns (uint256) {
         // We run a binary search to look for the earliest checkpoint taken after `blockNumber`.
         //
+        // Initially we check if the block is recent to narrow the search range.
         // During the loop, the index of the wanted checkpoint remains in the range [low-1, high).
         // With each iteration, either `low` or `high` is moved towards the middle of the range to maintain the invariant.
         // - If the middle checkpoint is after `blockNumber`, we look in [low, mid)
@@ -106,18 +109,32 @@ abstract contract ERC20Votes is IVotes, ERC20Permit {
         // Note that if the latest checkpoint available is exactly for `blockNumber`, we end up with an index that is
         // past the end of the array, so we technically don't find a checkpoint after `blockNumber`, but it works out
         // the same.
-        uint256 high = ckpts.length;
+        uint256 length = ckpts.length;
+
         uint256 low = 0;
+        uint256 high = length;
+
+        if (length > 5) {
+            uint256 mid = length - Math.sqrt(length);
+            if (_unsafeAccess(ckpts, mid).fromBlock > blockNumber) {
+                high = mid;
+            } else {
+                low = mid + 1;
+            }
+        }
+
         while (low < high) {
             uint256 mid = Math.average(low, high);
-            if (ckpts[mid].fromBlock > blockNumber) {
+            if (_unsafeAccess(ckpts, mid).fromBlock > blockNumber) {
                 high = mid;
             } else {
                 low = mid + 1;
             }
         }
 
-        return high == 0 ? 0 : ckpts[high - 1].votes;
+        unchecked {
+            return high == 0 ? 0 : _unsafeAccess(ckpts, high - 1).votes;
+        }
     }
 
     /**
@@ -178,7 +195,7 @@ abstract contract ERC20Votes is IVotes, ERC20Permit {
     /**
      * @dev Move voting power when tokens are transferred.
      *
-     * Emits a {DelegateVotesChanged} event.
+     * Emits a {IVotes-DelegateVotesChanged} event.
      */
     function _afterTokenTransfer(
         address from,
@@ -193,7 +210,7 @@ abstract contract ERC20Votes is IVotes, ERC20Permit {
     /**
      * @dev Change delegation for `delegator` to `delegatee`.
      *
-     * Emits events {DelegateChanged} and {DelegateVotesChanged}.
+     * Emits events {IVotes-DelegateChanged} and {IVotes-DelegateVotesChanged}.
      */
     function _delegate(address delegator, address delegatee) internal virtual {
         address currentDelegate = delegates(delegator);
@@ -229,13 +246,20 @@ abstract contract ERC20Votes is IVotes, ERC20Permit {
         uint256 delta
     ) private returns (uint256 oldWeight, uint256 newWeight) {
         uint256 pos = ckpts.length;
-        oldWeight = pos == 0 ? 0 : ckpts[pos - 1].votes;
-        newWeight = op(oldWeight, delta);
 
-        if (pos > 0 && ckpts[pos - 1].fromBlock == block.number) {
-            ckpts[pos - 1].votes = SafeCast.toUint224(newWeight);
-        } else {
-            ckpts.push(Checkpoint({fromBlock: SafeCast.toUint32(block.number), votes: SafeCast.toUint224(newWeight)}));
+        unchecked {
+            Checkpoint memory oldCkpt = pos == 0 ? Checkpoint(0, 0) : _unsafeAccess(ckpts, pos - 1);
+
+            oldWeight = oldCkpt.votes;
+            newWeight = op(oldWeight, delta);
+
+            if (pos > 0 && oldCkpt.fromBlock == block.number) {
+                _unsafeAccess(ckpts, pos - 1).votes = SafeCast.toUint224(newWeight);
+            } else {
+                ckpts.push(
+                    Checkpoint({fromBlock: SafeCast.toUint32(block.number), votes: SafeCast.toUint224(newWeight)})
+                );
+            }
         }
     }
 
@@ -246,4 +270,11 @@ abstract contract ERC20Votes is IVotes, ERC20Permit {
     function _subtract(uint256 a, uint256 b) private pure returns (uint256) {
         return a - b;
     }
+
+    function _unsafeAccess(Checkpoint[] storage ckpts, uint256 pos) private pure returns (Checkpoint storage result) {
+        assembly {
+            mstore(0, ckpts.slot)
+            result.slot := add(keccak256(0, 0x20), pos)
+        }
+    }
 }

+ 60 - 9
contracts/token/ERC20/extensions/ERC4626.sol

@@ -26,15 +26,44 @@ import "../../../utils/math/Math.sol";
 abstract contract ERC4626 is ERC20, IERC4626 {
     using Math for uint256;
 
-    IERC20Metadata private immutable _asset;
+    IERC20 private immutable _asset;
+    uint8 private immutable _decimals;
 
     /**
      * @dev Set the underlying asset contract. This must be an ERC20-compatible contract (ERC20 or ERC777).
      */
-    constructor(IERC20Metadata asset_) {
+    constructor(IERC20 asset_) {
+        (bool success, uint8 assetDecimals) = _tryGetAssetDecimals(asset_);
+        _decimals = success ? assetDecimals : super.decimals();
         _asset = asset_;
     }
 
+    /**
+     * @dev Attempts to fetch the asset decimals. A return value of false indicates that the attempt failed in some way.
+     */
+    function _tryGetAssetDecimals(IERC20 asset_) private returns (bool, uint8) {
+        (bool success, bytes memory encodedDecimals) = address(asset_).call(
+            abi.encodeWithSelector(IERC20Metadata.decimals.selector)
+        );
+        if (success && encodedDecimals.length >= 32) {
+            uint256 returnedDecimals = abi.decode(encodedDecimals, (uint256));
+            if (returnedDecimals <= type(uint8).max) {
+                return (true, uint8(returnedDecimals));
+            }
+        }
+        return (false, 0);
+    }
+
+    /**
+     * @dev Decimals are read from the underlying asset in the constructor and cached. If this fails (e.g., the asset
+     * has not been created yet), the cached value is set to a default obtained by `super.decimals()` (which depends on
+     * inheritance but is most likely 18). Override this function in order to set a guaranteed hardcoded value.
+     * See {IERC20Metadata-decimals}.
+     */
+    function decimals() public view virtual override(IERC20Metadata, ERC20) returns (uint8) {
+        return _decimals;
+    }
+
     /** @dev See {IERC4626-asset}. */
     function asset() public view virtual override returns (address) {
         return address(_asset);
@@ -147,25 +176,47 @@ abstract contract ERC4626 is ERC20, IERC4626 {
      * @dev Internal conversion function (from assets to shares) with support for rounding direction.
      *
      * Will revert if assets > 0, totalSupply > 0 and totalAssets = 0. That corresponds to a case where any asset
-     * would represent an infinite amout of shares.
+     * would represent an infinite amount of shares.
      */
     function _convertToShares(uint256 assets, Math.Rounding rounding) internal view virtual returns (uint256 shares) {
         uint256 supply = totalSupply();
         return
             (assets == 0 || supply == 0)
-                ? assets.mulDiv(10**decimals(), 10**_asset.decimals(), rounding)
+                ? _initialConvertToShares(assets, rounding)
                 : assets.mulDiv(supply, totalAssets(), rounding);
     }
 
+    /**
+     * @dev Internal conversion function (from assets to shares) to apply when the vault is empty.
+     *
+     * NOTE: Make sure to keep this function consistent with {_initialConvertToAssets} when overriding it.
+     */
+    function _initialConvertToShares(
+        uint256 assets,
+        Math.Rounding /*rounding*/
+    ) internal view virtual returns (uint256 shares) {
+        return assets;
+    }
+
     /**
      * @dev Internal conversion function (from shares to assets) with support for rounding direction.
      */
     function _convertToAssets(uint256 shares, Math.Rounding rounding) internal view virtual returns (uint256 assets) {
         uint256 supply = totalSupply();
         return
-            (supply == 0)
-                ? shares.mulDiv(10**_asset.decimals(), 10**decimals(), rounding)
-                : shares.mulDiv(totalAssets(), supply, rounding);
+            (supply == 0) ? _initialConvertToAssets(shares, rounding) : shares.mulDiv(totalAssets(), supply, rounding);
+    }
+
+    /**
+     * @dev Internal conversion function (from shares to assets) to apply when the vault is empty.
+     *
+     * NOTE: Make sure to keep this function consistent with {_initialConvertToShares} when overriding it.
+     */
+    function _initialConvertToAssets(
+        uint256 shares,
+        Math.Rounding /*rounding*/
+    ) internal view virtual returns (uint256 assets) {
+        return shares;
     }
 
     /**
@@ -182,7 +233,7 @@ abstract contract ERC4626 is ERC20, IERC4626 {
         // calls the vault, which is assumed not malicious.
         //
         // Conclusion: we need to do the transfer before we mint so that any reentrancy would happen before the
-        // assets are transfered and before the shares are minted, which is a valid state.
+        // assets are transferred and before the shares are minted, which is a valid state.
         // slither-disable-next-line reentrancy-no-eth
         SafeERC20.safeTransferFrom(_asset, caller, address(this), assets);
         _mint(receiver, shares);
@@ -209,7 +260,7 @@ abstract contract ERC4626 is ERC20, IERC4626 {
         // calls the vault, which is assumed not malicious.
         //
         // Conclusion: we need to do the transfer after the burn so that any reentrancy would happen after the
-        // shares are burned and after the assets are transfered, which is a valid state.
+        // shares are burned and after the assets are transferred, which is a valid state.
         _burn(owner, shares);
         SafeERC20.safeTransfer(_asset, receiver, assets);
 

+ 1 - 1
contracts/token/ERC20/utils/SafeERC20.sol

@@ -104,7 +104,7 @@ library SafeERC20 {
      */
     function _callOptionalReturn(IERC20 token, bytes memory data) private {
         // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
-        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
+        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
         // the target address contains contract code and also asserts for success in the low-level call.
 
         bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");

+ 65 - 26
contracts/token/ERC721/ERC721.sol

@@ -68,7 +68,7 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
      * @dev See {IERC721-ownerOf}.
      */
     function ownerOf(uint256 tokenId) public view virtual override returns (address) {
-        address owner = _owners[tokenId];
+        address owner = _ownerOf(tokenId);
         require(owner != address(0), "ERC721: invalid token ID");
         return owner;
     }
@@ -210,6 +210,13 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
         require(_checkOnERC721Received(from, to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer");
     }
 
+    /**
+     * @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist
+     */
+    function _ownerOf(uint256 tokenId) internal view virtual returns (address) {
+        return _owners[tokenId];
+    }
+
     /**
      * @dev Returns whether `tokenId` exists.
      *
@@ -219,7 +226,7 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
      * and stop existing when they are burned (`_burn`).
      */
     function _exists(uint256 tokenId) internal view virtual returns (bool) {
-        return _owners[tokenId] != address(0);
+        return _ownerOf(tokenId) != address(0);
     }
 
     /**
@@ -280,17 +287,24 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
         require(to != address(0), "ERC721: mint to the zero address");
         require(!_exists(tokenId), "ERC721: token already minted");
 
-        _beforeTokenTransfer(address(0), to, tokenId);
+        _beforeTokenTransfer(address(0), to, tokenId, 1);
 
         // Check that tokenId was not minted by `_beforeTokenTransfer` hook
         require(!_exists(tokenId), "ERC721: token already minted");
 
-        _balances[to] += 1;
+        unchecked {
+            // Will not overflow unless all 2**256 token ids are minted to the same owner.
+            // Given that tokens are minted one by one, it is impossible in practice that
+            // this ever happens. Might change if we allow batch minting.
+            // The ERC fails to describe this case.
+            _balances[to] += 1;
+        }
+
         _owners[tokenId] = to;
 
         emit Transfer(address(0), to, tokenId);
 
-        _afterTokenTransfer(address(0), to, tokenId);
+        _afterTokenTransfer(address(0), to, tokenId, 1);
     }
 
     /**
@@ -307,20 +321,24 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
     function _burn(uint256 tokenId) internal virtual {
         address owner = ERC721.ownerOf(tokenId);
 
-        _beforeTokenTransfer(owner, address(0), tokenId);
+        _beforeTokenTransfer(owner, address(0), tokenId, 1);
 
-        // Update ownership in case tokenId was transfered by `_beforeTokenTransfer` hook
+        // Update ownership in case tokenId was transferred by `_beforeTokenTransfer` hook
         owner = ERC721.ownerOf(tokenId);
 
         // Clear approvals
         delete _tokenApprovals[tokenId];
 
-        _balances[owner] -= 1;
+        unchecked {
+            // Cannot overflow, as that would require more tokens to be burned/transferred
+            // out than the owner initially received through minting and transferring in.
+            _balances[owner] -= 1;
+        }
         delete _owners[tokenId];
 
         emit Transfer(owner, address(0), tokenId);
 
-        _afterTokenTransfer(owner, address(0), tokenId);
+        _afterTokenTransfer(owner, address(0), tokenId, 1);
     }
 
     /**
@@ -342,21 +360,28 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
         require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner");
         require(to != address(0), "ERC721: transfer to the zero address");
 
-        _beforeTokenTransfer(from, to, tokenId);
+        _beforeTokenTransfer(from, to, tokenId, 1);
 
-        // Check that tokenId was not transfered by `_beforeTokenTransfer` hook
+        // Check that tokenId was not transferred by `_beforeTokenTransfer` hook
         require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner");
 
         // Clear approvals from the previous owner
         delete _tokenApprovals[tokenId];
 
-        _balances[from] -= 1;
-        _balances[to] += 1;
+        unchecked {
+            // `_balances[from]` cannot overflow for the same reason as described in `_burn`:
+            // `from`'s balance is the number of token held, which is at least one before the current
+            // transfer.
+            // `_balances[to]` could overflow in the conditions described in `_mint`. That would require
+            // all 2**256 token ids to be minted, which in practice is impossible.
+            _balances[from] -= 1;
+            _balances[to] += 1;
+        }
         _owners[tokenId] = to;
 
         emit Transfer(from, to, tokenId);
 
-        _afterTokenTransfer(from, to, tokenId);
+        _afterTokenTransfer(from, to, tokenId, 1);
     }
 
     /**
@@ -426,39 +451,53 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
     }
 
     /**
-     * @dev Hook that is called before any token transfer. This includes minting
-     * and burning.
+     * @dev Hook that is called before any token transfer. This includes minting and burning. If {ERC721Consecutive} is
+     * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1.
      *
      * Calling conditions:
      *
-     * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be
-     * transferred to `to`.
-     * - When `from` is zero, `tokenId` will be minted for `to`.
-     * - When `to` is zero, ``from``'s `tokenId` will be burned.
+     * - When `from` and `to` are both non-zero, ``from``'s tokens will be transferred to `to`.
+     * - When `from` is zero, the tokens will be minted for `to`.
+     * - When `to` is zero, ``from``'s tokens will be burned.
      * - `from` and `to` are never both zero.
+     * - `batchSize` is non-zero.
      *
      * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
      */
     function _beforeTokenTransfer(
         address from,
         address to,
-        uint256 tokenId
-    ) internal virtual {}
+        uint256, /* firstTokenId */
+        uint256 batchSize
+    ) internal virtual {
+        if (batchSize > 1) {
+            if (from != address(0)) {
+                _balances[from] -= batchSize;
+            }
+            if (to != address(0)) {
+                _balances[to] += batchSize;
+            }
+        }
+    }
 
     /**
-     * @dev Hook that is called after any transfer of tokens. This includes
-     * minting and burning.
+     * @dev Hook that is called after any token transfer. This includes minting and burning. If {ERC721Consecutive} is
+     * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1.
      *
      * Calling conditions:
      *
-     * - when `from` and `to` are both non-zero.
+     * - When `from` and `to` are both non-zero, ``from``'s tokens were transferred to `to`.
+     * - When `from` is zero, the tokens were minted for `to`.
+     * - When `to` is zero, ``from``'s tokens were burned.
      * - `from` and `to` are never both zero.
+     * - `batchSize` is non-zero.
      *
      * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
      */
     function _afterTokenTransfer(
         address from,
         address to,
-        uint256 tokenId
+        uint256 firstTokenId,
+        uint256 batchSize
     ) internal virtual {}
 }

+ 3 - 1
contracts/token/ERC721/IERC721.sol

@@ -81,7 +81,9 @@ interface IERC721 is IERC165 {
     /**
      * @dev Transfers `tokenId` token from `from` to `to`.
      *
-     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
+     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
+     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
+     * understand this adds an external call which potentially creates a reentrancy vulnerability.
      *
      * Requirements:
      *

+ 3 - 0
contracts/token/ERC721/README.adoc

@@ -22,6 +22,7 @@ OpenZeppelin Contracts provides implementations of all four interfaces:
 
 Additionally there are a few of other extensions:
 
+* {ERC721Consecutive}: An implementation of https://eips.ethereum.org/EIPS/eip-2309[ERC2309] for minting batchs of tokens during construction, in accordance with ERC721.
 * {ERC721URIStorage}: A more flexible but more expensive way of storing metadata.
 * {ERC721Votes}: Support for voting and vote delegation.
 * {ERC721Royalty}: A way to signal royalty information following ERC2981.
@@ -50,6 +51,8 @@ NOTE: This core set of contracts is designed to be unopinionated, allowing devel
 
 {{ERC721Burnable}}
 
+{{ERC721Consecutive}}
+
 {{ERC721URIStorage}}
 
 {{ERC721Votes}}

+ 142 - 0
contracts/token/ERC721/extensions/ERC721Consecutive.sol

@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: MIT
+
+pragma solidity ^0.8.0;
+
+import "../ERC721.sol";
+import "../../../interfaces/IERC2309.sol";
+import "../../../utils/Checkpoints.sol";
+import "../../../utils/structs/BitMaps.sol";
+
+/**
+ * @dev Implementation of the ERC2309 "Consecutive Transfer Extension" as defined in
+ * https://eips.ethereum.org/EIPS/eip-2309[EIP-2309].
+ *
+ * This extension allows the minting of large batches of tokens, during contract construction only. For upgradeable
+ * contracts this implies that batch minting is only available during proxy deployment, and not in subsequent upgrades.
+ * These batches are limited to 5000 tokens at a time by default to accommodate off-chain indexers.
+ *
+ * Using this extension removes the ability to mint single tokens during contract construction. This ability is
+ * regained after construction. During construction, only batch minting is allowed.
+ *
+ * IMPORTANT: This extension bypasses the hooks {_beforeTokenTransfer} and {_afterTokenTransfer} for tokens minted in
+ * batch. When using this extension, you should consider the {_beforeConsecutiveTokenTransfer} and
+ * {_afterConsecutiveTokenTransfer} hooks in addition to {_beforeTokenTransfer} and {_afterTokenTransfer}.
+ *
+ * IMPORTANT: When overriding {_afterTokenTransfer}, be careful about call ordering. {ownerOf} may return invalid
+ * values during the {_afterTokenTransfer} execution if the super call is not called first. To be safe, execute the
+ * super call before your custom logic.
+ *
+ * _Available since v4.8._
+ */
+abstract contract ERC721Consecutive is IERC2309, ERC721 {
+    using BitMaps for BitMaps.BitMap;
+    using Checkpoints for Checkpoints.Trace160;
+
+    Checkpoints.Trace160 private _sequentialOwnership;
+    BitMaps.BitMap private _sequentialBurn;
+
+    /**
+     * @dev Maximum size of a batch of consecutive tokens. This is designed to limit stress on off-chain indexing
+     * services that have to record one entry per token, and have protections against "unreasonably large" batches of
+     * tokens.
+     *
+     * NOTE: Overriding the default value of 5000 will not cause on-chain issues, but may result in the asset not being
+     * correctly supported by off-chain indexing services (including marketplaces).
+     */
+    function _maxBatchSize() internal view virtual returns (uint96) {
+        return 5000;
+    }
+
+    /**
+     * @dev See {ERC721-_ownerOf}. Override that checks the sequential ownership structure for tokens that have
+     * been minted as part of a batch, and not yet transferred.
+     */
+    function _ownerOf(uint256 tokenId) internal view virtual override returns (address) {
+        address owner = super._ownerOf(tokenId);
+
+        // If token is owned by the core, or beyond consecutive range, return base value
+        if (owner != address(0) || tokenId > type(uint96).max) {
+            return owner;
+        }
+
+        // Otherwise, check the token was not burned, and fetch ownership from the anchors
+        // Note: no need for safe cast, we know that tokenId <= type(uint96).max
+        return _sequentialBurn.get(tokenId) ? address(0) : address(_sequentialOwnership.lowerLookup(uint96(tokenId)));
+    }
+
+    /**
+     * @dev Mint a batch of tokens of length `batchSize` for `to`. Returns the token id of the first token minted in the
+     * batch; if `batchSize` is 0, returns the number of consecutive ids minted so far.
+     *
+     * Requirements:
+     *
+     * - `batchSize` must not be greater than {_maxBatchSize}.
+     * - The function is called in the constructor of the contract (directly or indirectly).
+     *
+     * CAUTION: Does not emit a `Transfer` event. This is ERC721 compliant as long as it is done inside of the
+     * constructor, which is enforced by this function.
+     *
+     * CAUTION: Does not invoke `onERC721Received` on the receiver.
+     *
+     * Emits a {IERC2309-ConsecutiveTransfer} event.
+     */
+    function _mintConsecutive(address to, uint96 batchSize) internal virtual returns (uint96) {
+        uint96 first = _totalConsecutiveSupply();
+
+        // minting a batch of size 0 is a no-op
+        if (batchSize > 0) {
+            require(!Address.isContract(address(this)), "ERC721Consecutive: batch minting restricted to constructor");
+            require(to != address(0), "ERC721Consecutive: mint to the zero address");
+            require(batchSize <= _maxBatchSize(), "ERC721Consecutive: batch too large");
+
+            // hook before
+            _beforeTokenTransfer(address(0), to, first, batchSize);
+
+            // push an ownership checkpoint & emit event
+            uint96 last = first + batchSize - 1;
+            _sequentialOwnership.push(last, uint160(to));
+            emit ConsecutiveTransfer(first, last, address(0), to);
+
+            // hook after
+            _afterTokenTransfer(address(0), to, first, batchSize);
+        }
+
+        return first;
+    }
+
+    /**
+     * @dev See {ERC721-_mint}. Override version that restricts normal minting to after construction.
+     *
+     * Warning: Using {ERC721Consecutive} prevents using {_mint} during construction in favor of {_mintConsecutive}.
+     * After construction, {_mintConsecutive} is no longer available and {_mint} becomes available.
+     */
+    function _mint(address to, uint256 tokenId) internal virtual override {
+        require(Address.isContract(address(this)), "ERC721Consecutive: can't mint during construction");
+        super._mint(to, tokenId);
+    }
+
+    /**
+     * @dev See {ERC721-_afterTokenTransfer}. Burning of tokens that have been sequentially minted must be explicit.
+     */
+    function _afterTokenTransfer(
+        address from,
+        address to,
+        uint256 firstTokenId,
+        uint256 batchSize
+    ) internal virtual override {
+        if (
+            to == address(0) && // if we burn
+            firstTokenId < _totalConsecutiveSupply() && // and the tokenId was minted in a batch
+            !_sequentialBurn.get(firstTokenId) // and the token was never marked as burnt
+        ) {
+            require(batchSize == 1, "ERC721Consecutive: batch burn not supported");
+            _sequentialBurn.set(firstTokenId);
+        }
+        super._afterTokenTransfer(from, to, firstTokenId, batchSize);
+    }
+
+    function _totalConsecutiveSupply() private view returns (uint96) {
+        (bool exists, uint96 latestId, ) = _sequentialOwnership.latestCheckpoint();
+        return exists ? latestId + 1 : 0;
+    }
+}

+ 11 - 15
contracts/token/ERC721/extensions/ERC721Enumerable.sol

@@ -55,26 +55,22 @@ abstract contract ERC721Enumerable is ERC721, IERC721Enumerable {
     }
 
     /**
-     * @dev Hook that is called before any token transfer. This includes minting
-     * and burning.
-     *
-     * Calling conditions:
-     *
-     * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be
-     * transferred to `to`.
-     * - When `from` is zero, `tokenId` will be minted for `to`.
-     * - When `to` is zero, ``from``'s `tokenId` will be burned.
-     * - `from` cannot be the zero address.
-     * - `to` cannot be the zero address.
-     *
-     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
+     * @dev See {ERC721-_beforeTokenTransfer}.
      */
     function _beforeTokenTransfer(
         address from,
         address to,
-        uint256 tokenId
+        uint256 firstTokenId,
+        uint256 batchSize
     ) internal virtual override {
-        super._beforeTokenTransfer(from, to, tokenId);
+        super._beforeTokenTransfer(from, to, firstTokenId, batchSize);
+
+        if (batchSize > 1) {
+            // Will only trigger during construction. Batch transferring (minting) is not available afterwards.
+            revert("ERC721Enumerable: consecutive transfers not supported");
+        }
+
+        uint256 tokenId = firstTokenId;
 
         if (from == address(0)) {
             _addTokenToAllTokensEnumeration(tokenId);

+ 3 - 2
contracts/token/ERC721/extensions/ERC721Pausable.sol

@@ -24,9 +24,10 @@ abstract contract ERC721Pausable is ERC721, Pausable {
     function _beforeTokenTransfer(
         address from,
         address to,
-        uint256 tokenId
+        uint256 firstTokenId,
+        uint256 batchSize
     ) internal virtual override {
-        super._beforeTokenTransfer(from, to, tokenId);
+        super._beforeTokenTransfer(from, to, firstTokenId, batchSize);
 
         require(!paused(), "ERC721Pausable: token transfer while paused");
     }

+ 2 - 2
contracts/token/ERC721/extensions/ERC721Royalty.sol

@@ -11,8 +11,8 @@ import "../../../utils/introspection/ERC165.sol";
  * @dev Extension of ERC721 with the ERC2981 NFT Royalty Standard, a standardized way to retrieve royalty payment
  * information.
  *
- * Royalty information can be specified globally for all token ids via {_setDefaultRoyalty}, and/or individually for
- * specific token ids via {_setTokenRoyalty}. The latter takes precedence over the first.
+ * Royalty information can be specified globally for all token ids via {ERC2981-_setDefaultRoyalty}, and/or individually for
+ * specific token ids via {ERC2981-_setTokenRoyalty}. The latter takes precedence over the first.
  *
  * IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See
  * https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to

+ 40 - 0
contracts/token/ERC721/extensions/ERC721Votes.sol

@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: MIT
+
+pragma solidity ^0.8.0;
+
+import "../ERC721.sol";
+import "../../../governance/utils/Votes.sol";
+
+/**
+ * @dev Extension of ERC721 to support voting and delegation as implemented by {Votes}, where each individual NFT counts
+ * as 1 vote unit.
+ *
+ * Tokens do not count as votes until they are delegated, because votes must be tracked which incurs an additional cost
+ * on every transfer. Token holders can either delegate to a trusted representative who will decide how to make use of
+ * the votes in governance decisions, or they can delegate to themselves to be their own representative.
+ *
+ * _Available since v4.5._
+ */
+abstract contract ERC721Votes is ERC721, Votes {
+    /**
+     * @dev See {ERC721-_afterTokenTransfer}. Adjusts votes when tokens are transferred.
+     *
+     * Emits a {IVotes-DelegateVotesChanged} event.
+     */
+    function _afterTokenTransfer(
+        address from,
+        address to,
+        uint256 firstTokenId,
+        uint256 batchSize
+    ) internal virtual override {
+        _transferVotingUnits(from, to, batchSize);
+        super._afterTokenTransfer(from, to, firstTokenId, batchSize);
+    }
+
+    /**
+     * @dev Returns the balance of `account`.
+     */
+    function _getVotingUnits(address account) internal view virtual override returns (uint256) {
+        return balanceOf(account);
+    }
+}

+ 3 - 35
contracts/token/ERC721/extensions/draft-ERC721Votes.sol

@@ -1,40 +1,8 @@
 // SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/extensions/draft-ERC721Votes.sol)
 
 pragma solidity ^0.8.0;
 
-import "../ERC721.sol";
-import "../../../governance/utils/Votes.sol";
+// ERC721Votes was marked as draft due to the EIP-712 dependency.
+// EIP-712 is Final as of 2022-08-11. This file is deprecated.
 
-/**
- * @dev Extension of ERC721 to support voting and delegation as implemented by {Votes}, where each individual NFT counts
- * as 1 vote unit.
- *
- * Tokens do not count as votes until they are delegated, because votes must be tracked which incurs an additional cost
- * on every transfer. Token holders can either delegate to a trusted representative who will decide how to make use of
- * the votes in governance decisions, or they can delegate to themselves to be their own representative.
- *
- * _Available since v4.5._
- */
-abstract contract ERC721Votes is ERC721, Votes {
-    /**
-     * @dev Adjusts votes when tokens are transferred.
-     *
-     * Emits a {Votes-DelegateVotesChanged} event.
-     */
-    function _afterTokenTransfer(
-        address from,
-        address to,
-        uint256 tokenId
-    ) internal virtual override {
-        _transferVotingUnits(from, to, 1);
-        super._afterTokenTransfer(from, to, tokenId);
-    }
-
-    /**
-     * @dev Returns the balance of `account`.
-     */
-    function _getVotingUnits(address account) internal view virtual override returns (uint256) {
-        return balanceOf(account);
-    }
-}
+import "./ERC721Votes.sol";

+ 3 - 2
contracts/token/ERC721/presets/ERC721PresetMinterPauserAutoId.sol

@@ -119,9 +119,10 @@ contract ERC721PresetMinterPauserAutoId is
     function _beforeTokenTransfer(
         address from,
         address to,
-        uint256 tokenId
+        uint256 firstTokenId,
+        uint256 batchSize
     ) internal virtual override(ERC721, ERC721Enumerable, ERC721Pausable) {
-        super._beforeTokenTransfer(from, to, tokenId);
+        super._beforeTokenTransfer(from, to, firstTokenId, batchSize);
     }
 
     /**

+ 1 - 1
contracts/token/ERC777/ERC777.sol

@@ -508,7 +508,7 @@ contract ERC777 is Context, IERC777, IERC20 {
      * Does not update the allowance amount in case of infinite allowance.
      * Revert if not enough allowance is available.
      *
-     * Might emit an {Approval} event.
+     * Might emit an {IERC20-Approval} event.
      */
     function _spendAllowance(
         address owner,

+ 1 - 1
contracts/utils/Address.sol

@@ -50,7 +50,7 @@ library Address {
      * imposed by `transfer`, making them unable to receive funds via
      * `transfer`. {sendValue} removes this limitation.
      *
-     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
+     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
      *
      * IMPORTANT: because control is transferred to `recipient`, care must be
      * taken to not create reentrancy vulnerabilities. Consider using

+ 59 - 2
contracts/utils/Arrays.sol

@@ -3,12 +3,15 @@
 
 pragma solidity ^0.8.0;
 
+import "./StorageSlot.sol";
 import "./math/Math.sol";
 
 /**
  * @dev Collection of functions related to array types.
  */
 library Arrays {
+    using StorageSlot for bytes32;
+
     /**
      * @dev Searches a sorted `array` and returns the first index that contains
      * a value greater or equal to `element`. If no such index exists (i.e. all
@@ -31,7 +34,7 @@ library Arrays {
 
             // Note that mid will always be strictly less than high (i.e. it will be a valid array index)
             // because Math.average rounds down (it does integer division with truncation).
-            if (array[mid] > element) {
+            if (unsafeAccess(array, mid).value > element) {
                 high = mid;
             } else {
                 low = mid + 1;
@@ -39,10 +42,64 @@ library Arrays {
         }
 
         // At this point `low` is the exclusive upper bound. We will return the inclusive upper bound.
-        if (low > 0 && array[low - 1] == element) {
+        if (low > 0 && unsafeAccess(array, low - 1).value == element) {
             return low - 1;
         } else {
             return low;
         }
     }
+
+    /**
+     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
+     *
+     * WARNING: Only use if you are certain `pos` is lower than the array length.
+     */
+    function unsafeAccess(address[] storage arr, uint256 pos) internal pure returns (StorageSlot.AddressSlot storage) {
+        bytes32 slot;
+        // We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr`
+        // following https://docs.soliditylang.org/en/v0.8.17/internals/layout_in_storage.html#mappings-and-dynamic-arrays.
+
+        /// @solidity memory-safe-assembly
+        assembly {
+            mstore(0, arr.slot)
+            slot := add(keccak256(0, 0x20), pos)
+        }
+        return slot.getAddressSlot();
+    }
+
+    /**
+     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
+     *
+     * WARNING: Only use if you are certain `pos` is lower than the array length.
+     */
+    function unsafeAccess(bytes32[] storage arr, uint256 pos) internal pure returns (StorageSlot.Bytes32Slot storage) {
+        bytes32 slot;
+        // We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr`
+        // following https://docs.soliditylang.org/en/v0.8.17/internals/layout_in_storage.html#mappings-and-dynamic-arrays.
+
+        /// @solidity memory-safe-assembly
+        assembly {
+            mstore(0, arr.slot)
+            slot := add(keccak256(0, 0x20), pos)
+        }
+        return slot.getBytes32Slot();
+    }
+
+    /**
+     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
+     *
+     * WARNING: Only use if you are certain `pos` is lower than the array length.
+     */
+    function unsafeAccess(uint256[] storage arr, uint256 pos) internal pure returns (StorageSlot.Uint256Slot storage) {
+        bytes32 slot;
+        // We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr`
+        // following https://docs.soliditylang.org/en/v0.8.17/internals/layout_in_storage.html#mappings-and-dynamic-arrays.
+
+        /// @solidity memory-safe-assembly
+        assembly {
+            mstore(0, arr.slot)
+            slot := add(keccak256(0, 0x20), pos)
+        }
+        return slot.getUint256Slot();
+    }
 }

+ 483 - 25
contracts/utils/Checkpoints.sol

@@ -1,5 +1,7 @@
 // SPDX-License-Identifier: MIT
 // OpenZeppelin Contracts (last updated v4.5.0) (utils/Checkpoints.sol)
+// This file was procedurally generated from scripts/generate/templates/Checkpoints.js.
+
 pragma solidity ^0.8.0;
 
 import "./math/Math.sol";
@@ -15,41 +17,55 @@ import "./math/SafeCast.sol";
  * _Available since v4.5._
  */
 library Checkpoints {
+    struct History {
+        Checkpoint[] _checkpoints;
+    }
+
     struct Checkpoint {
         uint32 _blockNumber;
         uint224 _value;
     }
 
-    struct History {
-        Checkpoint[] _checkpoints;
-    }
-
     /**
-     * @dev Returns the value in the latest checkpoint, or zero if there are no checkpoints.
+     * @dev Returns the value at a given block number. If a checkpoint is not available at that block, the closest one
+     * before it is returned, or zero otherwise.
      */
-    function latest(History storage self) internal view returns (uint256) {
-        uint256 pos = self._checkpoints.length;
-        return pos == 0 ? 0 : self._checkpoints[pos - 1]._value;
+    function getAtBlock(History storage self, uint256 blockNumber) internal view returns (uint256) {
+        require(blockNumber < block.number, "Checkpoints: block not yet mined");
+        uint32 key = SafeCast.toUint32(blockNumber);
+
+        uint256 len = self._checkpoints.length;
+        uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len);
+        return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
     }
 
     /**
      * @dev Returns the value at a given block number. If a checkpoint is not available at that block, the closest one
-     * before it is returned, or zero otherwise.
+     * before it is returned, or zero otherwise. Similar to {upperLookup} but optimized for the case when the searched
+     * checkpoint is probably "recent", defined as being among the last sqrt(N) checkpoints where N is the number of
+     * checkpoints.
      */
-    function getAtBlock(History storage self, uint256 blockNumber) internal view returns (uint256) {
+    function getAtProbablyRecentBlock(History storage self, uint256 blockNumber) internal view returns (uint256) {
         require(blockNumber < block.number, "Checkpoints: block not yet mined");
+        uint32 key = SafeCast.toUint32(blockNumber);
+
+        uint256 len = self._checkpoints.length;
 
-        uint256 high = self._checkpoints.length;
         uint256 low = 0;
-        while (low < high) {
-            uint256 mid = Math.average(low, high);
-            if (self._checkpoints[mid]._blockNumber > blockNumber) {
+        uint256 high = len;
+
+        if (len > 5) {
+            uint256 mid = len - Math.sqrt(len);
+            if (key < _unsafeAccess(self._checkpoints, mid)._blockNumber) {
                 high = mid;
             } else {
                 low = mid + 1;
             }
         }
-        return high == 0 ? 0 : self._checkpoints[high - 1]._value;
+
+        uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high);
+
+        return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
     }
 
     /**
@@ -58,16 +74,7 @@ library Checkpoints {
      * Returns previous value and new value.
      */
     function push(History storage self, uint256 value) internal returns (uint256, uint256) {
-        uint256 pos = self._checkpoints.length;
-        uint256 old = latest(self);
-        if (pos > 0 && self._checkpoints[pos - 1]._blockNumber == block.number) {
-            self._checkpoints[pos - 1]._value = SafeCast.toUint224(value);
-        } else {
-            self._checkpoints.push(
-                Checkpoint({_blockNumber: SafeCast.toUint32(block.number), _value: SafeCast.toUint224(value)})
-            );
-        }
-        return (old, value);
+        return _insert(self._checkpoints, SafeCast.toUint32(block.number), SafeCast.toUint224(value));
     }
 
     /**
@@ -83,4 +90,455 @@ library Checkpoints {
     ) internal returns (uint256, uint256) {
         return push(self, op(latest(self), delta));
     }
+
+    /**
+     * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints.
+     */
+    function latest(History storage self) internal view returns (uint224) {
+        uint256 pos = self._checkpoints.length;
+        return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
+    }
+
+    /**
+     * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value
+     * in the most recent checkpoint.
+     */
+    function latestCheckpoint(History storage self)
+        internal
+        view
+        returns (
+            bool exists,
+            uint32 _blockNumber,
+            uint224 _value
+        )
+    {
+        uint256 pos = self._checkpoints.length;
+        if (pos == 0) {
+            return (false, 0, 0);
+        } else {
+            Checkpoint memory ckpt = _unsafeAccess(self._checkpoints, pos - 1);
+            return (true, ckpt._blockNumber, ckpt._value);
+        }
+    }
+
+    /**
+     * @dev Returns the number of checkpoint.
+     */
+    function length(History storage self) internal view returns (uint256) {
+        return self._checkpoints.length;
+    }
+
+    /**
+     * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint,
+     * or by updating the last one.
+     */
+    function _insert(
+        Checkpoint[] storage self,
+        uint32 key,
+        uint224 value
+    ) private returns (uint224, uint224) {
+        uint256 pos = self.length;
+
+        if (pos > 0) {
+            // Copying to memory is important here.
+            Checkpoint memory last = _unsafeAccess(self, pos - 1);
+
+            // Checkpoints keys must be increasing.
+            require(last._blockNumber <= key, "Checkpoint: invalid key");
+
+            // Update or push new checkpoint
+            if (last._blockNumber == key) {
+                _unsafeAccess(self, pos - 1)._value = value;
+            } else {
+                self.push(Checkpoint({_blockNumber: key, _value: value}));
+            }
+            return (last._value, value);
+        } else {
+            self.push(Checkpoint({_blockNumber: key, _value: value}));
+            return (0, value);
+        }
+    }
+
+    /**
+     * @dev Return the index of the oldest checkpoint whose key is greater than the search key, or `high` if there is none.
+     * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`.
+     *
+     * WARNING: `high` should not be greater than the array's length.
+     */
+    function _upperBinaryLookup(
+        Checkpoint[] storage self,
+        uint32 key,
+        uint256 low,
+        uint256 high
+    ) private view returns (uint256) {
+        while (low < high) {
+            uint256 mid = Math.average(low, high);
+            if (_unsafeAccess(self, mid)._blockNumber > key) {
+                high = mid;
+            } else {
+                low = mid + 1;
+            }
+        }
+        return high;
+    }
+
+    /**
+     * @dev Return the index of the oldest checkpoint whose key is greater or equal than the search key, or `high` if there is none.
+     * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`.
+     *
+     * WARNING: `high` should not be greater than the array's length.
+     */
+    function _lowerBinaryLookup(
+        Checkpoint[] storage self,
+        uint32 key,
+        uint256 low,
+        uint256 high
+    ) private view returns (uint256) {
+        while (low < high) {
+            uint256 mid = Math.average(low, high);
+            if (_unsafeAccess(self, mid)._blockNumber < key) {
+                low = mid + 1;
+            } else {
+                high = mid;
+            }
+        }
+        return high;
+    }
+
+    function _unsafeAccess(Checkpoint[] storage self, uint256 pos) private pure returns (Checkpoint storage result) {
+        assembly {
+            mstore(0, self.slot)
+            result.slot := add(keccak256(0, 0x20), pos)
+        }
+    }
+
+    struct Trace224 {
+        Checkpoint224[] _checkpoints;
+    }
+
+    struct Checkpoint224 {
+        uint32 _key;
+        uint224 _value;
+    }
+
+    /**
+     * @dev Pushes a (`key`, `value`) pair into a Trace224 so that it is stored as the checkpoint.
+     *
+     * Returns previous value and new value.
+     */
+    function push(
+        Trace224 storage self,
+        uint32 key,
+        uint224 value
+    ) internal returns (uint224, uint224) {
+        return _insert(self._checkpoints, key, value);
+    }
+
+    /**
+     * @dev Returns the value in the oldest checkpoint with key greater or equal than the search key, or zero if there is none.
+     */
+    function lowerLookup(Trace224 storage self, uint32 key) internal view returns (uint224) {
+        uint256 len = self._checkpoints.length;
+        uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len);
+        return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value;
+    }
+
+    /**
+     * @dev Returns the value in the most recent checkpoint with key lower or equal than the search key.
+     */
+    function upperLookup(Trace224 storage self, uint32 key) internal view returns (uint224) {
+        uint256 len = self._checkpoints.length;
+        uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len);
+        return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
+    }
+
+    /**
+     * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints.
+     */
+    function latest(Trace224 storage self) internal view returns (uint224) {
+        uint256 pos = self._checkpoints.length;
+        return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
+    }
+
+    /**
+     * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value
+     * in the most recent checkpoint.
+     */
+    function latestCheckpoint(Trace224 storage self)
+        internal
+        view
+        returns (
+            bool exists,
+            uint32 _key,
+            uint224 _value
+        )
+    {
+        uint256 pos = self._checkpoints.length;
+        if (pos == 0) {
+            return (false, 0, 0);
+        } else {
+            Checkpoint224 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1);
+            return (true, ckpt._key, ckpt._value);
+        }
+    }
+
+    /**
+     * @dev Returns the number of checkpoint.
+     */
+    function length(Trace224 storage self) internal view returns (uint256) {
+        return self._checkpoints.length;
+    }
+
+    /**
+     * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint,
+     * or by updating the last one.
+     */
+    function _insert(
+        Checkpoint224[] storage self,
+        uint32 key,
+        uint224 value
+    ) private returns (uint224, uint224) {
+        uint256 pos = self.length;
+
+        if (pos > 0) {
+            // Copying to memory is important here.
+            Checkpoint224 memory last = _unsafeAccess(self, pos - 1);
+
+            // Checkpoints keys must be increasing.
+            require(last._key <= key, "Checkpoint: invalid key");
+
+            // Update or push new checkpoint
+            if (last._key == key) {
+                _unsafeAccess(self, pos - 1)._value = value;
+            } else {
+                self.push(Checkpoint224({_key: key, _value: value}));
+            }
+            return (last._value, value);
+        } else {
+            self.push(Checkpoint224({_key: key, _value: value}));
+            return (0, value);
+        }
+    }
+
+    /**
+     * @dev Return the index of the oldest checkpoint whose key is greater than the search key, or `high` if there is none.
+     * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`.
+     *
+     * WARNING: `high` should not be greater than the array's length.
+     */
+    function _upperBinaryLookup(
+        Checkpoint224[] storage self,
+        uint32 key,
+        uint256 low,
+        uint256 high
+    ) private view returns (uint256) {
+        while (low < high) {
+            uint256 mid = Math.average(low, high);
+            if (_unsafeAccess(self, mid)._key > key) {
+                high = mid;
+            } else {
+                low = mid + 1;
+            }
+        }
+        return high;
+    }
+
+    /**
+     * @dev Return the index of the oldest checkpoint whose key is greater or equal than the search key, or `high` if there is none.
+     * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`.
+     *
+     * WARNING: `high` should not be greater than the array's length.
+     */
+    function _lowerBinaryLookup(
+        Checkpoint224[] storage self,
+        uint32 key,
+        uint256 low,
+        uint256 high
+    ) private view returns (uint256) {
+        while (low < high) {
+            uint256 mid = Math.average(low, high);
+            if (_unsafeAccess(self, mid)._key < key) {
+                low = mid + 1;
+            } else {
+                high = mid;
+            }
+        }
+        return high;
+    }
+
+    function _unsafeAccess(Checkpoint224[] storage self, uint256 pos)
+        private
+        pure
+        returns (Checkpoint224 storage result)
+    {
+        assembly {
+            mstore(0, self.slot)
+            result.slot := add(keccak256(0, 0x20), pos)
+        }
+    }
+
+    struct Trace160 {
+        Checkpoint160[] _checkpoints;
+    }
+
+    struct Checkpoint160 {
+        uint96 _key;
+        uint160 _value;
+    }
+
+    /**
+     * @dev Pushes a (`key`, `value`) pair into a Trace160 so that it is stored as the checkpoint.
+     *
+     * Returns previous value and new value.
+     */
+    function push(
+        Trace160 storage self,
+        uint96 key,
+        uint160 value
+    ) internal returns (uint160, uint160) {
+        return _insert(self._checkpoints, key, value);
+    }
+
+    /**
+     * @dev Returns the value in the oldest checkpoint with key greater or equal than the search key, or zero if there is none.
+     */
+    function lowerLookup(Trace160 storage self, uint96 key) internal view returns (uint160) {
+        uint256 len = self._checkpoints.length;
+        uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len);
+        return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value;
+    }
+
+    /**
+     * @dev Returns the value in the most recent checkpoint with key lower or equal than the search key.
+     */
+    function upperLookup(Trace160 storage self, uint96 key) internal view returns (uint160) {
+        uint256 len = self._checkpoints.length;
+        uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len);
+        return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
+    }
+
+    /**
+     * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints.
+     */
+    function latest(Trace160 storage self) internal view returns (uint160) {
+        uint256 pos = self._checkpoints.length;
+        return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
+    }
+
+    /**
+     * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value
+     * in the most recent checkpoint.
+     */
+    function latestCheckpoint(Trace160 storage self)
+        internal
+        view
+        returns (
+            bool exists,
+            uint96 _key,
+            uint160 _value
+        )
+    {
+        uint256 pos = self._checkpoints.length;
+        if (pos == 0) {
+            return (false, 0, 0);
+        } else {
+            Checkpoint160 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1);
+            return (true, ckpt._key, ckpt._value);
+        }
+    }
+
+    /**
+     * @dev Returns the number of checkpoint.
+     */
+    function length(Trace160 storage self) internal view returns (uint256) {
+        return self._checkpoints.length;
+    }
+
+    /**
+     * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint,
+     * or by updating the last one.
+     */
+    function _insert(
+        Checkpoint160[] storage self,
+        uint96 key,
+        uint160 value
+    ) private returns (uint160, uint160) {
+        uint256 pos = self.length;
+
+        if (pos > 0) {
+            // Copying to memory is important here.
+            Checkpoint160 memory last = _unsafeAccess(self, pos - 1);
+
+            // Checkpoints keys must be increasing.
+            require(last._key <= key, "Checkpoint: invalid key");
+
+            // Update or push new checkpoint
+            if (last._key == key) {
+                _unsafeAccess(self, pos - 1)._value = value;
+            } else {
+                self.push(Checkpoint160({_key: key, _value: value}));
+            }
+            return (last._value, value);
+        } else {
+            self.push(Checkpoint160({_key: key, _value: value}));
+            return (0, value);
+        }
+    }
+
+    /**
+     * @dev Return the index of the oldest checkpoint whose key is greater than the search key, or `high` if there is none.
+     * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`.
+     *
+     * WARNING: `high` should not be greater than the array's length.
+     */
+    function _upperBinaryLookup(
+        Checkpoint160[] storage self,
+        uint96 key,
+        uint256 low,
+        uint256 high
+    ) private view returns (uint256) {
+        while (low < high) {
+            uint256 mid = Math.average(low, high);
+            if (_unsafeAccess(self, mid)._key > key) {
+                high = mid;
+            } else {
+                low = mid + 1;
+            }
+        }
+        return high;
+    }
+
+    /**
+     * @dev Return the index of the oldest checkpoint whose key is greater or equal than the search key, or `high` if there is none.
+     * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`.
+     *
+     * WARNING: `high` should not be greater than the array's length.
+     */
+    function _lowerBinaryLookup(
+        Checkpoint160[] storage self,
+        uint96 key,
+        uint256 low,
+        uint256 high
+    ) private view returns (uint256) {
+        while (low < high) {
+            uint256 mid = Math.average(low, high);
+            if (_unsafeAccess(self, mid)._key < key) {
+                low = mid + 1;
+            } else {
+                high = mid;
+            }
+        }
+        return high;
+    }
+
+    function _unsafeAccess(Checkpoint160[] storage self, uint256 pos)
+        private
+        pure
+        returns (Checkpoint160 storage result)
+    {
+        assembly {
+            mstore(0, self.slot)
+            result.slot := add(keccak256(0, 0x20), pos)
+        }
+    }
 }

+ 23 - 6
contracts/utils/Create2.sol

@@ -31,8 +31,7 @@ library Create2 {
         uint256 amount,
         bytes32 salt,
         bytes memory bytecode
-    ) internal returns (address) {
-        address addr;
+    ) internal returns (address addr) {
         require(address(this).balance >= amount, "Create2: insufficient balance");
         require(bytecode.length != 0, "Create2: bytecode length is zero");
         /// @solidity memory-safe-assembly
@@ -40,7 +39,6 @@ library Create2 {
             addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt)
         }
         require(addr != address(0), "Create2: Failed on deploy");
-        return addr;
     }
 
     /**
@@ -59,8 +57,27 @@ library Create2 {
         bytes32 salt,
         bytes32 bytecodeHash,
         address deployer
-    ) internal pure returns (address) {
-        bytes32 _data = keccak256(abi.encodePacked(bytes1(0xff), deployer, salt, bytecodeHash));
-        return address(uint160(uint256(_data)));
+    ) internal pure returns (address addr) {
+        /// @solidity memory-safe-assembly
+        assembly {
+            let ptr := mload(0x40) // Get free memory pointer
+
+            // |                   | ↓ ptr ...  ↓ ptr + 0x0B (start) ...  ↓ ptr + 0x20 ...  ↓ ptr + 0x40 ...   |
+            // |-------------------|---------------------------------------------------------------------------|
+            // | bytecodeHash      |                                                        CCCCCCCCCCCCC...CC |
+            // | salt              |                                      BBBBBBBBBBBBB...BB                   |
+            // | deployer          | 000000...0000AAAAAAAAAAAAAAAAAAA...AA                                     |
+            // | 0xFF              |            FF                                                             |
+            // |-------------------|---------------------------------------------------------------------------|
+            // | memory            | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC |
+            // | keccak(start, 85) |            ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ |
+
+            mstore(add(ptr, 0x40), bytecodeHash)
+            mstore(add(ptr, 0x20), salt)
+            mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes
+            let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff
+            mstore8(start, 0xff)
+            addr := keccak256(start, 85)
+        }
     }
 }

+ 24 - 29
contracts/utils/Strings.sol

@@ -3,52 +3,47 @@
 
 pragma solidity ^0.8.0;
 
+import "./math/Math.sol";
+
 /**
  * @dev String operations.
  */
 library Strings {
-    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
+    bytes16 private constant _SYMBOLS = "0123456789abcdef";
     uint8 private constant _ADDRESS_LENGTH = 20;
 
     /**
      * @dev Converts a `uint256` to its ASCII `string` decimal representation.
      */
     function toString(uint256 value) internal pure returns (string memory) {
-        // Inspired by OraclizeAPI's implementation - MIT licence
-        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
-
-        if (value == 0) {
-            return "0";
-        }
-        uint256 temp = value;
-        uint256 digits;
-        while (temp != 0) {
-            digits++;
-            temp /= 10;
+        unchecked {
+            uint256 length = Math.log10(value) + 1;
+            string memory buffer = new string(length);
+            uint256 ptr;
+            /// @solidity memory-safe-assembly
+            assembly {
+                ptr := add(buffer, add(32, length))
+            }
+            while (true) {
+                ptr--;
+                /// @solidity memory-safe-assembly
+                assembly {
+                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
+                }
+                value /= 10;
+                if (value == 0) break;
+            }
+            return buffer;
         }
-        bytes memory buffer = new bytes(digits);
-        while (value != 0) {
-            digits -= 1;
-            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
-            value /= 10;
-        }
-        return string(buffer);
     }
 
     /**
      * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
      */
     function toHexString(uint256 value) internal pure returns (string memory) {
-        if (value == 0) {
-            return "0x00";
-        }
-        uint256 temp = value;
-        uint256 length = 0;
-        while (temp != 0) {
-            length++;
-            temp >>= 8;
+        unchecked {
+            return toHexString(value, Math.log256(value) + 1);
         }
-        return toHexString(value, length);
     }
 
     /**
@@ -59,7 +54,7 @@ library Strings {
         buffer[0] = "0";
         buffer[1] = "x";
         for (uint256 i = 2 * length + 1; i > 1; --i) {
-            buffer[i] = _HEX_SYMBOLS[value & 0xf];
+            buffer[i] = _SYMBOLS[value & 0xf];
             value >>= 4;
         }
         require(value == 0, "Strings: hex length insufficient");

+ 21 - 10
contracts/utils/cryptography/MerkleProof.sol

@@ -6,16 +6,16 @@ pragma solidity ^0.8.0;
 /**
  * @dev These functions deal with verification of Merkle Tree proofs.
  *
- * The proofs can be generated using the JavaScript library
- * https://github.com/miguelmota/merkletreejs[merkletreejs].
- * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.
- *
- * See `test/utils/cryptography/MerkleProof.test.js` for some examples.
+ * The tree and the proofs can be generated using our
+ * https://github.com/OpenZeppelin/merkle-tree[JavaScript library].
+ * You will find a quickstart guide in the readme.
  *
  * WARNING: You should avoid using leaf values that are 64 bytes long prior to
  * hashing, or use a hash function other than keccak256 for hashing leaves.
  * This is because the concatenation of a sorted pair of internal nodes in
  * the merkle tree could be reinterpreted as a leaf value.
+ * OpenZeppelin's JavaScript library generates merkle trees that are safe
+ * against this attack out of the box.
  */
 library MerkleProof {
     /**
@@ -75,9 +75,11 @@ library MerkleProof {
     }
 
     /**
-     * @dev Returns true if the `leaves` can be proved to be a part of a Merkle tree defined by
+     * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a merkle tree defined by
      * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
      *
+     * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
+     *
      * _Available since v4.7._
      */
     function multiProofVerify(
@@ -92,6 +94,8 @@ library MerkleProof {
     /**
      * @dev Calldata version of {multiProofVerify}
      *
+     * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
+     *
      * _Available since v4.7._
      */
     function multiProofVerifyCalldata(
@@ -104,9 +108,14 @@ library MerkleProof {
     }
 
     /**
-     * @dev Returns the root of a tree reconstructed from `leaves` and the sibling nodes in `proof`,
-     * consuming from one or the other at each step according to the instructions given by
-     * `proofFlags`.
+     * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction
+     * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another
+     * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false
+     * respectively.
+     *
+     * CAUTION: Not all merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree
+     * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the
+     * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).
      *
      * _Available since v4.7._
      */
@@ -152,7 +161,9 @@ library MerkleProof {
     }
 
     /**
-     * @dev Calldata version of {processMultiProof}
+     * @dev Calldata version of {processMultiProof}.
+     *
+     * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
      *
      * _Available since v4.7._
      */

+ 0 - 1
contracts/utils/cryptography/SignatureChecker.sol

@@ -4,7 +4,6 @@
 pragma solidity ^0.8.0;
 
 import "./ECDSA.sol";
-import "../Address.sol";
 import "../../interfaces/IERC1271.sol";
 
 /**

+ 2 - 2
contracts/utils/introspection/ERC165Checker.sol

@@ -17,7 +17,7 @@ library ERC165Checker {
     bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;
 
     /**
-     * @dev Returns true if `account` supports the {IERC165} interface,
+     * @dev Returns true if `account` supports the {IERC165} interface.
      */
     function supportsERC165(address account) internal view returns (bool) {
         // Any contract that implements ERC165 must explicitly indicate support of
@@ -82,7 +82,7 @@ library ERC165Checker {
             return false;
         }
 
-        // query support of each interface in _interfaceIds
+        // query support of each interface in interfaceIds
         for (uint256 i = 0; i < interfaceIds.length; i++) {
             if (!supportsERC165InterfaceUnchecked(account, interfaceIds[i])) {
                 return false;

+ 157 - 38
contracts/utils/math/Math.sol

@@ -17,7 +17,7 @@ library Math {
      * @dev Returns the largest of two numbers.
      */
     function max(uint256 a, uint256 b) internal pure returns (uint256) {
-        return a >= b ? a : b;
+        return a > b ? a : b;
     }
 
     /**
@@ -161,41 +161,16 @@ library Math {
         }
 
         // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
+        //
         // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
-        // `msb(a) <= a < 2*msb(a)`.
-        // We also know that `k`, the position of the most significant bit, is such that `msb(a) = 2**k`.
-        // This gives `2**k < a <= 2**(k+1)` → `2**(k/2) <= sqrt(a) < 2 ** (k/2+1)`.
-        // Using an algorithm similar to the msb computation, we are able to compute `result = 2**(k/2)` which is a
-        // good first approximation of `sqrt(a)` with at least 1 correct bit.
-        uint256 result = 1;
-        uint256 x = a;
-        if (x >> 128 > 0) {
-            x >>= 128;
-            result <<= 64;
-        }
-        if (x >> 64 > 0) {
-            x >>= 64;
-            result <<= 32;
-        }
-        if (x >> 32 > 0) {
-            x >>= 32;
-            result <<= 16;
-        }
-        if (x >> 16 > 0) {
-            x >>= 16;
-            result <<= 8;
-        }
-        if (x >> 8 > 0) {
-            x >>= 8;
-            result <<= 4;
-        }
-        if (x >> 4 > 0) {
-            x >>= 4;
-            result <<= 2;
-        }
-        if (x >> 2 > 0) {
-            result <<= 1;
-        }
+        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
+        //
+        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
+        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
+        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
+        //
+        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
+        uint256 result = 1 << (log2(a) >> 1);
 
         // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
         // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
@@ -217,10 +192,154 @@ library Math {
      * @notice Calculates sqrt(a), following the selected rounding direction.
      */
     function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
-        uint256 result = sqrt(a);
-        if (rounding == Rounding.Up && result * result < a) {
-            result += 1;
+        unchecked {
+            uint256 result = sqrt(a);
+            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
+        }
+    }
+
+    /**
+     * @dev Return the log in base 2, rounded down, of a positive value.
+     * Returns 0 if given 0.
+     */
+    function log2(uint256 value) internal pure returns (uint256) {
+        uint256 result = 0;
+        unchecked {
+            if (value >> 128 > 0) {
+                value >>= 128;
+                result += 128;
+            }
+            if (value >> 64 > 0) {
+                value >>= 64;
+                result += 64;
+            }
+            if (value >> 32 > 0) {
+                value >>= 32;
+                result += 32;
+            }
+            if (value >> 16 > 0) {
+                value >>= 16;
+                result += 16;
+            }
+            if (value >> 8 > 0) {
+                value >>= 8;
+                result += 8;
+            }
+            if (value >> 4 > 0) {
+                value >>= 4;
+                result += 4;
+            }
+            if (value >> 2 > 0) {
+                value >>= 2;
+                result += 2;
+            }
+            if (value >> 1 > 0) {
+                result += 1;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
+     * Returns 0 if given 0.
+     */
+    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
+        unchecked {
+            uint256 result = log2(value);
+            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
+        }
+    }
+
+    /**
+     * @dev Return the log in base 10, rounded down, of a positive value.
+     * Returns 0 if given 0.
+     */
+    function log10(uint256 value) internal pure returns (uint256) {
+        uint256 result = 0;
+        unchecked {
+            if (value >= 10**64) {
+                value /= 10**64;
+                result += 64;
+            }
+            if (value >= 10**32) {
+                value /= 10**32;
+                result += 32;
+            }
+            if (value >= 10**16) {
+                value /= 10**16;
+                result += 16;
+            }
+            if (value >= 10**8) {
+                value /= 10**8;
+                result += 8;
+            }
+            if (value >= 10**4) {
+                value /= 10**4;
+                result += 4;
+            }
+            if (value >= 10**2) {
+                value /= 10**2;
+                result += 2;
+            }
+            if (value >= 10**1) {
+                result += 1;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
+     * Returns 0 if given 0.
+     */
+    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
+        unchecked {
+            uint256 result = log10(value);
+            return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
+        }
+    }
+
+    /**
+     * @dev Return the log in base 256, rounded down, of a positive value.
+     * Returns 0 if given 0.
+     *
+     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
+     */
+    function log256(uint256 value) internal pure returns (uint256) {
+        uint256 result = 0;
+        unchecked {
+            if (value >> 128 > 0) {
+                value >>= 128;
+                result += 16;
+            }
+            if (value >> 64 > 0) {
+                value >>= 64;
+                result += 8;
+            }
+            if (value >> 32 > 0) {
+                value >>= 32;
+                result += 4;
+            }
+            if (value >> 16 > 0) {
+                value >>= 16;
+                result += 2;
+            }
+            if (value >> 8 > 0) {
+                result += 1;
+            }
         }
         return result;
     }
+
+    /**
+     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
+     * Returns 0 if given 0.
+     */
+    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
+        unchecked {
+            uint256 result = log256(value);
+            return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
+        }
+    }
 }

+ 1 - 0
contracts/utils/math/SafeCast.sol

@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: MIT
 // OpenZeppelin Contracts (last updated v4.7.0) (utils/math/SafeCast.sol)
+// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
 
 pragma solidity ^0.8.0;
 

+ 1 - 1
contracts/utils/math/SignedMath.sol

@@ -11,7 +11,7 @@ library SignedMath {
      * @dev Returns the largest of two signed numbers.
      */
     function max(int256 a, int256 b) internal pure returns (int256) {
-        return a >= b ? a : b;
+        return a > b ? a : b;
     }
 
     /**

+ 8 - 5
contracts/utils/structs/EnumerableMap.sol

@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: MIT
 // OpenZeppelin Contracts (last updated v4.7.0) (utils/structs/EnumerableMap.sol)
+// This file was procedurally generated from scripts/generate/templates/EnumerableMap.js.
 
 pragma solidity ^0.8.0;
 
@@ -36,10 +37,12 @@ import "./EnumerableSet.sol";
  *
  * [WARNING]
  * ====
- *  Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable.
- *  See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
+ * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
+ * unusable.
+ * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
  *
- *  In order to clean an EnumerableMap, you can either remove all elements one by one or create a fresh instance using an array of EnumerableMap.
+ * In order to clean an EnumerableMap, you can either remove all elements one by one or create a fresh instance using an
+ * array of EnumerableMap.
  * ====
  */
 library EnumerableMap {
@@ -142,10 +145,10 @@ library EnumerableMap {
     }
 
     /**
-     * @dev Same as {_get}, with a custom error message when `key` is not in the map.
+     * @dev Same as {get}, with a custom error message when `key` is not in the map.
      *
      * CAUTION: This function is deprecated because it requires allocating memory for the error
-     * message unnecessarily. For custom revert reasons use {_tryGet}.
+     * message unnecessarily. For custom revert reasons use {tryGet}.
      */
     function get(
         Bytes32ToBytes32Map storage map,

+ 6 - 3
contracts/utils/structs/EnumerableSet.sol

@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: MIT
 // OpenZeppelin Contracts (last updated v4.7.0) (utils/structs/EnumerableSet.sol)
+// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
 
 pragma solidity ^0.8.0;
 
@@ -29,10 +30,12 @@ pragma solidity ^0.8.0;
  *
  * [WARNING]
  * ====
- *  Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable.
- *  See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
+ * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
+ * unusable.
+ * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
  *
- *  In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet.
+ * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
+ * array of EnumerableSet.
  * ====
  */
 library EnumerableSet {

+ 82 - 41
contracts/vendor/arbitrum/IArbSys.sol

@@ -1,19 +1,15 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.6.0) (vendor/arbitrum/IArbSys.sol)
+// Copyright 2021-2022, Offchain Labs, Inc.
+// For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE
+// SPDX-License-Identifier: BUSL-1.1
+
 pragma solidity >=0.4.21 <0.9.0;
 
 /**
- * @title Precompiled contract that exists in every Arbitrum chain at address(100), 0x0000000000000000000000000000000000000064. Exposes a variety of system-level functionality.
+ * @title System level functionality
+ * @notice For use by contracts to interact with core L2-specific functionality.
+ * Precompiled contract that exists in every Arbitrum chain at address(100), 0x0000000000000000000000000000000000000064.
  */
 interface IArbSys {
-    /**
-     * @notice Get internal version number identifying an ArbOS build
-     * @return version number as int
-     */
-    function arbOSVersion() external pure returns (uint256);
-
-    function arbChainID() external view returns (uint256);
-
     /**
      * @notice Get Arbitrum block number (distinct from L1 block number; Arbitrum genesis block has block number 0)
      * @return block number as int
@@ -21,43 +17,44 @@ interface IArbSys {
     function arbBlockNumber() external view returns (uint256);
 
     /**
-     * @notice Send given amount of Eth to dest from sender.
-     * This is a convenience function, which is equivalent to calling sendTxToL1 with empty calldataForL1.
-     * @param destination recipient address on L1
-     * @return unique identifier for this L2-to-L1 transaction.
+     * @notice Get Arbitrum block hash (reverts unless currentBlockNum-256 <= arbBlockNum < currentBlockNum)
+     * @return block hash
      */
-    function withdrawEth(address destination) external payable returns (uint256);
+    function arbBlockHash(uint256 arbBlockNum) external view returns (bytes32);
 
     /**
-     * @notice Send a transaction to L1
-     * @param destination recipient address on L1
-     * @param calldataForL1 (optional) calldata for L1 contract call
-     * @return a unique identifier for this L2-to-L1 transaction.
+     * @notice Gets the rollup's unique chain identifier
+     * @return Chain identifier as int
      */
-    function sendTxToL1(address destination, bytes calldata calldataForL1) external payable returns (uint256);
+    function arbChainID() external view returns (uint256);
 
     /**
-     * @notice get the number of transactions issued by the given external account or the account sequence number of the given contract
-     * @param account target account
-     * @return the number of transactions issued by the given external account or the account sequence number of the given contract
+     * @notice Get internal version number identifying an ArbOS build
+     * @return version number as int
      */
-    function getTransactionCount(address account) external view returns (uint256);
+    function arbOSVersion() external view returns (uint256);
 
     /**
-     * @notice get the value of target L2 storage slot
-     * This function is only callable from address 0 to prevent contracts from being able to call it
-     * @param account target account
-     * @param index target index of storage slot
-     * @return stotage value for the given account at the given index
+     * @notice Returns 0 since Nitro has no concept of storage gas
+     * @return uint 0
      */
-    function getStorageAt(address account, uint256 index) external view returns (uint256);
+    function getStorageGasAvailable() external view returns (uint256);
 
     /**
-     * @notice check if current call is coming from l1
-     * @return true if the caller of this was called directly from L1
+     * @notice (deprecated) check if current call is top level (meaning it was triggered by an EoA or a L1 contract)
+     * @dev this call has been deprecated and may be removed in a future release
+     * @return true if current execution frame is not a call by another L2 contract
      */
     function isTopLevelCall() external view returns (bool);
 
+    /**
+     * @notice map L1 sender contract address to its L2 alias
+     * @param sender sender address
+     * @param unused argument no longer used
+     * @return aliased sender address
+     */
+    function mapL1SenderContractAddressToL2Alias(address sender, address unused) external pure returns (address);
+
     /**
      * @notice check if the caller (of this caller of this) is an aliased L1 contract address
      * @return true iff the caller's address is an alias for an L1 contract address
@@ -71,19 +68,55 @@ interface IArbSys {
     function myCallersAddressWithoutAliasing() external view returns (address);
 
     /**
-     * @notice map L1 sender contract address to its L2 alias
-     * @param sender sender address
-     * @param dest destination address
-     * @return aliased sender address
+     * @notice Send given amount of Eth to dest from sender.
+     * This is a convenience function, which is equivalent to calling sendTxToL1 with empty data.
+     * @param destination recipient address on L1
+     * @return unique identifier for this L2-to-L1 transaction.
      */
-    function mapL1SenderContractAddressToL2Alias(address sender, address dest) external pure returns (address);
+    function withdrawEth(address destination) external payable returns (uint256);
 
     /**
-     * @notice get the caller's amount of available storage gas
-     * @return amount of storage gas available to the caller
+     * @notice Send a transaction to L1
+     * @dev it is not possible to execute on the L1 any L2-to-L1 transaction which contains data
+     * to a contract address without any code (as enforced by the Bridge contract).
+     * @param destination recipient address on L1
+     * @param data (optional) calldata for L1 contract call
+     * @return a unique identifier for this L2-to-L1 transaction.
      */
-    function getStorageGasAvailable() external view returns (uint256);
+    function sendTxToL1(address destination, bytes calldata data) external payable returns (uint256);
+
+    /**
+     * @notice Get send Merkle tree state
+     * @return size number of sends in the history
+     * @return root root hash of the send history
+     * @return partials hashes of partial subtrees in the send history tree
+     */
+    function sendMerkleTreeState()
+        external
+        view
+        returns (
+            uint256 size,
+            bytes32 root,
+            bytes32[] memory partials
+        );
+
+    /**
+     * @notice creates a send txn from L2 to L1
+     * @param position = (level << 192) + leaf = (0 << 192) + leaf = leaf
+     */
+    event L2ToL1Tx(
+        address caller,
+        address indexed destination,
+        uint256 indexed hash,
+        uint256 indexed position,
+        uint256 arbBlockNum,
+        uint256 ethBlockNum,
+        uint256 timestamp,
+        uint256 callvalue,
+        bytes data
+    );
 
+    /// @dev DEPRECATED in favour of the new L2ToL1Tx event above after the nitro upgrade
     event L2ToL1Transaction(
         address caller,
         address indexed destination,
@@ -96,4 +129,12 @@ interface IArbSys {
         uint256 callvalue,
         bytes data
     );
+
+    /**
+     * @notice logs a merkle branch for proof synthesis
+     * @param reserved an index meant only to align the 4th index with L2ToL1Transaction's 4th event
+     * @param hash the merkle hash
+     * @param position = (level << 192) + leaf
+     */
+    event SendMerkleUpdate(uint256 indexed reserved, bytes32 indexed hash, uint256 indexed position);
 }

+ 76 - 34
contracts/vendor/arbitrum/IBridge.sol

@@ -1,23 +1,9 @@
-// SPDX-License-Identifier: Apache-2.0
-// OpenZeppelin Contracts (last updated v4.6.0) (vendor/arbitrum/IBridge.sol)
-
-/*
- * Copyright 2021, Offchain Labs, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-pragma solidity ^0.8.0;
+// Copyright 2021-2022, Offchain Labs, Inc.
+// For license information, see https://github.com/nitro/blob/master/LICENSE
+// SPDX-License-Identifier: BUSL-1.1
+
+// solhint-disable-next-line compiler-version
+pragma solidity >=0.6.9 <0.9.0;
 
 interface IBridge {
     event MessageDelivered(
@@ -26,41 +12,97 @@ interface IBridge {
         address inbox,
         uint8 kind,
         address sender,
-        bytes32 messageDataHash
+        bytes32 messageDataHash,
+        uint256 baseFeeL1,
+        uint64 timestamp
     );
 
-    event BridgeCallTriggered(address indexed outbox, address indexed destAddr, uint256 amount, bytes data);
+    event BridgeCallTriggered(address indexed outbox, address indexed to, uint256 value, bytes data);
 
     event InboxToggle(address indexed inbox, bool enabled);
 
     event OutboxToggle(address indexed outbox, bool enabled);
 
-    function deliverMessageToInbox(
+    event SequencerInboxUpdated(address newSequencerInbox);
+
+    function allowedDelayedInboxList(uint256) external returns (address);
+
+    function allowedOutboxList(uint256) external returns (address);
+
+    /// @dev Accumulator for delayed inbox messages; tail represents hash of the current state; each element represents the inclusion of a new message.
+    function delayedInboxAccs(uint256) external view returns (bytes32);
+
+    /// @dev Accumulator for sequencer inbox messages; tail represents hash of the current state; each element represents the inclusion of a new message.
+    function sequencerInboxAccs(uint256) external view returns (bytes32);
+
+    // OpenZeppelin: changed return type from IOwnable
+    function rollup() external view returns (address);
+
+    function sequencerInbox() external view returns (address);
+
+    function activeOutbox() external view returns (address);
+
+    function allowedDelayedInboxes(address inbox) external view returns (bool);
+
+    function allowedOutboxes(address outbox) external view returns (bool);
+
+    function sequencerReportedSubMessageCount() external view returns (uint256);
+
+    /**
+     * @dev Enqueue a message in the delayed inbox accumulator.
+     *      These messages are later sequenced in the SequencerInbox, either
+     *      by the sequencer as part of a normal batch, or by force inclusion.
+     */
+    function enqueueDelayedMessage(
         uint8 kind,
         address sender,
         bytes32 messageDataHash
     ) external payable returns (uint256);
 
     function executeCall(
-        address destAddr,
-        uint256 amount,
+        address to,
+        uint256 value,
         bytes calldata data
     ) external returns (bool success, bytes memory returnData);
 
-    // These are only callable by the admin
-    function setInbox(address inbox, bool enabled) external;
+    function delayedMessageCount() external view returns (uint256);
 
-    function setOutbox(address inbox, bool enabled) external;
+    function sequencerMessageCount() external view returns (uint256);
 
-    // View functions
+    // ---------- onlySequencerInbox functions ----------
 
-    function activeOutbox() external view returns (address);
+    function enqueueSequencerMessage(
+        bytes32 dataHash,
+        uint256 afterDelayedMessagesRead,
+        uint256 prevMessageCount,
+        uint256 newMessageCount
+    )
+        external
+        returns (
+            uint256 seqMessageIndex,
+            bytes32 beforeAcc,
+            bytes32 delayedAcc,
+            bytes32 acc
+        );
 
-    function allowedInboxes(address inbox) external view returns (bool);
+    /**
+     * @dev Allows the sequencer inbox to submit a delayed message of the batchPostingReport type
+     *      This is done through a separate function entrypoint instead of allowing the sequencer inbox
+     *      to call `enqueueDelayedMessage` to avoid the gas overhead of an extra SLOAD in either
+     *      every delayed inbox or every sequencer inbox call.
+     */
+    function submitBatchSpendingReport(address batchPoster, bytes32 dataHash) external returns (uint256 msgNum);
 
-    function allowedOutboxes(address outbox) external view returns (bool);
+    // ---------- onlyRollupOrOwner functions ----------
+
+    function setSequencerInbox(address _sequencerInbox) external;
+
+    function setDelayedInbox(address inbox, bool enabled) external;
+
+    function setOutbox(address inbox, bool enabled) external;
 
-    function inboxAccs(uint256 index) external view returns (bytes32);
+    // ---------- initializer ----------
 
-    function messageCount() external view returns (uint256);
+    // OpenZeppelin: changed rollup_ type from IOwnable
+    function initialize(address rollup_) external;
 }

+ 15 - 0
contracts/vendor/arbitrum/IDelayedMessageProvider.sol

@@ -0,0 +1,15 @@
+// Copyright 2021-2022, Offchain Labs, Inc.
+// For license information, see https://github.com/nitro/blob/master/LICENSE
+// SPDX-License-Identifier: BUSL-1.1
+
+// solhint-disable-next-line compiler-version
+pragma solidity >=0.6.9 <0.9.0;
+
+interface IDelayedMessageProvider {
+    /// @dev event emitted when a inbox message is added to the Bridge's delayed accumulator
+    event InboxMessageDelivered(uint256 indexed messageNum, bytes data);
+
+    /// @dev event emitted when a inbox message is added to the Bridge's delayed accumulator
+    /// same as InboxMessageDelivered but the batch data is available in tx.input
+    event InboxMessageDeliveredFromOrigin(uint256 indexed messageNum);
+}

+ 124 - 65
contracts/vendor/arbitrum/IInbox.sol

@@ -1,92 +1,151 @@
-// SPDX-License-Identifier: Apache-2.0
-// OpenZeppelin Contracts (last updated v4.6.0) (vendor/arbitrum/IInbox.sol)
-
-/*
- * Copyright 2021, Offchain Labs, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-pragma solidity ^0.8.0;
-
-import "./IMessageProvider.sol";
-
-interface IInbox is IMessageProvider {
+// Copyright 2021-2022, Offchain Labs, Inc.
+// For license information, see https://github.com/nitro/blob/master/LICENSE
+// SPDX-License-Identifier: BUSL-1.1
+
+// solhint-disable-next-line compiler-version
+pragma solidity >=0.6.9 <0.9.0;
+
+import "./IBridge.sol";
+import "./IDelayedMessageProvider.sol";
+
+interface IInbox is IDelayedMessageProvider {
+    function bridge() external view returns (IBridge);
+
+    // OpenZeppelin: changed return type from ISequencerInbox
+    function sequencerInbox() external view returns (address);
+
+    /**
+     * @notice Send a generic L2 message to the chain
+     * @dev This method is an optimization to avoid having to emit the entirety of the messageData in a log. Instead validators are expected to be able to parse the data from the transaction's input
+     * @param messageData Data of the message being sent
+     */
+    function sendL2MessageFromOrigin(bytes calldata messageData) external returns (uint256);
+
+    /**
+     * @notice Send a generic L2 message to the chain
+     * @dev This method can be used to send any type of message that doesn't require L1 validation
+     * @param messageData Data of the message being sent
+     */
     function sendL2Message(bytes calldata messageData) external returns (uint256);
 
-    function sendUnsignedTransaction(
-        uint256 maxGas,
-        uint256 gasPriceBid,
+    function sendL1FundedUnsignedTransaction(
+        uint256 gasLimit,
+        uint256 maxFeePerGas,
         uint256 nonce,
-        address destAddr,
-        uint256 amount,
+        address to,
         bytes calldata data
-    ) external returns (uint256);
+    ) external payable returns (uint256);
 
-    function sendContractTransaction(
-        uint256 maxGas,
-        uint256 gasPriceBid,
-        address destAddr,
-        uint256 amount,
+    function sendL1FundedContractTransaction(
+        uint256 gasLimit,
+        uint256 maxFeePerGas,
+        address to,
         bytes calldata data
-    ) external returns (uint256);
+    ) external payable returns (uint256);
 
-    function sendL1FundedUnsignedTransaction(
-        uint256 maxGas,
-        uint256 gasPriceBid,
+    function sendUnsignedTransaction(
+        uint256 gasLimit,
+        uint256 maxFeePerGas,
         uint256 nonce,
-        address destAddr,
+        address to,
+        uint256 value,
         bytes calldata data
-    ) external payable returns (uint256);
+    ) external returns (uint256);
 
-    function sendL1FundedContractTransaction(
-        uint256 maxGas,
-        uint256 gasPriceBid,
-        address destAddr,
+    function sendContractTransaction(
+        uint256 gasLimit,
+        uint256 maxFeePerGas,
+        address to,
+        uint256 value,
         bytes calldata data
-    ) external payable returns (uint256);
+    ) external returns (uint256);
 
+    /**
+     * @notice Get the L1 fee for submitting a retryable
+     * @dev This fee can be paid by funds already in the L2 aliased address or by the current message value
+     * @dev This formula may change in the future, to future proof your code query this method instead of inlining!!
+     * @param dataLength The length of the retryable's calldata, in bytes
+     * @param baseFee The block basefee when the retryable is included in the chain, if 0 current block.basefee will be used
+     */
+    function calculateRetryableSubmissionFee(uint256 dataLength, uint256 baseFee) external view returns (uint256);
+
+    /**
+     * @notice Deposit eth from L1 to L2 to address of the sender if sender is an EOA, and to its aliased address if the sender is a contract
+     * @dev This does not trigger the fallback function when receiving in the L2 side.
+     *      Look into retryable tickets if you are interested in this functionality.
+     * @dev This function should not be called inside contract constructors
+     */
+    function depositEth() external payable returns (uint256);
+
+    /**
+     * @notice Put a message in the L2 inbox that can be reexecuted for some fixed amount of time if it reverts
+     * @dev all msg.value will deposited to callValueRefundAddress on L2
+     * @dev Gas limit and maxFeePerGas should not be set to 1 as that is used to trigger the RetryableData error
+     * @param to destination L2 contract address
+     * @param l2CallValue call value for retryable L2 message
+     * @param maxSubmissionCost Max gas deducted from user's L2 balance to cover base submission fee
+     * @param excessFeeRefundAddress gasLimit x maxFeePerGas - execution cost gets credited here on L2 balance
+     * @param callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled
+     * @param gasLimit Max gas deducted from user's L2 balance to cover L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)
+     * @param maxFeePerGas price bid for L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)
+     * @param data ABI encoded data of L2 message
+     * @return unique message number of the retryable transaction
+     */
     function createRetryableTicket(
-        address destAddr,
-        uint256 arbTxCallValue,
+        address to,
+        uint256 l2CallValue,
         uint256 maxSubmissionCost,
-        address submissionRefundAddress,
-        address valueRefundAddress,
-        uint256 maxGas,
-        uint256 gasPriceBid,
+        address excessFeeRefundAddress,
+        address callValueRefundAddress,
+        uint256 gasLimit,
+        uint256 maxFeePerGas,
         bytes calldata data
     ) external payable returns (uint256);
 
-    function createRetryableTicketNoRefundAliasRewrite(
-        address destAddr,
-        uint256 arbTxCallValue,
+    /**
+     * @notice Put a message in the L2 inbox that can be reexecuted for some fixed amount of time if it reverts
+     * @dev Same as createRetryableTicket, but does not guarantee that submission will succeed by requiring the needed funds
+     * come from the deposit alone, rather than falling back on the user's L2 balance
+     * @dev Advanced usage only (does not rewrite aliases for excessFeeRefundAddress and callValueRefundAddress).
+     * createRetryableTicket method is the recommended standard.
+     * @dev Gas limit and maxFeePerGas should not be set to 1 as that is used to trigger the RetryableData error
+     * @param to destination L2 contract address
+     * @param l2CallValue call value for retryable L2 message
+     * @param maxSubmissionCost Max gas deducted from user's L2 balance to cover base submission fee
+     * @param excessFeeRefundAddress gasLimit x maxFeePerGas - execution cost gets credited here on L2 balance
+     * @param callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled
+     * @param gasLimit Max gas deducted from user's L2 balance to cover L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)
+     * @param maxFeePerGas price bid for L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)
+     * @param data ABI encoded data of L2 message
+     * @return unique message number of the retryable transaction
+     */
+    function unsafeCreateRetryableTicket(
+        address to,
+        uint256 l2CallValue,
         uint256 maxSubmissionCost,
-        address submissionRefundAddress,
-        address valueRefundAddress,
-        uint256 maxGas,
-        uint256 gasPriceBid,
+        address excessFeeRefundAddress,
+        address callValueRefundAddress,
+        uint256 gasLimit,
+        uint256 maxFeePerGas,
         bytes calldata data
     ) external payable returns (uint256);
 
-    function depositEth(uint256 maxSubmissionCost) external payable returns (uint256);
+    // ---------- onlyRollupOrOwner functions ----------
 
-    function bridge() external view returns (address);
+    /// @notice pauses all inbox functionality
+    function pause() external;
 
-    function pauseCreateRetryables() external;
+    /// @notice unpauses all inbox functionality
+    function unpause() external;
 
-    function unpauseCreateRetryables() external;
+    // ---------- initializer ----------
 
-    function startRewriteAddress() external;
+    /**
+     * @dev function to be called one time during the inbox upgrade process
+     *      this is used to fix the storage slots
+     */
+    function postUpgradeInit(IBridge _bridge) external;
 
-    function stopRewriteAddress() external;
+    // OpenZeppelin: changed _sequencerInbox type from ISequencerInbox
+    function initialize(IBridge _bridge, address _sequencerInbox) external;
 }

+ 0 - 26
contracts/vendor/arbitrum/IMessageProvider.sol

@@ -1,26 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-// OpenZeppelin Contracts (last updated v4.6.0) (vendor/arbitrum/IMessageProvider.sol)
-
-/*
- * Copyright 2021, Offchain Labs, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-pragma solidity ^0.8.0;
-
-interface IMessageProvider {
-    event InboxMessageDelivered(uint256 indexed messageNum, bytes data);
-
-    event InboxMessageDeliveredFromOrigin(uint256 indexed messageNum);
-}

+ 101 - 32
contracts/vendor/arbitrum/IOutbox.sol

@@ -1,51 +1,120 @@
-// SPDX-License-Identifier: Apache-2.0
-// OpenZeppelin Contracts (last updated v4.6.0) (vendor/arbitrum/IOutbox.sol)
-
-/*
- * Copyright 2021, Offchain Labs, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-pragma solidity ^0.8.0;
+// Copyright 2021-2022, Offchain Labs, Inc.
+// For license information, see https://github.com/nitro/blob/master/LICENSE
+// SPDX-License-Identifier: BUSL-1.1
+
+// solhint-disable-next-line compiler-version
+pragma solidity >=0.6.9 <0.9.0;
+
+import "./IBridge.sol";
 
 interface IOutbox {
-    event OutboxEntryCreated(
-        uint256 indexed batchNum,
-        uint256 outboxEntryIndex,
-        bytes32 outputRoot,
-        uint256 numInBatch
-    );
+    event SendRootUpdated(bytes32 indexed blockHash, bytes32 indexed outputRoot);
     event OutBoxTransactionExecuted(
-        address indexed destAddr,
+        address indexed to,
         address indexed l2Sender,
-        uint256 indexed outboxEntryIndex,
+        uint256 indexed zero,
         uint256 transactionIndex
     );
 
+    function rollup() external view returns (address); // the rollup contract
+
+    function bridge() external view returns (IBridge); // the bridge contract
+
+    function spent(uint256) external view returns (bytes32); // packed spent bitmap
+
+    function roots(bytes32) external view returns (bytes32); // maps root hashes => L2 block hash
+
+    // solhint-disable-next-line func-name-mixedcase
+    function OUTBOX_VERSION() external view returns (uint128); // the outbox version
+
+    function updateSendRoot(bytes32 sendRoot, bytes32 l2BlockHash) external;
+
+    /// @notice When l2ToL1Sender returns a nonzero address, the message was originated by an L2 account
+    ///         When the return value is zero, that means this is a system message
+    /// @dev the l2ToL1Sender behaves as the tx.origin, the msg.sender should be validated to protect against reentrancies
     function l2ToL1Sender() external view returns (address);
 
+    /// @return l2Block return L2 block when the L2 tx was initiated or 0 if no L2 to L1 transaction is active
     function l2ToL1Block() external view returns (uint256);
 
+    /// @return l1Block return L1 block when the L2 tx was initiated or 0 if no L2 to L1 transaction is active
     function l2ToL1EthBlock() external view returns (uint256);
 
+    /// @return timestamp return L2 timestamp when the L2 tx was initiated or 0 if no L2 to L1 transaction is active
     function l2ToL1Timestamp() external view returns (uint256);
 
-    function l2ToL1BatchNum() external view returns (uint256);
-
+    /// @return outputId returns the unique output identifier of the L2 to L1 tx or 0 if no L2 to L1 transaction is active
     function l2ToL1OutputId() external view returns (bytes32);
 
-    function processOutgoingMessages(bytes calldata sendsData, uint256[] calldata sendLengths) external;
+    /**
+     * @notice Executes a messages in an Outbox entry.
+     * @dev Reverts if dispute period hasn't expired, since the outbox entry
+     *      is only created once the rollup confirms the respective assertion.
+     * @dev it is not possible to execute any L2-to-L1 transaction which contains data
+     *      to a contract address without any code (as enforced by the Bridge contract).
+     * @param proof Merkle proof of message inclusion in send root
+     * @param index Merkle path to message
+     * @param l2Sender sender if original message (i.e., caller of ArbSys.sendTxToL1)
+     * @param to destination address for L1 contract call
+     * @param l2Block l2 block number at which sendTxToL1 call was made
+     * @param l1Block l1 block number at which sendTxToL1 call was made
+     * @param l2Timestamp l2 Timestamp at which sendTxToL1 call was made
+     * @param value wei in L1 message
+     * @param data abi-encoded L1 message data
+     */
+    function executeTransaction(
+        bytes32[] calldata proof,
+        uint256 index,
+        address l2Sender,
+        address to,
+        uint256 l2Block,
+        uint256 l1Block,
+        uint256 l2Timestamp,
+        uint256 value,
+        bytes calldata data
+    ) external;
+
+    /**
+     *  @dev function used to simulate the result of a particular function call from the outbox
+     *       it is useful for things such as gas estimates. This function includes all costs except for
+     *       proof validation (which can be considered offchain as a somewhat of a fixed cost - it's
+     *       not really a fixed cost, but can be treated as so with a fixed overhead for gas estimation).
+     *       We can't include the cost of proof validation since this is intended to be used to simulate txs
+     *       that are included in yet-to-be confirmed merkle roots. The simulation entrypoint could instead pretend
+     *       to confirm a pending merkle root, but that would be less practical for integrating with tooling.
+     *       It is only possible to trigger it when the msg sender is address zero, which should be impossible
+     *       unless under simulation in an eth_call or eth_estimateGas
+     */
+    function executeTransactionSimulation(
+        uint256 index,
+        address l2Sender,
+        address to,
+        uint256 l2Block,
+        uint256 l1Block,
+        uint256 l2Timestamp,
+        uint256 value,
+        bytes calldata data
+    ) external;
+
+    /**
+     * @param index Merkle path to message
+     * @return true if the message has been spent
+     */
+    function isSpent(uint256 index) external view returns (bool);
+
+    function calculateItemHash(
+        address l2Sender,
+        address to,
+        uint256 l2Block,
+        uint256 l1Block,
+        uint256 l2Timestamp,
+        uint256 value,
+        bytes calldata data
+    ) external pure returns (bytes32);
 
-    function outboxEntryExists(uint256 batchNum) external view returns (bool);
+    function calculateMerkleRoot(
+        bytes32[] memory proof,
+        uint256 path,
+        bytes32 item
+    ) external pure returns (bytes32);
 }

+ 21 - 0
docs/config.js

@@ -0,0 +1,21 @@
+const path = require('path');
+const fs = require('fs');
+
+/** @type import('solidity-docgen/dist/config').UserConfig */
+module.exports = {
+  outputDir: 'docs/modules/api/pages',
+  templates: 'docs/templates',
+  exclude: ['mocks'],
+  pageExtension: '.adoc',
+  pages: (_, file, config) => {
+    // For each contract file, find the closest README.adoc and return its location as the output page path.
+    const sourcesDir = path.resolve(config.root, config.sourcesDir);
+    let dir = path.resolve(config.root, file.absolutePath);
+    while (dir.startsWith(sourcesDir)) {
+      dir = path.dirname(dir);
+      if (fs.existsSync(path.join(dir, 'README.adoc'))) {
+        return path.relative(sourcesDir, dir) + config.pageExtension;
+      }
+    }
+  },
+};

+ 0 - 91
docs/contract.hbs

@@ -1,91 +0,0 @@
-{{~#*inline "typed-variable-array"~}}
-{{#each .}}{{typeName}}{{#if name}} {{name}}{{/if}}{{#unless @last}}, {{/unless}}{{/each}}
-{{~/inline~}}
-
-{{#each linkable}}
-:{{name}}: pass:normal[xref:#{{anchor}}[`++{{name}}++`]]
-{{/each}}
-
-[.contract]
-[[{{anchor}}]]
-=== `++{{name}}++` link:{{github-link file.path}}[{github-icon},role=heading-link]
-
-[.hljs-theme-light.nopadding]
-```solidity
-import "@openzeppelin/contracts/{{file.path}}";
-```
-
-{{natspec.devdoc}}
-
-{{#if ownModifiers}}
-[.contract-index]
-.Modifiers
---
-{{#each ownModifiers}}
-* {xref-{{slug anchor~}} }[`++{{name}}({{args.names}})++`]
-{{/each}}
---
-{{/if}}
-
-{{#if functions}}
-[.contract-index]
-.Functions
---
-{{#each inheritedItems}}
-{{#if (or @first (ne contract.name "Context"))}}
-{{#unless @first}}
-[.contract-subindex-inherited]
-.{{contract.name}}
-{{/unless}}
-{{#each functions}}
-* {xref-{{slug anchor~}} }[`++{{name}}({{args.names}})++`]
-{{/each}}
-
-{{/if}}
-{{/each}}
---
-{{/if}}
-
-{{#if events}}
-[.contract-index]
-.Events
---
-{{#each inheritedItems}}
-{{#unless @first}}
-[.contract-subindex-inherited]
-.{{contract.name}}
-{{/unless}}
-{{#each events}}
-* {xref-{{slug anchor~}} }[`++{{name}}({{args.names}})++`]
-{{/each}}
-
-{{/each}}
---
-{{/if}}
-
-{{#each ownModifiers}}
-[.contract-item]
-[[{{anchor}}]]
-==== `[.contract-item-name]#++{{name}}++#++({{> typed-variable-array args}})++` [.item-kind]#modifier#
-
-{{natspec.devdoc}}
-
-{{/each}}
-
-{{#each ownFunctions}}
-[.contract-item]
-[[{{anchor}}]]
-==== `[.contract-item-name]#++{{name}}++#++({{> typed-variable-array args}}){{#if outputs}} → {{> typed-variable-array outputs}}{{/if}}++` [.item-kind]#{{visibility}}#
-
-{{natspec.devdoc}}
-
-{{/each}}
-
-{{#each ownEvents}}
-[.contract-item]
-[[{{anchor}}]]
-==== `[.contract-item-name]#++{{name}}++#++({{> typed-variable-array args}})++` [.item-kind]#event#
-
-{{natspec.devdoc}}
-
-{{/each}}

+ 0 - 10
docs/helpers.js

@@ -1,10 +0,0 @@
-const { version } = require('../package.json');
-
-module.exports = {
-  'github-link': (contractPath) => {
-    if (typeof contractPath !== 'string') {
-      throw new Error('Missing argument');
-    }
-    return `https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v${version}/contracts/${contractPath}`;
-  },
-};

+ 1 - 1
docs/modules/ROOT/pages/access-control.adoc

@@ -39,7 +39,7 @@ WARNING: Removing the owner altogether will mean that administrative tasks that
 
 Note that *a contract can also be the owner of another one*! This opens the door to using, for example, a https://gnosis-safe.io[Gnosis Safe], an https://aragon.org[Aragon DAO], or a totally custom contract that _you_ create.
 
-In this way you can use _composability_ to add additional layers of access control complexity to your contracts. Instead of having a single regular Ethereum account (Externally Owned Account, or EOA) as the owner, you could use a 2-of-3 multisig run by your project leads, for example. Prominent projects in the space, such as https://makerdao.com[MakerDAO], use systems similar to this one.
+In this way, you can use _composability_ to add additional layers of access control complexity to your contracts. Instead of having a single regular Ethereum account (Externally Owned Account, or EOA) as the owner, you could use a 2-of-3 multisig run by your project leads, for example. Prominent projects in the space, such as https://makerdao.com[MakerDAO], use systems similar to this one.
 
 [[role-based-access-control]]
 == Role-Based Access Control

+ 3 - 3
docs/modules/ROOT/pages/crosschain.adoc

@@ -82,7 +82,7 @@ Once the abstract cross-chain version of our token is ready we can easily specia
 
 This is done using one of the many `CrossChainEnabled` implementations.
 
-For example, if our token on xDai, and our governor on mainnet, we can use the https://docs.tokenbridge.net/amb-bridge/about-amb-bridge[AMB] bridge available on xDai at https://blockscout.com/xdai/mainnet/address/0x75Df5AF045d91108662D8080fD1FEFAd6aA0bb59[0x75Df5AF045d91108662D8080fD1FEFAd6aA0bb59]
+For example, if our token is on xDai, and our governor on mainnet, we can use the https://docs.tokenbridge.net/amb-bridge/about-amb-bridge[AMB] bridge available on xDai at https://blockscout.com/xdai/mainnet/address/0x75Df5AF045d91108662D8080fD1FEFAd6aA0bb59[0x75Df5AF045d91108662D8080fD1FEFAd6aA0bb59]
 
 [source,solidity]
 ----
@@ -116,11 +116,11 @@ When designing a contract with cross-chain support, it is essential to understan
 
 In this guide, we are particularly focusing on restricting access to a specific caller. This is usually done (as shown above) using `msg.sender` or `_msgSender()`. However, when going cross-chain, it is not just that simple. Even without considering possible bridge issues, it is important to keep in mind that the same address can correspond to very different entities when considering a multi-chain space. EOA wallets can only execute operations if the wallet's private-key signs the transaction. To our knowledge this is the case in all EVM chains, so a cross-chain message coming from such a wallet is arguably equivalent to a non-cross-chain message by the same wallet. The situation is however very different for smart contracts.
 
-Due to the way smart contract addresses are computed, and the fact that smart contracts on different chains live independent lives, you could have two very different contracts live at the same address on different chains. You could imagine two multisig wallets with different signers use the same address on different chains. You could also see a very basic smart wallet live on one chain at the same address as a full-fledge governor on another chain. Therefore, you should be careful that whenever you give permissions to a specific address, you control with chain this address can act from.
+Due to the way smart contract addresses are computed, and the fact that smart contracts on different chains live independent lives, you could have two very different contracts live at the same address on different chains. You could imagine two multisig wallets with different signers using the same address on different chains. You could also see a very basic smart wallet live on one chain at the same address as a full-fledged governor on another chain. Therefore, you should be careful that whenever you give permissions to a specific address, you control with chain this address can act from.
 
 == Going further with access control
 
-In previous example, we have both a `onlyOwner()` modifier and the `onlyCrossChainSender(owner)` mechanism. We didn't use the xref:access-control.adoc#ownership-and-ownable[`Ownable`] pattern because the ownership transfer mechanism in includes is not designed to work with the owner being a cross-chain entity. Unlike xref:access-control.adoc#ownership-and-ownable[`Ownable`], xref:access-control.adoc#role-based-access-control[`AccessControl`] is more effective at capturing the nuances and can effectivelly be used to build cross-chain-aware contracts.
+In the previous example, we have both an `onlyOwner()` modifier and the `onlyCrossChainSender(owner)` mechanism. We didn't use the xref:access-control.adoc#ownership-and-ownable[`Ownable`] pattern because the ownership transfer mechanism in includes is not designed to work with the owner being a cross-chain entity. Unlike xref:access-control.adoc#ownership-and-ownable[`Ownable`], xref:access-control.adoc#role-based-access-control[`AccessControl`] is more effective at capturing the nuances and can effectively be used to build cross-chain-aware contracts.
 
 Using xref:api:access.adoc#AccessControlCrossChain[`AccessControlCrossChain`] includes both the xref:api:access.adoc#AccessControl[`AccessControl`] core and the xref:api:crosschain.adoc#CrossChainEnabled[`CrossChainEnabled`] abstraction. It also includes some binding to make role management compatible with cross-chain operations.
 

+ 2 - 2
docs/modules/ROOT/pages/erc1155.adoc

@@ -24,9 +24,9 @@ In the spirit of the standard, we've also included batch operations in the non-s
 
 We'll use ERC1155 to track multiple items in our game, which will each have their own unique attributes. We mint all items to the deployer of the contract, which we can later transfer to players. Players are free to keep their tokens or trade them with other people as they see fit, as they would any other asset on the blockchain!  
 
-For simplicity we will mint all items in the constructor but you could add minting functionality to the contract to mint on demand to players. 
+For simplicity, we will mint all items in the constructor, but you could add minting functionality to the contract to mint on demand to players. 
 
-TIP: For an overview of minting mechanisms check out xref:erc20-supply.adoc[Creating ERC20 Supply].
+TIP: For an overview of minting mechanisms, check out xref:erc20-supply.adoc[Creating ERC20 Supply].
 
 Here's what a contract for tokenized items might look like:
 

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