From fc2d30a7616e59505950dd5274f6488a9dcad3eb Mon Sep 17 00:00:00 2001 From: MoNyAvA Date: Mon, 15 Dec 2025 15:04:07 +0100 Subject: [PATCH 01/33] chore: fix minor typos in specs (#6204) --- fv/specs/AccessControlDefaultAdminRules.spec | 2 +- fv/specs/ERC20Wrapper.spec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fv/specs/AccessControlDefaultAdminRules.spec b/fv/specs/AccessControlDefaultAdminRules.spec index bda5a7a0b31..3b52fe32cf1 100644 --- a/fv/specs/AccessControlDefaultAdminRules.spec +++ b/fv/specs/AccessControlDefaultAdminRules.spec @@ -71,7 +71,7 @@ invariant defaultAdminRoleAdminConsistency() └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ */ // Writing this as an invariant would be flagged by Certora as trivial. Writing it as a rule is just as valid: we -// verify the is true for any state of the storage +// verify this is true for any state of the storage rule ownerConsistency() { assert defaultAdmin() == owner(); } diff --git a/fv/specs/ERC20Wrapper.spec b/fv/specs/ERC20Wrapper.spec index 1535144a7ef..8716a944e67 100644 --- a/fv/specs/ERC20Wrapper.spec +++ b/fv/specs/ERC20Wrapper.spec @@ -65,7 +65,7 @@ invariant totalSupplyIsSmallerThanUnderlyingBalance() require sumOfUnderlyingBalancesLowerThanUnderlyingSupply(from, to); } preserved ERC20PermitHarness.burn(address from, uint256 amount) with (env e) { - // If someone can burn from the wrapper, than the invariant obviously doesn't hold. + // If someone can burn from the wrapper, then the invariant obviously doesn't hold. require from != currentContract; require sumOfUnderlyingBalancesLowerThanUnderlyingSupply(from, currentContract); } From bc9659f1bca84953651796d30d8ef9ca3f84be67 Mon Sep 17 00:00:00 2001 From: David Klank <155117116+davidjsonn@users.noreply.github.com> Date: Mon, 15 Dec 2025 16:10:03 +0200 Subject: [PATCH 02/33] fix(test): remove redundant nullish coalescing in ERC721 behavior tests (#6199) Co-authored-by: Hadrien Croubois --- test/token/ERC721/ERC721.behavior.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/token/ERC721/ERC721.behavior.js b/test/token/ERC721/ERC721.behavior.js index 63b4e19bece..22ad6dfef39 100644 --- a/test/token/ERC721/ERC721.behavior.js +++ b/test/token/ERC721/ERC721.behavior.js @@ -480,15 +480,13 @@ function shouldBehaveLikeERC721() { const itApproves = function () { it('sets the approval for the target address', async function () { - expect(await this.token.getApproved(tokenId)).to.equal(this.approved ?? this.approved); + expect(await this.token.getApproved(tokenId)).to.equal(this.approved); }); }; const itEmitsApprovalEvent = function () { it('emits an approval event', async function () { - await expect(this.tx) - .to.emit(this.token, 'Approval') - .withArgs(this.owner, this.approved ?? this.approved, tokenId); + await expect(this.tx).to.emit(this.token, 'Approval').withArgs(this.owner, this.approved, tokenId); }); }; From b1df0c25b3384cf49dc3cbcbc9e17bdaad30c95c Mon Sep 17 00:00:00 2001 From: kurahin Date: Mon, 15 Dec 2025 16:11:10 +0200 Subject: [PATCH 03/33] fix: _useNonce documentation in NoncesKeyed (#6198) --- contracts/utils/NoncesKeyed.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/utils/NoncesKeyed.sol b/contracts/utils/NoncesKeyed.sol index df9c5704bc9..c0c87ae877d 100644 --- a/contracts/utils/NoncesKeyed.sol +++ b/contracts/utils/NoncesKeyed.sol @@ -24,7 +24,7 @@ abstract contract NoncesKeyed is Nonces { /** * @dev Consumes the next unused nonce for an address and key. * - * Returns the current value without the key prefix. Consumed nonce is increased, so calling this function twice + * Returns the current value with the key prefix (i.e. the packed keyNonce). Consumed nonce is increased, so calling this function twice * with the same arguments will return different (sequential) results. */ function _useNonce(address owner, uint192 key) internal virtual returns (uint256) { From 566c3146e94e22ff383d364a454bd8e95e9909fb Mon Sep 17 00:00:00 2001 From: SashaMalysehko Date: Mon, 15 Dec 2025 16:16:31 +0200 Subject: [PATCH 04/33] fix: align EnumerableMap FV comments with invariants (#6190) --- fv/specs/EnumerableMap.spec | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fv/specs/EnumerableMap.spec b/fv/specs/EnumerableMap.spec index 99183e9ca7b..b171f5299a2 100644 --- a/fv/specs/EnumerableMap.spec +++ b/fv/specs/EnumerableMap.spec @@ -53,7 +53,7 @@ invariant indexedContained(uint256 index) /* ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ -│ Invariant: A value can only be stored at a single location │ +│ Invariant: A key can only be stored at a single location │ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ */ invariant atUniqueness(uint256 index1, uint256 index2) @@ -72,9 +72,9 @@ invariant atUniqueness(uint256 index1, uint256 index2) /* ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ -│ Invariant: index <> value relationship is consistent │ +│ Invariant: index <> key relationship is consistent │ │ │ -│ Note that the two consistencyXxx invariants, put together, prove that at_ and _positionOf are inverse of one │ +│ Note that the two consistencyXxx invariants, put together, prove that key_at and _positionOf are inverse of one │ │ another. This proves that we have a bijection between indices (the enumerability part) and keys (the entries that │ │ are set and removed from the EnumerableMap). │ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ From 7d2fc5f83259779f061e8ae1e961f4ca97d228d4 Mon Sep 17 00:00:00 2001 From: phrwlk Date: Mon, 15 Dec 2025 16:19:45 +0200 Subject: [PATCH 05/33] docs(governor): correct Natspec to reference ICompoundTimelock (#6114) --- .../governance/extensions/GovernorTimelockCompound.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/governance/extensions/GovernorTimelockCompound.sol b/contracts/governance/extensions/GovernorTimelockCompound.sol index 8f6183e8b89..bae571e7872 100644 --- a/contracts/governance/extensions/GovernorTimelockCompound.sol +++ b/contracts/governance/extensions/GovernorTimelockCompound.sol @@ -14,15 +14,15 @@ import {SafeCast} from "../../utils/math/SafeCast.sol"; * the admin of the timelock for any operation to be performed. A public, unrestricted, * {GovernorTimelockCompound-__acceptAdmin} is available to accept ownership of the timelock. * - * Using this model means the proposal will be operated by the {TimelockController} and not by the {Governor}. Thus, - * the assets and permissions must be attached to the {TimelockController}. Any asset sent to the {Governor} will be + * Using this model means the proposal will be operated by the {ICompoundTimelock} and not by the {Governor}. Thus, + * the assets and permissions must be attached to the {ICompoundTimelock}. Any asset sent to the {Governor} will be * inaccessible from a proposal, unless executed via {Governor-relay}. */ abstract contract GovernorTimelockCompound is Governor { ICompoundTimelock private _timelock; /** - * @dev Emitted when the timelock controller used for proposal execution is modified. + * @dev Emitted when the timelock used for proposal execution is modified. */ event TimelockChange(address oldTimelock, address newTimelock); From cbe95aa860915bfe37a68d7f08b3c490f051e73f Mon Sep 17 00:00:00 2001 From: Fibonacci747 Date: Mon, 15 Dec 2025 15:23:00 +0100 Subject: [PATCH 06/33] docs: remove legacy constructor visibility from upgradeable diff example (#6112) Co-authored-by: Hadrien Croubois --- docs/modules/ROOT/pages/upgradeable.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/modules/ROOT/pages/upgradeable.adoc b/docs/modules/ROOT/pages/upgradeable.adoc index 6d252d8fac7..4ab101048b4 100644 --- a/docs/modules/ROOT/pages/upgradeable.adoc +++ b/docs/modules/ROOT/pages/upgradeable.adoc @@ -33,7 +33,7 @@ NOTE: Interfaces and libraries are not included in the Upgradeable package, but Constructors are replaced by internal initializer functions following the naming convention `+__{ContractName}_init+`. Since these are internal, you must always define your own public initializer function and call the parent initializer of the contract you extend. ```diff -- constructor() ERC721("MyCollectible", "MCO") public { +- constructor() ERC721("MyCollectible", "MCO") { + function initialize() initializer public { + __ERC721_init("MyCollectible", "MCO"); } @@ -74,4 +74,4 @@ You may notice that contracts use a struct with the `@custom:storage-location er Without namespaced storage, it isn't safe to simply add a state variable because it "shifts down" all of the state variables below in the inheritance chain. This makes the storage layouts incompatible, as explained in xref:upgrades-plugins::writing-upgradeable.adoc#modifying-your-contracts[Writing Upgradeable Contracts]. -The namespaced storage pattern used in the Upgradeable package allows us to freely add new state variables in the future without compromising the storage compatibility with existing deployments. It also allows changing the inheritance order with no impact on the resulting storage layout, as long as all inherited contracts use namespaced storage. \ No newline at end of file +The namespaced storage pattern used in the Upgradeable package allows us to freely add new state variables in the future without compromising the storage compatibility with existing deployments. It also allows changing the inheritance order with no impact on the resulting storage layout, as long as all inherited contracts use namespaced storage. From e0cdb249100cbce9f94e63d937e2184f2cfa7a67 Mon Sep 17 00:00:00 2001 From: Desant pivo Date: Fri, 19 Dec 2025 16:44:43 +0100 Subject: [PATCH 07/33] fix(docs): correct variable names in Math library example (#6213) --- docs/modules/ROOT/pages/utilities.adoc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/modules/ROOT/pages/utilities.adoc b/docs/modules/ROOT/pages/utilities.adoc index 2ed5ab254a0..a7a599eff4e 100644 --- a/docs/modules/ROOT/pages/utilities.adoc +++ b/docs/modules/ROOT/pages/utilities.adoc @@ -234,10 +234,10 @@ contract MyContract { using SignedMath for int256; function tryOperations(uint256 a, uint256 b) internal pure { - (bool succeededAdd, uint256 resultAdd) = x.tryAdd(y); - (bool succeededSub, uint256 resultSub) = x.trySub(y); - (bool succeededMul, uint256 resultMul) = x.tryMul(y); - (bool succeededDiv, uint256 resultDiv) = x.tryDiv(y); + (bool succeededAdd, uint256 resultAdd) = a.tryAdd(b); + (bool succeededSub, uint256 resultSub) = a.trySub(b); + (bool succeededMul, uint256 resultMul) = a.tryMul(b); + (bool succeededDiv, uint256 resultDiv) = a.tryDiv(b); // ... } From 220d8fdd0a3ac0094538790685b3cf5fe3315517 Mon Sep 17 00:00:00 2001 From: Azzurra Moore Date: Sat, 20 Dec 2025 03:46:20 +1200 Subject: [PATCH 08/33] perf: defer signer() read in SignerECDSA (#6211) --- contracts/utils/cryptography/signers/SignerECDSA.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/utils/cryptography/signers/SignerECDSA.sol b/contracts/utils/cryptography/signers/SignerECDSA.sol index 609634dcab8..f3c254c2e4d 100644 --- a/contracts/utils/cryptography/signers/SignerECDSA.sol +++ b/contracts/utils/cryptography/signers/SignerECDSA.sol @@ -51,6 +51,6 @@ abstract contract SignerECDSA is AbstractSigner { bytes calldata signature ) internal view virtual override returns (bool) { (address recovered, ECDSA.RecoverError err, ) = ECDSA.tryRecoverCalldata(hash, signature); - return signer() == recovered && err == ECDSA.RecoverError.NoError; + return err == ECDSA.RecoverError.NoError && signer() == recovered; } } From 16a82a1054956da20cac99577e1d8ef55a03f24c Mon Sep 17 00:00:00 2001 From: iPLAY888 <133153661+letmehateu@users.noreply.github.com> Date: Sun, 21 Dec 2025 19:16:07 +0300 Subject: [PATCH 09/33] docs(ERC20Burnable): Fix parameter name typo in burnFrom documentation (#6229) --- contracts/token/ERC20/extensions/ERC20Burnable.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/token/ERC20/extensions/ERC20Burnable.sol b/contracts/token/ERC20/extensions/ERC20Burnable.sol index 4d482d8ec83..03951ec4734 100644 --- a/contracts/token/ERC20/extensions/ERC20Burnable.sol +++ b/contracts/token/ERC20/extensions/ERC20Burnable.sol @@ -29,7 +29,7 @@ abstract contract ERC20Burnable is Context, ERC20 { * * Requirements: * - * - the caller must have allowance for ``accounts``'s tokens of at least + * - the caller must have allowance for `account`'s tokens of at least * `value`. */ function burnFrom(address account, uint256 value) public virtual { From cd69dc44143677f31cbc7cfbe3035927e4735694 Mon Sep 17 00:00:00 2001 From: andrewshab <152420261+andrewshab3@users.noreply.github.com> Date: Tue, 23 Dec 2025 09:19:33 +0100 Subject: [PATCH 10/33] docs: fix minor typo (#6236) --- contracts/crosschain/ERC7786Recipient.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/crosschain/ERC7786Recipient.sol b/contracts/crosschain/ERC7786Recipient.sol index 0035aee4b25..7048f008174 100644 --- a/contracts/crosschain/ERC7786Recipient.sol +++ b/contracts/crosschain/ERC7786Recipient.sol @@ -13,7 +13,7 @@ import {BitMaps} from "../utils/structs/BitMaps.sol"; * destination gateways. This contract leaves two functions unimplemented: * * * {_isAuthorizedGateway}, an internal getter used to verify whether an address is recognised by the contract as a - * valid ERC-7786 destination gateway. One or multiple gateway can be supported. Note that any malicious address for + * valid ERC-7786 destination gateway. One or multiple gateways can be supported. Note that any malicious address for * which this function returns true would be able to impersonate any account on any other chain sending any message. * * * {_processMessage}, the internal function that will be called with any message that has been validated. From f889b7dd959cdaa2e61e211dfbf23deff316704a Mon Sep 17 00:00:00 2001 From: sashaodessa <140454972+sashaodessa@users.noreply.github.com> Date: Tue, 23 Dec 2025 13:48:40 +0100 Subject: [PATCH 11/33] Fix minor typos in ShortStrings and RLP docs (#6238) --- contracts/utils/RLP.sol | 4 ++-- contracts/utils/ShortStrings.sol | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/utils/RLP.sol b/contracts/utils/RLP.sol index 8fa6c31bef3..14542cb7040 100644 --- a/contracts/utils/RLP.sol +++ b/contracts/utils/RLP.sol @@ -154,7 +154,7 @@ library RLP { * @dev Encode an address as an RLP item of fixed size (20 bytes). * * The address is encoded with its leading zeros (if it has any). If someone wants to encode the address as a scalar, - * they can cast it to an uint256 and then call the corresponding {encode} function. + * they can cast it to a uint256 and then call the corresponding {encode} function. */ function encode(address input) internal pure returns (bytes memory result) { assembly ("memory-safe") { @@ -166,7 +166,7 @@ library RLP { } /** - * @dev Encode an uint256 as an RLP scalar. + * @dev Encode a uint256 as an RLP scalar. * * Unlike {encode-bytes32-}, this function uses scalar encoding that removes the prefix zeros. */ diff --git a/contracts/utils/ShortStrings.sol b/contracts/utils/ShortStrings.sol index 79332317aad..f8675d2f889 100644 --- a/contracts/utils/ShortStrings.sol +++ b/contracts/utils/ShortStrings.sol @@ -47,7 +47,7 @@ library ShortStrings { /** * @dev Encode a string of at most 31 chars into a `ShortString`. * - * This will trigger a `StringTooLong` error is the input string is too long. + * This will trigger a `StringTooLong` error if the input string is too long. */ function toShortString(string memory str) internal pure returns (ShortString) { bytes memory bstr = bytes(str); From 775957bf6f62d9e04b82e581b2e331c2fe609003 Mon Sep 17 00:00:00 2001 From: forkfury Date: Sat, 27 Dec 2025 17:24:55 +0100 Subject: [PATCH 12/33] fix: remove redundant Context inheritance from ERC20Burnable (#6245) Co-authored-by: Hadrien Croubois --- contracts/token/ERC20/extensions/ERC20Burnable.sol | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contracts/token/ERC20/extensions/ERC20Burnable.sol b/contracts/token/ERC20/extensions/ERC20Burnable.sol index 03951ec4734..3dffe6a6ab2 100644 --- a/contracts/token/ERC20/extensions/ERC20Burnable.sol +++ b/contracts/token/ERC20/extensions/ERC20Burnable.sol @@ -4,14 +4,13 @@ pragma solidity ^0.8.20; import {ERC20} from "../ERC20.sol"; -import {Context} from "../../../utils/Context.sol"; /** * @dev Extension of {ERC20} that allows token holders to destroy both their own * tokens and those that they have an allowance for, in a way that can be * recognized off-chain (via event analysis). */ -abstract contract ERC20Burnable is Context, ERC20 { +abstract contract ERC20Burnable is ERC20 { /** * @dev Destroys a `value` amount of tokens from the caller. * From 9e839d12b24992fba41c9a654caeb25ff1263707 Mon Sep 17 00:00:00 2001 From: emmmm <155267286+eeemmmmmm@users.noreply.github.com> Date: Wed, 31 Dec 2025 09:40:30 -0500 Subject: [PATCH 13/33] docs: add missing contract references to README files (#6201) --- contracts/finance/README.adoc | 3 +++ contracts/governance/README.adoc | 6 ++++++ contracts/utils/cryptography/README.adoc | 2 ++ 3 files changed, 11 insertions(+) diff --git a/contracts/finance/README.adoc b/contracts/finance/README.adoc index c855cbb6a99..efa63126ef1 100644 --- a/contracts/finance/README.adoc +++ b/contracts/finance/README.adoc @@ -8,7 +8,10 @@ This directory includes primitives for financial systems: - {VestingWallet} handles the vesting of Ether and ERC-20 tokens for a given beneficiary. Custody of multiple tokens can be given to this contract, which will release the token to the beneficiary following a given, customizable, vesting schedule. +- {VestingWalletCliff} is an extension of {VestingWallet} that adds a cliff to the vesting schedule. == Contracts {{VestingWallet}} + +{{VestingWalletCliff}} diff --git a/contracts/governance/README.adoc b/contracts/governance/README.adoc index 0901a5521da..8387864daa7 100644 --- a/contracts/governance/README.adoc +++ b/contracts/governance/README.adoc @@ -56,6 +56,8 @@ Other extensions can customize the behavior or interface in multiple ways. * {GovernorNoncesKeyed}: An extension of {Governor} with support for keyed nonces in addition to traditional nonces when voting by signature. +* {GovernorSequentialProposalId}: An extension of {Governor} that changes the numbering of proposal ids from the default hash-based approach to sequential ids. + In addition to modules and extensions, the core contract requires a few virtual functions to be implemented to your particular specifications: * <>: Delay (in ERC-6372 clock) since the proposal is submitted until voting power is fixed and voting starts. This can be used to enforce a delay after a proposal is published for users to buy tokens, or delegate their votes. @@ -104,8 +106,12 @@ NOTE: Functions of the `Governor` contract do not include access control. If you {{GovernorNoncesKeyed}} +{{GovernorSequentialProposalId}} + == Utils +{{IVotes}} + {{Votes}} {{VotesExtended}} diff --git a/contracts/utils/cryptography/README.adoc b/contracts/utils/cryptography/README.adoc index 66c47d12675..706ec45f7de 100644 --- a/contracts/utils/cryptography/README.adoc +++ b/contracts/utils/cryptography/README.adoc @@ -61,6 +61,8 @@ A collection of contracts and libraries that implement various signature validat {{SignerEIP7702}} +{{SignerWebAuthn}} + {{SignerERC7913}} {{MultiSignerERC7913}} From 750453e0fbd2112075ee402823ee362227b09c0d Mon Sep 17 00:00:00 2001 From: iPLAY888 <133153661+letmehateu@users.noreply.github.com> Date: Mon, 5 Jan 2026 16:29:36 +0300 Subject: [PATCH 14/33] docs(governance): fix ethers.js v5 API usage in code example (#6248) --- docs/modules/ROOT/pages/governance.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/governance.adoc b/docs/modules/ROOT/pages/governance.adoc index 37081d42233..f3b3f7729df 100644 --- a/docs/modules/ROOT/pages/governance.adoc +++ b/docs/modules/ROOT/pages/governance.adoc @@ -152,7 +152,7 @@ If a timelock was set up, the first step to execution is queueing. You will noti To queue, we call the queue function: ```javascript -const descriptionHash = ethers.utils.id(“Proposal #1: Give grant to team”); +const descriptionHash = ethers.id(“Proposal #1: Give grant to team”); await governor.queue( [tokenAddress], From 0ecef0b9d5b934b77ca05d95e25d47477ffcec1d Mon Sep 17 00:00:00 2001 From: andrewshab <152420261+andrewshab3@users.noreply.github.com> Date: Wed, 7 Jan 2026 11:26:34 +0100 Subject: [PATCH 15/33] docs: fix typo in ERC1155 example contract name (#6265) Co-authored-by: Hadrien Croubois --- ...MyERC115HolderContract.sol => MyERC1155HolderContract.sol} | 4 ++-- docs/modules/ROOT/pages/erc1155.adoc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename contracts/mocks/docs/token/ERC1155/{MyERC115HolderContract.sol => MyERC1155HolderContract.sol} (59%) diff --git a/contracts/mocks/docs/token/ERC1155/MyERC115HolderContract.sol b/contracts/mocks/docs/token/ERC1155/MyERC1155HolderContract.sol similarity index 59% rename from contracts/mocks/docs/token/ERC1155/MyERC115HolderContract.sol rename to contracts/mocks/docs/token/ERC1155/MyERC1155HolderContract.sol index 742a53ba4a6..2c837c97d20 100644 --- a/contracts/mocks/docs/token/ERC1155/MyERC115HolderContract.sol +++ b/contracts/mocks/docs/token/ERC1155/MyERC1155HolderContract.sol @@ -1,7 +1,7 @@ -// contracts/MyERC115HolderContract.sol +// contracts/MyERC1155HolderContract.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {ERC1155Holder} from "../../../../token/ERC1155/utils/ERC1155Holder.sol"; -contract MyERC115HolderContract is ERC1155Holder {} +contract MyERC1155HolderContract is ERC1155Holder {} diff --git a/docs/modules/ROOT/pages/erc1155.adoc b/docs/modules/ROOT/pages/erc1155.adoc index 214c52cd322..1dede1b2cfc 100644 --- a/docs/modules/ROOT/pages/erc1155.adoc +++ b/docs/modules/ROOT/pages/erc1155.adoc @@ -112,7 +112,7 @@ In order for our contract to receive ERC-1155 tokens we can inherit from the con [source,solidity] ---- -include::api:example$token/ERC1155/MyERC115HolderContract.sol[] +include::api:example$token/ERC1155/MyERC1155HolderContract.sol[] ---- We can also implement more complex scenarios using the xref:api:token/ERC1155.adoc#IERC1155Receiver-onERC1155Received-address-address-uint256-uint256-bytes-[`onERC1155Received`] and xref:api:token/ERC1155.adoc#IERC1155Receiver-onERC1155BatchReceived-address-address-uint256---uint256---bytes-[`onERC1155BatchReceived`] functions. From 82efe00e55e9ab9b6ee9512c4ab189d3eb2b09bb Mon Sep 17 00:00:00 2001 From: viktorking7 <140458814+viktorking7@users.noreply.github.com> Date: Tue, 13 Jan 2026 20:30:10 +0100 Subject: [PATCH 16/33] Remove duplicate call in `VestingWalletCliff` constructor (#6278) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Arr00 <13561405+arr00@users.noreply.github.com> Co-authored-by: Hadrien Croubois Co-authored-by: Ernesto García --- .github/actions/setup/action.yml | 102 +++++++++++-- .github/workflows/formal-verification.yml | 41 ++---- contracts/finance/VestingWalletCliff.sol | 5 +- .../token/ERC20/extensions/ERC20Wrapper.sol | 2 +- contracts/utils/cryptography/TrieProof.sol | 2 +- .../signers/MultiSignerERC7913.sol | 7 + foundry.toml | 4 +- hardhat.config.js | 7 +- package-lock.json | 134 ++++++++---------- package.json | 2 +- test/helpers/trie.js | 80 +++++++++++ test/utils/cryptography/P256.t.sol | 22 +-- test/utils/cryptography/RSA.test.js | 2 +- test/utils/cryptography/TrieProof.test.js | 55 +++---- 14 files changed, 280 insertions(+), 185 deletions(-) create mode 100644 test/helpers/trie.js diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 3e76d0c7e62..3f5b7db5699 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -1,22 +1,108 @@ name: Setup description: Common environment setup +inputs: + node: + description: Whether to set up node + required: false + default: 'on' # 'off' | 'on' | + foundry: + description: Whether to set up Foundry + required: false + default: 'on' # 'off' | 'on' | + java: + description: Whether to set up Java + required: false + default: 'off' # 'off' | 'on' | + python: + description: Whether to set up Python + required: false + default: 'off' # 'off' | 'on' | + python-requirements: + description: Path to Python requirements file (if python is true) + required: false + default: 'requirements.txt' + solc: + description: Whether to set up solc + required: false + default: 'off' # 'off' | 'on' | runs: using: composite steps: - - uses: actions/setup-node@v6 + - name: "Determine versions to install" + id: versions + shell: bash + run: | + ( + [[ "${{ inputs.node }}" = "on" ]] \ + && echo "node=$NODE_DEFAULT_VERSION" \ + || echo "node=${{ inputs.node }}" + [[ "${{ inputs.foundry }}" = "on" ]] \ + && echo "foundry=$FOUNDRY_DEFAULT_VERSION" \ + || echo "foundry=${{ inputs.foundry }}" + [[ "${{ inputs.java }}" = "on" ]] \ + && echo "java=$JAVA_DEFAULT_VERSION" \ + || echo "java=${{ inputs.java }}" + [[ "${{ inputs.python }}" = "on" ]] \ + && echo "python=$PYTHON_DEFAULT_VERSION" \ + || echo "python=${{ inputs.python }}" + [[ "${{ inputs.solc }}" = "on" ]] \ + && echo "solc=$SOLC_DEFAULT_VERSION" \ + || echo "solc=${{ inputs.solc }}" + ) > $GITHUB_OUTPUT + env: + NODE_DEFAULT_VERSION: "24.x" + FOUNDRY_DEFAULT_VERSION: "stable" + JAVA_DEFAULT_VERSION: "21" + PYTHON_DEFAULT_VERSION: "3.13" + SOLC_DEFAULT_VERSION: "0.8.31" + # Node & npm setup + - name: Install Node (${{ steps.versions.outputs.node }}) + if: inputs.node != 'off' + uses: actions/setup-node@v6 with: - node-version: 24.x - - uses: actions/cache@v5 + node-version: ${{ steps.versions.outputs.node }} + - name: Try fetch node modules from cache id: cache + if: inputs.node != 'off' + uses: actions/cache@v5 with: path: '**/node_modules' - key: npm-v3-${{ hashFiles('**/package-lock.json') }} + key: npm-${{ steps.versions.outputs.node }}-${{ hashFiles('**/package-lock.json') }} - name: Install dependencies - run: npm ci + if: inputs.node != 'off' && steps.cache.outputs.cache-hit != 'true' shell: bash - if: steps.cache.outputs.cache-hit != 'true' - - name: Install Foundry + run: npm ci + # Foundry setup + - name: Install Foundry (${{ steps.versions.outputs.foundry }}) + if: inputs.foundry != 'off' uses: foundry-rs/foundry-toolchain@v1 with: - version: stable + version: ${{ steps.versions.outputs.foundry }} + # Java setup + - name: Install java (${{ steps.versions.outputs.java }}) + if: ${{ inputs.java != 'off' }} + uses: actions/setup-java@v5 + with: + distribution: temurin + java-version: ${{ steps.versions.outputs.java }} + # Python setup + - name: Install python (${{ steps.versions.outputs.python }}) + if: inputs.python != 'off' + uses: actions/setup-python@v6 + with: + python-version: ${{ steps.versions.outputs.python }} + cache: 'pip' + cache-dependency-path: ${{ inputs.python-requirements }} + - name: Install python packages + if: inputs.python != 'off' + shell: bash + run: pip install -r ${{ inputs.python-requirements }} + # Solc setup + - name: Install solc (${{ steps.versions.outputs.solc }}) + if: inputs.solc != 'off' + shell: bash + run: | + wget -q https://github.com/argotorg/solidity/releases/download/v${{ steps.versions.outputs.solc }}/solc-static-linux + chmod +x solc-static-linux + sudo mv solc-static-linux /usr/local/bin/solc diff --git a/.github/workflows/formal-verification.yml b/.github/workflows/formal-verification.yml index b4f09e23ec4..f8a10cac91c 100644 --- a/.github/workflows/formal-verification.yml +++ b/.github/workflows/formal-verification.yml @@ -9,11 +9,6 @@ on: - labeled workflow_dispatch: {} -env: - PIP_VERSION: '3.11' - JAVA_VERSION: '11' - SOLC_VERSION: '0.8.27' - concurrency: ${{ github.workflow }}-${{ github.ref }} jobs: @@ -26,13 +21,16 @@ jobs: verify: runs-on: ubuntu-latest - if: github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'formal-verification') + if: github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'formal-verification') || contains(github.event.pull_request.labels.*.name, 'formal-verification-force-all') steps: - uses: actions/checkout@v6 - with: - fetch-depth: 0 - name: Set up environment uses: ./.github/actions/setup + with: + solc: 'on' + java: 'on' + python: 'on' + python-requirements: 'fv-requirements.txt' - name: identify specs that need to be run id: arguments run: | @@ -43,24 +41,6 @@ jobs: RESULT='--all' fi echo "result=$RESULT" >> "$GITHUB_OUTPUT" - - name: Install python - uses: actions/setup-python@v6 - with: - python-version: ${{ env.PIP_VERSION }} - cache: 'pip' - cache-dependency-path: 'fv-requirements.txt' - - name: Install python packages - run: pip install -r fv-requirements.txt - - name: Install java - uses: actions/setup-java@v5 - with: - distribution: temurin - java-version: ${{ env.JAVA_VERSION }} - - name: Install solc - run: | - wget https://github.com/ethereum/solidity/releases/download/v${{ env.SOLC_VERSION }}/solc-static-linux - sudo mv solc-static-linux /usr/local/bin/solc - chmod +x /usr/local/bin/solc - name: Verify specification run: | make -C fv apply @@ -74,14 +54,9 @@ jobs: - uses: actions/checkout@v6 - name: Set up environment uses: ./.github/actions/setup - - name: Install python - uses: actions/setup-python@v6 with: - python-version: ${{ env.PIP_VERSION }} - cache: 'pip' - cache-dependency-path: 'fv-requirements.txt' - - name: Install python packages - run: pip install -r fv-requirements.txt + python: 'on' + python-requirements: 'fv-requirements.txt' - name: Run Halmos run: halmos --match-test '^symbolic|^testSymbolic' -vv env: diff --git a/contracts/finance/VestingWalletCliff.sol b/contracts/finance/VestingWalletCliff.sol index dd1da6580bd..29ff3f4e98a 100644 --- a/contracts/finance/VestingWalletCliff.sol +++ b/contracts/finance/VestingWalletCliff.sol @@ -24,8 +24,9 @@ abstract contract VestingWalletCliff is VestingWallet { * constructor) and ends `cliffSeconds` later. */ constructor(uint64 cliffSeconds) { - if (cliffSeconds > duration()) { - revert InvalidCliffDuration(cliffSeconds, duration().toUint64()); + uint256 vestingDuration = duration(); + if (cliffSeconds > vestingDuration) { + revert InvalidCliffDuration(cliffSeconds, vestingDuration.toUint64()); } _cliff = start().toUint64() + cliffSeconds; } diff --git a/contracts/token/ERC20/extensions/ERC20Wrapper.sol b/contracts/token/ERC20/extensions/ERC20Wrapper.sol index 8916d1ab0ca..9efec93cf1a 100644 --- a/contracts/token/ERC20/extensions/ERC20Wrapper.sol +++ b/contracts/token/ERC20/extensions/ERC20Wrapper.sol @@ -27,7 +27,7 @@ abstract contract ERC20Wrapper is ERC20 { error ERC20InvalidUnderlying(address token); constructor(IERC20 underlyingToken) { - if (underlyingToken == this) { + if (address(underlyingToken) == address(this)) { revert ERC20InvalidUnderlying(address(this)); } _underlying = underlyingToken; diff --git a/contracts/utils/cryptography/TrieProof.sol b/contracts/utils/cryptography/TrieProof.sol index 676e9f9c340..15600876e1f 100644 --- a/contracts/utils/cryptography/TrieProof.sol +++ b/contracts/utils/cryptography/TrieProof.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.27; +pragma solidity ^0.8.26; import {Bytes} from "../Bytes.sol"; import {Memory} from "../Memory.sol"; diff --git a/contracts/utils/cryptography/signers/MultiSignerERC7913.sol b/contracts/utils/cryptography/signers/MultiSignerERC7913.sol index f485409bf28..7f8562eae79 100644 --- a/contracts/utils/cryptography/signers/MultiSignerERC7913.sol +++ b/contracts/utils/cryptography/signers/MultiSignerERC7913.sol @@ -114,6 +114,13 @@ abstract contract MultiSignerERC7913 is AbstractSigner { * * * Each of `newSigners` must be at least 20 bytes long. Reverts with {MultiSignerERC7913InvalidSigner} if not. * * Each of `newSigners` must not be authorized. See {isSigner}. Reverts with {MultiSignerERC7913AlreadyExists} if so. + * + * NOTE: This function does not validate that signers are controlled or represent appropriate entities. Integrators + * must ensure signers are properly validated before adding them. Problematic signers can compromise + * the multisig's security or functionality. Examples include uncontrolled addresses (e.g., `address(0)`), + * the account's own address (which may cause recursive validation loops), or contracts that may unintentionally + * allow arbitrary validation (e.g. using the identity precompile at `address(0x04)`, which would return the + * ERC-1271 magic value for any `isValidSignature` call). */ function _addSigners(bytes[] memory newSigners) internal virtual { for (uint256 i = 0; i < newSigners.length; ++i) { diff --git a/foundry.toml b/foundry.toml index b4d2de7ac87..3d9b8421ebc 100644 --- a/foundry.toml +++ b/foundry.toml @@ -1,6 +1,6 @@ [profile.default] -solc_version = '0.8.27' -evm_version = 'prague' +solc_version = '0.8.31' +evm_version = 'osaka' optimizer = true optimizer_runs = 200 src = 'contracts' diff --git a/hardhat.config.js b/hardhat.config.js index ca04c6c098b..c32c7977a99 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -1,5 +1,5 @@ /// ENVVAR -// - COMPILER: compiler version (default: 0.8.27) +// - COMPILER: compiler version (default: 0.8.31) // - SRC: contracts folder to compile (default: contracts) // - RUNS: number of optimization runs (default: 200) // - IR: enable IR compilation (default: false) @@ -18,7 +18,7 @@ const { argv } = require('yargs/yargs')() compiler: { alias: 'compileVersion', type: 'string', - default: '0.8.27', + default: '0.8.31', }, src: { alias: 'source', @@ -38,7 +38,7 @@ const { argv } = require('yargs/yargs')() evm: { alias: 'evmVersion', type: 'string', - default: 'prague', + default: 'osaka', }, // Extra modules coverage: { @@ -103,7 +103,6 @@ module.exports = { // we rely on the `code-size` compiler warning, that will cause a compilation error. allowUnlimitedContractSize: true, initialBaseFeePerGas: argv.coverage ? 0 : undefined, - enableRip7212: true, }, }, exposed: { diff --git a/package-lock.json b/package-lock.json index 73099e6e7a1..df9c08c8e58 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,7 +29,7 @@ "glob": "^13.0.0", "globals": "^16.0.0", "graphlib": "^2.1.8", - "hardhat": "^2.24.3", + "hardhat": "^2.28.0", "hardhat-exposed": "^0.3.15", "hardhat-gas-reporter": "^2.1.0", "hardhat-ignore-warnings": "^0.2.11", @@ -1828,92 +1828,92 @@ } }, "node_modules/@nomicfoundation/edr": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.11.3.tgz", - "integrity": "sha512-kqILRkAd455Sd6v8mfP3C1/0tCOynJWY+Ir+k/9Boocu2kObCrsFgG+ZWB7fSBVdd9cPVSNrnhWS+V+PEo637g==", + "version": "0.12.0-next.17", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.12.0-next.17.tgz", + "integrity": "sha512-Y8Kwqd5JpBmI/Kst6NJ/bZ81FeJea9J6WEwoSRTZnEvwfqW9dk9PI8zJs2UJpOACL1fXEPvN+doETbxT9EhwXA==", "dev": true, "license": "MIT", "dependencies": { - "@nomicfoundation/edr-darwin-arm64": "0.11.3", - "@nomicfoundation/edr-darwin-x64": "0.11.3", - "@nomicfoundation/edr-linux-arm64-gnu": "0.11.3", - "@nomicfoundation/edr-linux-arm64-musl": "0.11.3", - "@nomicfoundation/edr-linux-x64-gnu": "0.11.3", - "@nomicfoundation/edr-linux-x64-musl": "0.11.3", - "@nomicfoundation/edr-win32-x64-msvc": "0.11.3" + "@nomicfoundation/edr-darwin-arm64": "0.12.0-next.17", + "@nomicfoundation/edr-darwin-x64": "0.12.0-next.17", + "@nomicfoundation/edr-linux-arm64-gnu": "0.12.0-next.17", + "@nomicfoundation/edr-linux-arm64-musl": "0.12.0-next.17", + "@nomicfoundation/edr-linux-x64-gnu": "0.12.0-next.17", + "@nomicfoundation/edr-linux-x64-musl": "0.12.0-next.17", + "@nomicfoundation/edr-win32-x64-msvc": "0.12.0-next.17" }, "engines": { - "node": ">= 18" + "node": ">= 20" } }, "node_modules/@nomicfoundation/edr-darwin-arm64": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.11.3.tgz", - "integrity": "sha512-w0tksbdtSxz9nuzHKsfx4c2mwaD0+l5qKL2R290QdnN9gi9AV62p9DHkOgfBdyg6/a6ZlnQqnISi7C9avk/6VA==", + "version": "0.12.0-next.17", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.12.0-next.17.tgz", + "integrity": "sha512-gI9/9ysLeAid0+VSTBeutxOJ0/Rrh00niGkGL9+4lR577igDY+v55XGN0oBMST49ILS0f12J6ZY90LG8sxPXmQ==", "dev": true, "license": "MIT", "engines": { - "node": ">= 18" + "node": ">= 20" } }, "node_modules/@nomicfoundation/edr-darwin-x64": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.11.3.tgz", - "integrity": "sha512-QR4jAFrPbOcrO7O2z2ESg+eUeIZPe2bPIlQYgiJ04ltbSGW27FblOzdd5+S3RoOD/dsZGKAvvy6dadBEl0NgoA==", + "version": "0.12.0-next.17", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.12.0-next.17.tgz", + "integrity": "sha512-zSZtwf584RkIyb8awELDt7ctskogH0p4pmqOC4vhykc8ODOv2XLuG1IgeE4WgYhWGZOufbCtgLfpJQrWqN6mmw==", "dev": true, "license": "MIT", "engines": { - "node": ">= 18" + "node": ">= 20" } }, "node_modules/@nomicfoundation/edr-linux-arm64-gnu": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.11.3.tgz", - "integrity": "sha512-Ktjv89RZZiUmOFPspuSBVJ61mBZQ2+HuLmV67InNlh9TSUec/iDjGIwAn59dx0bF/LOSrM7qg5od3KKac4LJDQ==", + "version": "0.12.0-next.17", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.12.0-next.17.tgz", + "integrity": "sha512-WjdfgV6B7gT5Q0NXtSIWyeK8gzaJX5HK6/jclYVHarWuEtS1LFgePYgMjK8rmm7IRTkM9RsE/PCuQEP1nrSsuA==", "dev": true, "license": "MIT", "engines": { - "node": ">= 18" + "node": ">= 20" } }, "node_modules/@nomicfoundation/edr-linux-arm64-musl": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.11.3.tgz", - "integrity": "sha512-B3sLJx1rL2E9pfdD4mApiwOZSrX0a/KQSBWdlq1uAhFKqkl00yZaY4LejgZndsJAa4iKGQJlGnw4HCGeVt0+jA==", + "version": "0.12.0-next.17", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.12.0-next.17.tgz", + "integrity": "sha512-26rObKhhCDb9JkZbToyr7JVZo4tSVAFvzoJSJVmvpOl0LOHrfFsgVQu2n/8cNkwMAqulPubKL2E0jdnmEoZjWA==", "dev": true, "license": "MIT", "engines": { - "node": ">= 18" + "node": ">= 20" } }, "node_modules/@nomicfoundation/edr-linux-x64-gnu": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.11.3.tgz", - "integrity": "sha512-D/4cFKDXH6UYyKPu6J3Y8TzW11UzeQI0+wS9QcJzjlrrfKj0ENW7g9VihD1O2FvXkdkTjcCZYb6ai8MMTCsaVw==", + "version": "0.12.0-next.17", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.12.0-next.17.tgz", + "integrity": "sha512-dPkHScIf/CU6h6k3k4HNUnQyQcVSLKanviHCAcs5HkviiJPxvVtOMMvtNBxoIvKZRxGFxf2eutcqQW4ZV1wRQQ==", "dev": true, "license": "MIT", "engines": { - "node": ">= 18" + "node": ">= 20" } }, "node_modules/@nomicfoundation/edr-linux-x64-musl": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.11.3.tgz", - "integrity": "sha512-ergXuIb4nIvmf+TqyiDX5tsE49311DrBky6+jNLgsGDTBaN1GS3OFwFS8I6Ri/GGn6xOaT8sKu3q7/m+WdlFzg==", + "version": "0.12.0-next.17", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.12.0-next.17.tgz", + "integrity": "sha512-5Ixe/bpyWZxC3AjIb8EomAOK44ajemBVx/lZRHZiWSBlwQpbSWriYAtKjKcReQQPwuYVjnFpAD2AtuCvseIjHw==", "dev": true, "license": "MIT", "engines": { - "node": ">= 18" + "node": ">= 20" } }, "node_modules/@nomicfoundation/edr-win32-x64-msvc": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.11.3.tgz", - "integrity": "sha512-snvEf+WB3OV0wj2A7kQ+ZQqBquMcrozSLXcdnMdEl7Tmn+KDCbmFKBt3Tk0X3qOU4RKQpLPnTxdM07TJNVtung==", + "version": "0.12.0-next.17", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.12.0-next.17.tgz", + "integrity": "sha512-29YlvdgofSdXG1mUzIuH4kMXu1lmVc1hvYWUGWEH59L+LaakdhfJ/Wu5izeclKkrTh729Amtk/Hk1m29kFOO8A==", "dev": true, "license": "MIT", "engines": { - "node": ">= 18" + "node": ">= 20" } }, "node_modules/@nomicfoundation/hardhat-chai-matchers": { @@ -5520,16 +5520,16 @@ } }, "node_modules/hardhat": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.26.0.tgz", - "integrity": "sha512-hwEUBvMJzl3Iuru5bfMOEDeF2d7cbMNNF46rkwdo8AeW2GDT4VxFLyYWTi6PTLrZiftHPDiKDlAdAiGvsR9FYA==", + "version": "2.28.0", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.28.0.tgz", + "integrity": "sha512-A3yBISI18EcnY2IR7Ny2xZF33Q3qH01yrWapeWbyGOiJm/386SasWjbHRHYgUlZ3YWJETIMh7wYfMUaXrofTDQ==", "dev": true, "license": "MIT", "peer": true, "dependencies": { "@ethereumjs/util": "^9.1.0", "@ethersproject/abi": "^5.1.2", - "@nomicfoundation/edr": "^0.11.3", + "@nomicfoundation/edr": "0.12.0-next.17", "@nomicfoundation/solidity-analyzer": "^0.1.0", "@sentry/node": "^5.18.1", "adm-zip": "^0.4.16", @@ -5550,7 +5550,7 @@ "json-stream-stringify": "^3.1.4", "keccak": "^3.0.2", "lodash": "^4.17.11", - "micro-eth-signer": "^0.16.0", + "micro-eth-signer": "^0.14.0", "mnemonist": "^0.38.0", "mocha": "^10.0.0", "p-map": "^4.0.0", @@ -7375,28 +7375,25 @@ } }, "node_modules/micro-eth-signer": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/micro-eth-signer/-/micro-eth-signer-0.16.0.tgz", - "integrity": "sha512-rsSJcMGfY+kt3ROlL3U6y5BcjkK2H0zDKUQV6soo1JvjrctKKe+X7rKB0YIuwhWjlhJIoVHLuRYF+GXyyuVXxQ==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/micro-eth-signer/-/micro-eth-signer-0.14.0.tgz", + "integrity": "sha512-5PLLzHiVYPWClEvZIXXFu5yutzpadb73rnQCpUqIHu3No3coFuWQNfE5tkBQJ7djuLYl6aRLaS0MgWJYGoqiBw==", "dev": true, "license": "MIT", "dependencies": { - "@noble/curves": "~1.9.2", - "@noble/hashes": "2.0.0-beta.1", - "micro-packed": "~0.7.3" - }, - "engines": { - "node": ">= 20.19.0" + "@noble/curves": "~1.8.1", + "@noble/hashes": "~1.7.1", + "micro-packed": "~0.7.2" } }, "node_modules/micro-eth-signer/node_modules/@noble/curves": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.4.tgz", - "integrity": "sha512-2bKONnuM53lINoDrSmK8qP8W271ms7pygDhZt4SiLOoLwBtoHqeCFi6RG42V8zd3mLHuJFhU/Bmaqo4nX0/kBw==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.2.tgz", + "integrity": "sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g==", "dev": true, "license": "MIT", "dependencies": { - "@noble/hashes": "1.8.0" + "@noble/hashes": "1.7.2" }, "engines": { "node": "^14.21.3 || >=16" @@ -7405,27 +7402,14 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/micro-eth-signer/node_modules/@noble/curves/node_modules/@noble/hashes": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", - "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/micro-eth-signer/node_modules/@noble/hashes": { - "version": "2.0.0-beta.1", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.0.0-beta.1.tgz", - "integrity": "sha512-xnnogJ6ccNZ55lLgWdjhBqKUdFoznjpFr3oy23n5Qm7h+ZMtt8v4zWvHg9zRW6jcETweplD5F4iUqb0SSPC+Dw==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.2.tgz", + "integrity": "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ==", "dev": true, "license": "MIT", "engines": { - "node": ">= 20.19.0" + "node": "^14.21.3 || >=16" }, "funding": { "url": "https://paulmillr.com/funding/" diff --git a/package.json b/package.json index 6f2d411dd5b..478e5780348 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "glob": "^13.0.0", "globals": "^16.0.0", "graphlib": "^2.1.8", - "hardhat": "^2.24.3", + "hardhat": "^2.28.0", "hardhat-exposed": "^0.3.15", "hardhat-gas-reporter": "^2.1.0", "hardhat-ignore-warnings": "^0.2.11", diff --git a/test/helpers/trie.js b/test/helpers/trie.js new file mode 100644 index 00000000000..2ef6f6429a7 --- /dev/null +++ b/test/helpers/trie.js @@ -0,0 +1,80 @@ +const { ethers } = require('ethers'); +const { MerklePatriciaTrie, createMerkleProof } = require('@ethereumjs/mpt'); + +class BlockTries { + constructor(block) { + this.block = block; + + this.transactionTrie = new MerklePatriciaTrie(); + this.receiptTrie = new MerklePatriciaTrie(); + + this._ready = Promise.all( + block.transactions.map(hash => + block.getTransaction(hash).then(tx => + Promise.all([ + // Transaction + this.transactionTrie.put(BlockTries.indexToKeyBytes(tx.index), BlockTries.serializeTransaction(tx)), + // Receipt + tx + .wait() + .then(receipt => + this.receiptTrie.put(BlockTries.indexToKeyBytes(tx.index), BlockTries.serializeReceipt(receipt)), + ), + ]), + ), + ), + ).then(() => this); + } + + ready() { + return this._ready; + } + + getTransactionProof(index) { + return createMerkleProof(this.transactionTrie, BlockTries.indexToKeyBytes(index)); + } + + getReceiptProof(index) { + return createMerkleProof(this.receiptTrie, BlockTries.indexToKeyBytes(index)); + } + + get transactionTrieRoot() { + return ethers.hexlify(this.transactionTrie.root()); + } + + get receiptTrieRoot() { + return ethers.hexlify(this.receiptTrie.root()); + } + + static from(block) { + return new BlockTries(block); + } + + // Serialize a transaction into its RLP encoded form + static serializeTransaction(tx) { + return ethers.Transaction.from(tx).serialized; + } + + // Serialize a receipt into its RLP encoded form + static serializeReceipt(receipt) { + return ethers.concat([ + receipt.type === 0 ? '0x' : ethers.toBeHex(receipt.type), + ethers.encodeRlp([ + receipt.status === 0 ? '0x' : '0x01', + ethers.toBeHex(receipt.cumulativeGasUsed), + receipt.logsBloom, + receipt.logs.map(log => [log.address, log.topics, log.data]), + ]), + ]); + } + + static indexToKey(index) { + return ethers.encodeRlp(ethers.stripZerosLeft(ethers.toBeHex(index))); + } + + static indexToKeyBytes(index) { + return ethers.getBytes(BlockTries.indexToKey(index)); + } +} + +module.exports = { BlockTries }; diff --git a/test/utils/cryptography/P256.t.sol b/test/utils/cryptography/P256.t.sol index ee11b43edef..f144dadf109 100644 --- a/test/utils/cryptography/P256.t.sol +++ b/test/utils/cryptography/P256.t.sol @@ -16,6 +16,7 @@ contract P256Test is Test { (bytes32 r, bytes32 s) = vm.signP256(privateKey, digest); s = _ensureLowerS(s); assertTrue(P256.verify(digest, r, s, bytes32(x), bytes32(y))); + assertTrue(P256.verifyNative(digest, r, s, bytes32(x), bytes32(y))); assertTrue(P256.verifySolidity(digest, r, s, bytes32(x), bytes32(y))); } @@ -31,22 +32,6 @@ contract P256Test is Test { assertTrue((qx0 == bytes32(x) && qy0 == bytes32(y)) || (qx1 == bytes32(x) && qy1 == bytes32(y))); } - function testVerifyNativeUnsupportedRIP7212(bytes32 digest, uint256 seed) public { - // By default, the precompile at address 0x100 is not supported. - - uint256 privateKey = _asPrivateKey(seed); - - (uint256 x, uint256 y) = vm.publicKeyP256(privateKey); - (bytes32 r, bytes32 s) = vm.signP256(privateKey, digest); - s = _ensureLowerS(s); - - (bool success, bytes memory returndata) = address(this).call( - abi.encodeCall(P256Test.verifyNative, (digest, r, s, bytes32(x), bytes32(y))) - ); - assertFalse(success); - assertEq(returndata, abi.encodeWithSelector(Errors.MissingPrecompile.selector, address(0x100))); - } - function _asPrivateKey(uint256 seed) private pure returns (uint256) { return bound(seed, 1, P256.N - 1); } @@ -57,9 +42,4 @@ contract P256Test is Test { return _s > P256.N / 2 ? bytes32(P256.N - _s) : s; } } - - // See https://github.com/foundry-rs/foundry/issues/10237 - function verifyNative(bytes32 digest, bytes32 r, bytes32 s, bytes32 x, bytes32 y) external view { - P256.verifyNative(digest, r, s, x, y); - } } diff --git a/test/utils/cryptography/RSA.test.js b/test/utils/cryptography/RSA.test.js index bdf33911fe0..7ddf4d3a238 100644 --- a/test/utils/cryptography/RSA.test.js +++ b/test/utils/cryptography/RSA.test.js @@ -31,7 +31,7 @@ describe('RSA', function () { it(`signature length ${length} ${test.extra} ${result ? 'works' : 'fails'}`, async function () { const data = '0x' + test.Msg; const sig = '0x' + test.S; - const exp = '0x' + test.e; + const exp = ethers.stripZerosLeft('0x' + test.e); // strip zeros to reduce gas cost of the precompile const mod = '0x' + test.n; expect(await this.mock.$pkcs1Sha256(bytes32(ethers.sha256(data)), sig, exp, mod)).to.equal(result); diff --git a/test/utils/cryptography/TrieProof.test.js b/test/utils/cryptography/TrieProof.test.js index 78e961def20..98fc3aabb6f 100644 --- a/test/utils/cryptography/TrieProof.test.js +++ b/test/utils/cryptography/TrieProof.test.js @@ -1,11 +1,11 @@ const { ethers } = require('hardhat'); const { expect } = require('chai'); const { spawn } = require('child_process'); -const { MerklePatriciaTrie, createMerkleProof } = require('@ethereumjs/mpt'); const { Enum } = require('../../helpers/enums'); const { zip } = require('../../helpers/iterate'); const { generators } = require('../../helpers/random'); +const { BlockTries } = require('../../helpers/trie'); const { batchInBlock } = require('../../helpers/txpool'); const ProofError = Enum( @@ -82,44 +82,27 @@ describe('TrieProof', function () { false, ]); - // Rebuild tries - const transactionTrie = new MerklePatriciaTrie(); - const receiptTrie = new MerklePatriciaTrie(); - - for (const tx of txs) { - const key = ethers.encodeRlp(ethers.stripZerosLeft(ethers.toBeHex(tx.index))); - - // Transaction - const encodedTransaction = await tx.getTransaction().then(tx => ethers.Transaction.from(tx).serialized); - await transactionTrie.put(ethers.getBytes(key), encodedTransaction); - - // Receipt - const encodedReceipt = ethers.concat([ - tx.type === 0 ? '0x' : ethers.toBeHex(tx.type), - ethers.encodeRlp([ - tx.status === 0 ? '0x' : '0x01', - ethers.toBeHex(tx.cumulativeGasUsed), - tx.logsBloom, - tx.logs.map(log => [log.address, log.topics, log.data]), - ]), - ]); - await receiptTrie.put(ethers.getBytes(key), encodedReceipt); - - Object.assign(tx, { key, encodedTransaction, encodedReceipt }); - } + const blockTries = await this.provider + .getBlock(txs.at(0).blockNumber) + .then(block => BlockTries.from(block).ready()); // Sanity check trie roots - expect(ethers.hexlify(transactionTrie.root())).to.equal(transactionsRoot); - expect(ethers.hexlify(receiptTrie.root())).to.equal(receiptsRoot); + expect(blockTries.transactionTrieRoot).to.equal(transactionsRoot); + expect(blockTries.receiptTrieRoot).to.equal(receiptsRoot); - // Verify transaction inclusion in the block's transaction trie - for (const { key, encodedTransaction, encodedReceipt } of txs) { - const transactionProof = await createMerkleProof(transactionTrie, ethers.getBytes(key)); - await expect(this.mock.$verify(encodedTransaction, transactionsRoot, key, transactionProof)).to.eventually.be - .true; - - const receiptProof = await createMerkleProof(receiptTrie, ethers.getBytes(key)); - await expect(this.mock.$verify(encodedReceipt, receiptsRoot, key, receiptProof)).to.eventually.be.true; + for (const tx of txs) { + // verify transaction inclusion in the block's transaction trie + const transaction = await tx.getTransaction().then(BlockTries.serializeTransaction); + const transactionProof = await blockTries.getTransactionProof(tx.index); + await expect( + this.mock.$verify(transaction, transactionsRoot, BlockTries.indexToKey(tx.index), transactionProof), + ).to.eventually.be.true; + + // verify receipt inclusion in the block's receipt trie + const receipt = BlockTries.serializeReceipt(tx); + const receiptProof = await blockTries.getReceiptProof(tx.index); + await expect(this.mock.$verify(receipt, receiptsRoot, BlockTries.indexToKey(tx.index), receiptProof)).to + .eventually.be.true; } }); From 9ba3e0c6be8fe4cb049bc3afe7a4694017ac263a Mon Sep 17 00:00:00 2001 From: iPLAY888 <133153661+letmehateu@users.noreply.github.com> Date: Thu, 15 Jan 2026 19:05:10 +0300 Subject: [PATCH 17/33] docs:fix minor typo (#6222) Co-authored-by: Hadrien Croubois --- contracts/utils/structs/Heap.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/utils/structs/Heap.sol b/contracts/utils/structs/Heap.sol index 34fede1686a..e3b6682db6d 100644 --- a/contracts/utils/structs/Heap.sol +++ b/contracts/utils/structs/Heap.sol @@ -211,7 +211,7 @@ library Heap { uint256 rIndex = 2 * index + 2; // Three cases: - // 1. Both children exist: sifting may continue on one of the branch (selection required) + // 1. Both children exist: sifting may continue on one of the branches (selection required) // 2. Only left child exist: sifting may continue on the left branch (no selection required) // 3. Neither child exist: sifting is done if (rIndex < size) { From f6c342168bb1d7376c622f414f50b177f36420c0 Mon Sep 17 00:00:00 2001 From: maradini77 <140460067+maradini77@users.noreply.github.com> Date: Thu, 15 Jan 2026 17:06:31 +0100 Subject: [PATCH 18/33] fix: documentation typos in governance and FV guides (#6233) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Hadrien Croubois Co-authored-by: Ernesto García --- contracts/governance/README.adoc | 2 +- fv/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/governance/README.adoc b/contracts/governance/README.adoc index 8387864daa7..c4e3a8dac4b 100644 --- a/contracts/governance/README.adoc +++ b/contracts/governance/README.adoc @@ -7,7 +7,7 @@ This directory includes primitives for on-chain governance. == Governor -This modular system of Governor contracts allows the deployment on-chain voting protocols similar to https://compound.finance/docs/governance[Compound's Governor Alpha & Bravo] and beyond, through the ability to easily customize multiple aspects of the protocol. +This modular system of Governor contracts allows the deployment of on-chain voting protocols similar to https://compound.finance/docs/governance[Compound's Governor Alpha & Bravo] and beyond, through the ability to easily customize multiple aspects of the protocol. [TIP] ==== diff --git a/fv/README.md b/fv/README.md index fe582fe39f9..6709b838696 100644 --- a/fv/README.md +++ b/fv/README.md @@ -9,7 +9,7 @@ Documentation for CVT and the specification language is available [here](https:/ Follow the [Certora installation guide](https://docs.certora.com/en/latest/docs/user-guide/getting-started/install.html) in order to get the Certora Prover Package and the `solc` executable folder in your path. > **Note** -> An API Key is required for local testing. Although the prover will run on a GitHub Actions' CI environment on selected Pull Requests. +> An API Key is required for local testing. Although the prover will run in a GitHub Actions' CI environment on selected Pull Requests. ## Running the verification From 8998c7380629a9aa54da2fdb576d7b1222560284 Mon Sep 17 00:00:00 2001 From: lisenokdonbassenok Date: Thu, 15 Jan 2026 18:07:53 +0200 Subject: [PATCH 19/33] docs: fix super quorum fraction NatSpec (#6205) --- .../extensions/GovernorVotesSuperQuorumFraction.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/governance/extensions/GovernorVotesSuperQuorumFraction.sol b/contracts/governance/extensions/GovernorVotesSuperQuorumFraction.sol index 53a7049a637..2035da01dff 100644 --- a/contracts/governance/extensions/GovernorVotesSuperQuorumFraction.sol +++ b/contracts/governance/extensions/GovernorVotesSuperQuorumFraction.sol @@ -28,7 +28,7 @@ abstract contract GovernorVotesSuperQuorumFraction is GovernorVotesQuorumFractio error GovernorInvalidSuperQuorumFraction(uint256 superQuorumNumerator, uint256 denominator); /** - * @dev The super quorum set is not valid as it is smaller or equal to the quorum. + * @dev The super quorum set is not valid as it is smaller than the quorum. */ error GovernorInvalidSuperQuorumTooSmall(uint256 superQuorumNumerator, uint256 quorumNumerator); @@ -41,7 +41,7 @@ abstract contract GovernorVotesSuperQuorumFraction is GovernorVotesQuorumFractio * @dev Initialize super quorum as a fraction of the token's total supply. * * The super quorum is specified as a fraction of the token's total supply and has to - * be greater than the quorum. + * be greater than or equal to the quorum. */ constructor(uint256 superQuorumNumeratorValue) { _updateSuperQuorumNumerator(superQuorumNumeratorValue); From 4ed7df76a8911a8a7e9fa900fb39ea133a481159 Mon Sep 17 00:00:00 2001 From: iPLAY888 <133153661+letmehateu@users.noreply.github.com> Date: Mon, 19 Jan 2026 20:08:14 +0300 Subject: [PATCH 20/33] fix: fix incorrect recipient in Address.sendValue test (#6295) Co-authored-by: Hadrien Croubois --- test/utils/Address.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/utils/Address.test.js b/test/utils/Address.test.js index 2335c223722..7bb7e7ab7f7 100644 --- a/test/utils/Address.test.js +++ b/test/utils/Address.test.js @@ -26,7 +26,7 @@ describe('Address', function () { describe('sendValue', function () { describe('when sender contract has no funds', function () { it('sends 0 wei', async function () { - await expect(this.mock.$sendValue(this.other, 0n)).to.changeEtherBalance(this.recipient, 0n); + await expect(this.mock.$sendValue(this.recipient, 0n)).to.changeEtherBalance(this.recipient, 0n); }); it('reverts when sending non-zero amounts', async function () { From ae31c1a9daf20e6b95788ffa10b838fb1d00f2af Mon Sep 17 00:00:00 2001 From: anim001k <140460766+anim001k@users.noreply.github.com> Date: Mon, 2 Feb 2026 13:25:37 +0100 Subject: [PATCH 21/33] Fix typos in TrieProof documentation (#6318) Co-authored-by: Hadrien Croubois --- contracts/utils/cryptography/TrieProof.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/utils/cryptography/TrieProof.sol b/contracts/utils/cryptography/TrieProof.sol index 15600876e1f..4d6d01f866e 100644 --- a/contracts/utils/cryptography/TrieProof.sol +++ b/contracts/utils/cryptography/TrieProof.sol @@ -13,7 +13,7 @@ import {RLP} from "../RLP.sol"; * * Transaction against the transactionsRoot of a block. * * Event against receiptsRoot of a block. * * Account details (RLP encoding of [nonce, balance, storageRoot, codeHash]) against the stateRoot of a block. - * * Storage slot (RLP encoding of the value) against the storageRoot of a account. + * * Storage slot (RLP encoding of the value) against the storageRoot of an account. * * Proving a storage slot is usually done in 3 steps: * @@ -65,7 +65,7 @@ library TrieProof { /// @dev Number of items in leaf or extension nodes (always 2) uint256 internal constant LEAF_OR_EXTENSION_NODE_LENGTH = 2; - /// @dev Verifies a `proof` against a given `key`, `value`, `and root` hash. + /// @dev Verifies a `proof` against a given `key`, `value`, and `root` hash. function verify( bytes memory value, bytes32 root, From 14b40f3b2527f029a2742cd77cf4db3c7e9606f1 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Wed, 4 Feb 2026 17:20:29 +0100 Subject: [PATCH 22/33] Remove unecessary type referencing --- contracts/utils/Memory.sol | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/contracts/utils/Memory.sol b/contracts/utils/Memory.sol index bd21666b1d5..ccbf211f006 100644 --- a/contracts/utils/Memory.sol +++ b/contracts/utils/Memory.sol @@ -103,7 +103,7 @@ library Memory { /// @dev Extract the data corresponding to a Slice (allocate new memory) function toBytes(Slice self) internal pure returns (bytes memory result) { uint256 len = length(self); - Memory.Pointer ptr = _pointer(self); + Pointer ptr = _pointer(self); assembly ("memory-safe") { result := mload(0x40) mstore(result, len) @@ -114,8 +114,8 @@ library Memory { /// @dev Returns true if the two slices contain the same data. function equal(Slice a, Slice b) internal pure returns (bool result) { - Memory.Pointer ptrA = _pointer(a); - Memory.Pointer ptrB = _pointer(b); + Pointer ptrA = _pointer(a); + Pointer ptrB = _pointer(b); uint256 lenA = length(a); uint256 lenB = length(b); assembly ("memory-safe") { @@ -131,14 +131,14 @@ library Memory { * (`slice(Slice,uint256)` and `slice(Slice,uint256, uint256)`) should not cause this issue if the parent slice is * correct. */ - function _asSlice(uint256 len, Memory.Pointer ptr) private pure returns (Slice result) { + function _asSlice(uint256 len, Pointer ptr) private pure returns (Slice result) { assembly ("memory-safe") { result := or(shl(128, len), ptr) } } /// @dev Returns the memory location of a given slice (equiv to self.offset for calldata slices) - function _pointer(Slice self) private pure returns (Memory.Pointer result) { + function _pointer(Slice self) private pure returns (Pointer result) { assembly ("memory-safe") { result := and(self, shr(128, not(0))) } From 0bc213f112499b3d4aab86ca9a52af54f3602630 Mon Sep 17 00:00:00 2001 From: MozirDmitriy Date: Thu, 26 Feb 2026 15:04:10 +0200 Subject: [PATCH 23/33] fix: correct parameter reference in decodeContentsDescr comment (#6347) Co-authored-by: Hadrien Croubois --- contracts/utils/cryptography/draft-ERC7739Utils.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/utils/cryptography/draft-ERC7739Utils.sol b/contracts/utils/cryptography/draft-ERC7739Utils.sol index f3944136ea5..07affb79824 100644 --- a/contracts/utils/cryptography/draft-ERC7739Utils.sol +++ b/contracts/utils/cryptography/draft-ERC7739Utils.sol @@ -162,7 +162,7 @@ library ERC7739Utils { * Following ERC-7739 specifications, a `contentsName` is considered invalid if it's empty or it contains * any of the following bytes , )\x00 * - * If the `contentsType` is invalid, this returns an empty string. Otherwise, the return string has non-zero + * If the `contentsDescr` is invalid, this returns empty strings. Otherwise, the return strings have non-zero * length. */ function decodeContentsDescr( From 2ce1781dca24e715d4a6c11c19a613e7d5280a7d Mon Sep 17 00:00:00 2001 From: Micke <155267459+reallesee@users.noreply.github.com> Date: Thu, 26 Feb 2026 05:18:12 -0800 Subject: [PATCH 24/33] docs: fix incorrect param descriptions in SafeERC20 safeApprove (#6335) --- contracts/token/ERC20/utils/SafeERC20.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/token/ERC20/utils/SafeERC20.sol b/contracts/token/ERC20/utils/SafeERC20.sol index b1e4b6e67db..28bf8cb7bd7 100644 --- a/contracts/token/ERC20/utils/SafeERC20.sol +++ b/contracts/token/ERC20/utils/SafeERC20.sol @@ -249,8 +249,8 @@ library SafeERC20 { * * @param token The token targeted by the call. * @param spender The spender of the tokens - * @param value The amount of token to transfer - * @param bubble Behavior switch if the transfer call reverts: bubble the revert reason or return a false boolean. + * @param value The amount of token to approve + * @param bubble Behavior switch if the approve call reverts: bubble the revert reason or return a false boolean. */ function _safeApprove(IERC20 token, address spender, uint256 value, bool bubble) private returns (bool success) { bytes4 selector = IERC20.approve.selector; From c2fecf87e1585e9b2018ab22149ea59b4de41bdf Mon Sep 17 00:00:00 2001 From: bobtajson <152420524+bobtajson@users.noreply.github.com> Date: Wed, 4 Mar 2026 13:36:46 +0100 Subject: [PATCH 25/33] docs: fix NatSpec for checkOnERC1155BatchReceived referencing wrong callback (#6380) Co-authored-by: Hadrien Croubois --- contracts/token/ERC1155/utils/ERC1155Utils.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/token/ERC1155/utils/ERC1155Utils.sol b/contracts/token/ERC1155/utils/ERC1155Utils.sol index 03cb0f0b953..9cdc9557e1e 100644 --- a/contracts/token/ERC1155/utils/ERC1155Utils.sol +++ b/contracts/token/ERC1155/utils/ERC1155Utils.sol @@ -54,7 +54,7 @@ library ERC1155Utils { * on the `to` address. The `operator` is generally the address that initiated the token transfer (i.e. `msg.sender`). * * The acceptance call is not executed and treated as a no-op if the target address doesn't contain code (i.e. an EOA). - * Otherwise, the recipient must implement {IERC1155Receiver-onERC1155Received} and return the acceptance magic value to accept + * Otherwise, the recipient must implement {IERC1155Receiver-onERC1155BatchReceived} and return the acceptance magic value to accept * the transfer. */ function checkOnERC1155BatchReceived( From 10e20dd3f97d57c6769d352f5231251943cbee9d Mon Sep 17 00:00:00 2001 From: anim001k <140460766+anim001k@users.noreply.github.com> Date: Wed, 4 Mar 2026 13:39:36 +0100 Subject: [PATCH 26/33] Fix typos and grammatical errors across codebase (#6326) Co-authored-by: Hadrien Croubois --- contracts/utils/cryptography/P256.sol | 2 +- docs/modules/ROOT/pages/index.adoc | 2 +- fv/specs/TimelockController.spec | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/utils/cryptography/P256.sol b/contracts/utils/cryptography/P256.sol index 81d79adc427..8aae6db1226 100644 --- a/contracts/utils/cryptography/P256.sol +++ b/contracts/utils/cryptography/P256.sol @@ -89,7 +89,7 @@ library P256 { bytes32 qy ) private view returns (bool valid, bool supported) { if (!_isProperSignature(r, s) || !isValidPublicKey(qx, qy)) { - return (false, true); // signature is invalid, and its not because the precompile is missing + return (false, true); // signature is invalid, and it's not because the precompile is missing } else if (_rip7212(h, r, s, qx, qy)) { return (true, true); // precompile is present, signature is valid } else if ( diff --git a/docs/modules/ROOT/pages/index.adoc b/docs/modules/ROOT/pages/index.adoc index d47510cd773..7b725d03bd0 100644 --- a/docs/modules/ROOT/pages/index.adoc +++ b/docs/modules/ROOT/pages/index.adoc @@ -59,7 +59,7 @@ WARNING: Foundry installs the latest version initially, but subsequent `forge up $ forge install OpenZeppelin/openzeppelin-contracts ``` -Add `@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/` in `remappings.txt.` +Add `@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/` in `remappings.txt`. [[usage]] === Usage diff --git a/fv/specs/TimelockController.spec b/fv/specs/TimelockController.spec index 739fe976b0c..42df83d804d 100644 --- a/fv/specs/TimelockController.spec +++ b/fv/specs/TimelockController.spec @@ -251,7 +251,7 @@ rule execute(env e, method f, bytes32 id, bytes32 predecessor) filtered { f -> // The underlying transaction can revert, and that would cause the execution to revert. We can check that all non // reverting calls meet the requirements in terms of proposal readiness, access control and predecessor dependency. - // We can't however guarantee that these requirements being meet ensure liveness of the proposal, because the + // We can't however guarantee that these requirements being met ensure liveness of the proposal, because the // proposal can revert for reasons beyond our control. // liveness, should be `<=>` but can only check `=>` (see comment above) From 0c7d8be7c21afd787be280561f6a2375e7481d47 Mon Sep 17 00:00:00 2001 From: bobtajson <152420524+bobtajson@users.noreply.github.com> Date: Wed, 4 Mar 2026 13:45:07 +0100 Subject: [PATCH 27/33] docs: fix incorrect comments in AccessControl and AccessManager (#6336) Co-authored-by: Hadrien Croubois --- contracts/access/AccessControl.sol | 3 +-- contracts/access/manager/AccessManager.sol | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/contracts/access/AccessControl.sol b/contracts/access/AccessControl.sol index 1c4aeb9fb2a..03de0057ed3 100644 --- a/contracts/access/AccessControl.sol +++ b/contracts/access/AccessControl.sol @@ -143,8 +143,7 @@ abstract contract AccessControl is Context, IAccessControl, ERC165 { * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * - * If the calling account had been revoked `role`, emits a {RoleRevoked} - * event. + * Emits a {RoleRevoked} event if the calling account had `role` and this call successfully revoked it. * * Requirements: * diff --git a/contracts/access/manager/AccessManager.sol b/contracts/access/manager/AccessManager.sol index e52a62a481e..233c352f3f7 100644 --- a/contracts/access/manager/AccessManager.sol +++ b/contracts/access/manager/AccessManager.sol @@ -329,7 +329,7 @@ contract AccessManager is Context, Multicall, IAccessManager { * Emits a {RoleAdminChanged} event. * * NOTE: Setting the admin role as the `PUBLIC_ROLE` is allowed, but it will effectively allow - * anyone to set grant or revoke such role. + * anyone to grant or revoke such role. */ function _setRoleAdmin(uint64 roleId, uint64 admin) internal virtual { if (roleId == ADMIN_ROLE || roleId == PUBLIC_ROLE) { From 3e29c91a1e16bff0d2f6a855aba6e4e95da8d7d6 Mon Sep 17 00:00:00 2001 From: Adam Boudj Date: Fri, 6 Mar 2026 11:42:11 +0100 Subject: [PATCH 28/33] docs: fix NatSpec wording in ERC20FlashMint (#6397) Co-authored-by: Claude Opus 4.6 Co-authored-by: Hadrien Croubois --- contracts/token/ERC20/extensions/ERC20FlashMint.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/token/ERC20/extensions/ERC20FlashMint.sol b/contracts/token/ERC20/extensions/ERC20FlashMint.sol index f3ed94f3aa7..79c6e8bbb08 100644 --- a/contracts/token/ERC20/extensions/ERC20FlashMint.sol +++ b/contracts/token/ERC20/extensions/ERC20FlashMint.sol @@ -67,7 +67,7 @@ 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 + * implementation has 0 fees. This function can be overridden to make * the flash loan mechanism deflationary. * @return The fees applied to the corresponding flash loan. */ @@ -78,7 +78,7 @@ abstract contract ERC20FlashMint is ERC20, IERC3156FlashLender { /** * @dev Returns the receiver address of the flash fee. By default this * implementation returns the address(0) which means the fee amount will be burnt. - * This function can be overloaded to change the fee receiver. + * This function can be overridden to change the fee receiver. * @return The address for which the flash fee will be sent to. */ function _flashFeeReceiver() internal view virtual returns (address) { From 43daf24395ad5f70bf3bf8edb966ca2d03437162 Mon Sep 17 00:00:00 2001 From: andrewshab <152420261+andrewshab3@users.noreply.github.com> Date: Fri, 13 Mar 2026 16:16:38 +0100 Subject: [PATCH 29/33] docs: fix typos in BridgeMultiToken.sol (#6407) Co-authored-by: Hadrien Croubois --- contracts/crosschain/bridges/abstract/BridgeMultiToken.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/crosschain/bridges/abstract/BridgeMultiToken.sol b/contracts/crosschain/bridges/abstract/BridgeMultiToken.sol index 1e322f36d69..793208087e9 100644 --- a/contracts/crosschain/bridges/abstract/BridgeMultiToken.sol +++ b/contracts/crosschain/bridges/abstract/BridgeMultiToken.sol @@ -17,8 +17,8 @@ import {CrosschainLinked} from "../../CrosschainLinked.sol"; * This base contract is used by the {BridgeERC1155}, which interfaces with legacy ERC-1155 tokens. It is also used by * the {ERC1155Crosschain} extension, which embeds the bridge logic directly in the token contract. * - * This base contract implements the crosschain transfer operation though internal functions. It is for the the "child - * contracts" that inherit from this to implement the external interfaces and make this functions accessible. + * This base contract implements the crosschain transfer operation through internal functions. It is for the "child + * contracts" that inherit from this to implement the external interfaces and make these functions accessible. */ abstract contract BridgeMultiToken is Context, CrosschainLinked { using InteroperableAddress for bytes; From 29313ccb16eaa8fe5ad67bbf310df8053ccb19e3 Mon Sep 17 00:00:00 2001 From: bobtajson <152420524+bobtajson@users.noreply.github.com> Date: Thu, 19 Mar 2026 14:22:25 +0100 Subject: [PATCH 30/33] docs: fix grammar (#6409) --- contracts/account/Account.sol | 4 ++-- contracts/account/utils/draft-ERC4337Utils.sol | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/account/Account.sol b/contracts/account/Account.sol index 967ea0f347e..93ef045200b 100644 --- a/contracts/account/Account.sol +++ b/contracts/account/Account.sol @@ -15,7 +15,7 @@ import {LowLevelCall} from "../utils/LowLevelCall.sol"; * Developers must implement the {AbstractSigner-_rawSignatureValidation} function to define the account's validation logic. * * NOTE: This core account doesn't include any mechanism for performing arbitrary external calls. This is an essential - * feature that all Account should have. We leave it up to the developers to implement the mechanism of their choice. + * feature that all Accounts should have. We leave it up to the developers to implement the mechanism of their choice. * Common choices include ERC-6900, ERC-7579 and ERC-7821 (among others). * * IMPORTANT: Implementing a mechanism to validate signatures is a security-sensitive operation as it may allow an @@ -104,7 +104,7 @@ abstract contract Account is AbstractSigner, IAccount { } /** - * @dev Virtual function that returns the signable hash for a user operations. Since v0.8.0 of the entrypoint, + * @dev Virtual function that returns the signable hash for a user operation. Since v0.8.0 of the entrypoint, * `userOpHash` is an EIP-712 hash that can be signed directly. */ function _signableUserOpHash( diff --git a/contracts/account/utils/draft-ERC4337Utils.sol b/contracts/account/utils/draft-ERC4337Utils.sol index 4406f44c461..a59ab9ec9db 100644 --- a/contracts/account/utils/draft-ERC4337Utils.sol +++ b/contracts/account/utils/draft-ERC4337Utils.sol @@ -175,7 +175,7 @@ library ERC4337Utils { // // Prior to v0.8.0, this was easy to replicate for any entrypoint and chainId. Since v0.8.0 of the // entrypoint, this depends on the Entrypoint's domain separator, which cannot be hardcoded and is complex - // to recompute. Domain separator could be fetch using the `getDomainSeparatorV4` getter, or recomputed from + // to recompute. Domain separator could be fetched using the `getDomainSeparatorV4` getter, or recomputed from // the ERC-5267 getter, but both operation would require doing a view call to the entrypoint. Overall it feels // simpler and less error prone to get that functionality from the entrypoint directly. return IEntryPointExtra(entrypoint).getUserOpHash(self); From 7ac3ce1bcfdc61e71fdd09f4ef45eeb643248661 Mon Sep 17 00:00:00 2001 From: Gonzalo Othacehe <86085168+gonzaotc@users.noreply.github.com> Date: Wed, 25 Mar 2026 18:56:45 -0300 Subject: [PATCH 31/33] N-32: Fix `ERC721Consecutive` NatSpec for `_mintConsecutive` when `batchSize` is 0. (#6433) Co-authored-by: Hadrien Croubois --- contracts/token/ERC721/extensions/ERC721Consecutive.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/token/ERC721/extensions/ERC721Consecutive.sol b/contracts/token/ERC721/extensions/ERC721Consecutive.sol index a391923e8dc..3058595263b 100644 --- a/contracts/token/ERC721/extensions/ERC721Consecutive.sol +++ b/contracts/token/ERC721/extensions/ERC721Consecutive.sol @@ -87,7 +87,7 @@ abstract contract ERC721Consecutive is IERC2309, ERC721 { /** * @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. + * batch; if `batchSize` is 0, returns the next token id to be minted consecutively. * * Requirements: * From d16856d8fc432a2da24ad63f5adf8d9972be9c1a Mon Sep 17 00:00:00 2001 From: Axiom Date: Sun, 17 May 2026 12:49:30 -0700 Subject: [PATCH 32/33] fix(utils/Create3): correct verb form in _computeCreateAddress NatSpec (#6527) Co-authored-by: Axiom Bot <0xAxiom@users.noreply.github.com> Co-authored-by: Hadrien Croubois --- contracts/utils/Create3.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/utils/Create3.sol b/contracts/utils/Create3.sol index 14e50836df0..dbc9ffe16ce 100644 --- a/contracts/utils/Create3.sol +++ b/contracts/utils/Create3.sol @@ -122,7 +122,7 @@ library Create3 { return _computeCreateAddress(Create2.computeAddress(salt, PROXY_INITCODE_HASH, deployer)); } - /// @dev Compute the address of the first contract that `creator` would deployed using CREATE (nonce 1). + /// @dev Compute the address of the first contract that `creator` would deploy using CREATE (nonce 1). function _computeCreateAddress(address creator) private pure returns (address addr) { assembly ("memory-safe") { mstore(0x15, 0x01) From 5cc0b682a908a191ffde1e5c27735c8280ae11c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=82=BFhari=2Eeth?= <152027898+BhariGowda@users.noreply.github.com> Date: Fri, 29 May 2026 02:15:29 +0530 Subject: [PATCH 33/33] =?UTF-8?q?fix:=20correct=20grammar=20in=20draft-Int?= =?UTF-8?q?eroperableAddress=20NatSpec=20(a=20ERC=20=E2=86=92=20a=E2=80=A6?= =?UTF-8?q?=20(#6561)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contracts/utils/draft-InteroperableAddress.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/utils/draft-InteroperableAddress.sol b/contracts/utils/draft-InteroperableAddress.sol index 10b4e426adf..37595c84a86 100644 --- a/contracts/utils/draft-InteroperableAddress.sol +++ b/contracts/utils/draft-InteroperableAddress.sol @@ -66,7 +66,7 @@ library InteroperableAddress { } /** - * @dev Parse a ERC-7930 interoperable address (version 1) into its different components. Reverts if the input is + * @dev Parse an ERC-7930 interoperable address (version 1) into its different components. Reverts if the input is * not following a version 1 of ERC-7930. * * NOTE: Trailing bytes after a valid v1 encoding are ignored. The same decoded address may therefore correspond @@ -149,7 +149,7 @@ library InteroperableAddress { } /** - * @dev Parse a ERC-7930 interoperable address (version 1) corresponding to an EIP-155 chain. The `chainId` and + * @dev Parse an ERC-7930 interoperable address (version 1) corresponding to an EIP-155 chain. The `chainId` and * `addr` return values will be zero if the input doesn't include a chainReference or an address, respectively. * * NOTE: Trailing bytes after a valid v1 encoding are ignored. The same decoded (chainId, addr) may therefore