diff --git a/contracts/utils/cryptography/signers/MultiSignerERC7913.sol b/contracts/utils/cryptography/signers/MultiSignerERC7913.sol index e318eb52c..9f094bec9 100644 --- a/contracts/utils/cryptography/signers/MultiSignerERC7913.sol +++ b/contracts/utils/cryptography/signers/MultiSignerERC7913.sol @@ -218,7 +218,7 @@ abstract contract MultiSignerERC7913 is AbstractSigner { /** * @dev Validates the signatures using the signers and their corresponding signatures. - * Returns whether whether the signers are authorized and the signatures are valid for the given hash. + * Returns whether the signers are authorized and the signatures are valid for the given hash. * * IMPORTANT: Sorting the signers by their `keccak256` hash will improve the gas efficiency of this function. * See {SignatureChecker-areValidSignaturesNow-bytes32-bytes[]-bytes[]} for more details. diff --git a/contracts/utils/cryptography/signers/MultiSignerERC7913Weighted.sol b/contracts/utils/cryptography/signers/MultiSignerERC7913Weighted.sol index a73828a16..bf957684e 100644 --- a/contracts/utils/cryptography/signers/MultiSignerERC7913Weighted.sol +++ b/contracts/utils/cryptography/signers/MultiSignerERC7913Weighted.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.27; +pragma solidity ^0.8.26; import {SafeCast} from "../../math/SafeCast.sol"; import {MultiSignerERC7913} from "./MultiSignerERC7913.sol"; @@ -104,18 +104,22 @@ abstract contract MultiSignerERC7913Weighted is MultiSignerERC7913 { uint256 extraWeightRemoved = 0; for (uint256 i = 0; i < signers.length; ++i) { bytes memory signer = signers[i]; - uint64 weight = weights[i]; - require(isSigner(signer), MultiSignerERC7913NonexistentSigner(signer)); + + uint64 weight = weights[i]; require(weight > 0, MultiSignerERC7913WeightedInvalidWeight(signer, weight)); unchecked { - // Overflow impossible: weight values are bounded by uint64 and economic constraints - extraWeightRemoved += _extraWeights[signer]; - extraWeightAdded += _extraWeights[signer] = weight - 1; - } + uint64 oldExtraWeight = _extraWeights[signer]; + uint64 newExtraWeight = weight - 1; - emit ERC7913SignerWeightChanged(signer, weight); + if (oldExtraWeight != newExtraWeight) { + // Overflow impossible: weight values are bounded by uint64 and economic constraints + extraWeightRemoved += oldExtraWeight; + extraWeightAdded += _extraWeights[signer] = newExtraWeight; + emit ERC7913SignerWeightChanged(signer, weight); + } + } } unchecked { // Safe from underflow: `extraWeightRemoved` is bounded by `_totalExtraWeight` by construction diff --git a/contracts/utils/structs/EnumerableMap.sol b/contracts/utils/structs/EnumerableMap.sol index 69cb57781..eaf9ca62f 100644 --- a/contracts/utils/structs/EnumerableMap.sol +++ b/contracts/utils/structs/EnumerableMap.sol @@ -136,7 +136,7 @@ library EnumerableMap { } /** - * @dev Tries to returns the value associated with `key`. O(1). + * @dev Tries to return the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool exists, bytes32 value) { @@ -256,7 +256,7 @@ library EnumerableMap { } /** - * @dev Tries to returns the value associated with `key`. O(1). + * @dev Tries to return the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(UintToUintMap storage map, uint256 key) internal view returns (bool exists, uint256 value) { @@ -276,7 +276,7 @@ library EnumerableMap { } /** - * @dev Return the an array containing all the keys + * @dev Returns an array containing all the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that @@ -295,7 +295,7 @@ library EnumerableMap { } /** - * @dev Return the an array containing a slice of the keys + * @dev Returns an array containing a slice of the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that @@ -378,7 +378,7 @@ library EnumerableMap { } /** - * @dev Tries to returns the value associated with `key`. O(1). + * @dev Tries to return the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool exists, address value) { @@ -398,7 +398,7 @@ library EnumerableMap { } /** - * @dev Return the an array containing all the keys + * @dev Returns an array containing all the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that @@ -417,7 +417,7 @@ library EnumerableMap { } /** - * @dev Return the an array containing a slice of the keys + * @dev Returns an array containing a slice of the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that @@ -500,7 +500,7 @@ library EnumerableMap { } /** - * @dev Tries to returns the value associated with `key`. O(1). + * @dev Tries to return the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(UintToBytes32Map storage map, uint256 key) internal view returns (bool exists, bytes32 value) { @@ -520,7 +520,7 @@ library EnumerableMap { } /** - * @dev Return the an array containing all the keys + * @dev Returns an array containing all the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that @@ -539,7 +539,7 @@ library EnumerableMap { } /** - * @dev Return the an array containing a slice of the keys + * @dev Returns an array containing a slice of the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that @@ -622,7 +622,7 @@ library EnumerableMap { } /** - * @dev Tries to returns the value associated with `key`. O(1). + * @dev Tries to return the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(AddressToUintMap storage map, address key) internal view returns (bool exists, uint256 value) { @@ -642,7 +642,7 @@ library EnumerableMap { } /** - * @dev Return the an array containing all the keys + * @dev Returns an array containing all the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that @@ -661,7 +661,7 @@ library EnumerableMap { } /** - * @dev Return the an array containing a slice of the keys + * @dev Returns an array containing a slice of the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that @@ -744,7 +744,7 @@ library EnumerableMap { } /** - * @dev Tries to returns the value associated with `key`. O(1). + * @dev Tries to return the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(AddressToAddressMap storage map, address key) internal view returns (bool exists, address value) { @@ -764,7 +764,7 @@ library EnumerableMap { } /** - * @dev Return the an array containing all the keys + * @dev Returns an array containing all the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that @@ -783,7 +783,7 @@ library EnumerableMap { } /** - * @dev Return the an array containing a slice of the keys + * @dev Returns an array containing a slice of the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that @@ -870,7 +870,7 @@ library EnumerableMap { } /** - * @dev Tries to returns the value associated with `key`. O(1). + * @dev Tries to return the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(AddressToBytes32Map storage map, address key) internal view returns (bool exists, bytes32 value) { @@ -890,7 +890,7 @@ library EnumerableMap { } /** - * @dev Return the an array containing all the keys + * @dev Returns an array containing all the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that @@ -909,7 +909,7 @@ library EnumerableMap { } /** - * @dev Return the an array containing a slice of the keys + * @dev Returns an array containing a slice of the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that @@ -996,7 +996,7 @@ library EnumerableMap { } /** - * @dev Tries to returns the value associated with `key`. O(1). + * @dev Tries to return the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool exists, uint256 value) { @@ -1016,7 +1016,7 @@ library EnumerableMap { } /** - * @dev Return the an array containing all the keys + * @dev Returns an array containing all the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that @@ -1035,7 +1035,7 @@ library EnumerableMap { } /** - * @dev Return the an array containing a slice of the keys + * @dev Returns an array containing a slice of the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that @@ -1118,7 +1118,7 @@ library EnumerableMap { } /** - * @dev Tries to returns the value associated with `key`. O(1). + * @dev Tries to return the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(Bytes32ToAddressMap storage map, bytes32 key) internal view returns (bool exists, address value) { @@ -1138,7 +1138,7 @@ library EnumerableMap { } /** - * @dev Return the an array containing all the keys + * @dev Returns an array containing all the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that @@ -1157,7 +1157,7 @@ library EnumerableMap { } /** - * @dev Return the an array containing a slice of the keys + * @dev Returns an array containing a slice of the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that @@ -1259,7 +1259,7 @@ library EnumerableMap { } /** - * @dev Tries to returns the value associated with `key`. O(1). + * @dev Tries to return the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet( diff --git a/contracts/utils/structs/EnumerableSet.sol b/contracts/utils/structs/EnumerableSet.sol index 896e484c7..9d4c158a9 100644 --- a/contracts/utils/structs/EnumerableSet.sol +++ b/contracts/utils/structs/EnumerableSet.sol @@ -519,12 +519,12 @@ library EnumerableSet { * Returns true if the value was added to the set, that is if it was not * already present. */ - function add(StringSet storage self, string memory value) internal returns (bool) { - if (!contains(self, value)) { - self._values.push(value); + function add(StringSet storage set, string memory value) internal returns (bool) { + if (!contains(set, value)) { + set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value - self._positions[value] = self._values.length; + set._positions[value] = set._values.length; return true; } else { return false; @@ -537,33 +537,33 @@ library EnumerableSet { * Returns true if the value was removed from the set, that is if it was * present. */ - function remove(StringSet storage self, string memory value) internal returns (bool) { + function remove(StringSet storage set, string memory value) internal returns (bool) { // We cache the value's position to prevent multiple reads from the same storage slot - uint256 position = self._positions[value]; + uint256 position = set._positions[value]; if (position != 0) { - // Equivalent to contains(self, value) + // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 valueIndex = position - 1; - uint256 lastIndex = self._values.length - 1; + uint256 lastIndex = set._values.length - 1; if (valueIndex != lastIndex) { - string memory lastValue = self._values[lastIndex]; + string memory lastValue = set._values[lastIndex]; // Move the lastValue to the index where the value to delete is - self._values[valueIndex] = lastValue; + set._values[valueIndex] = lastValue; // Update the tracked position of the lastValue (that was just moved) - self._positions[lastValue] = position; + set._positions[lastValue] = position; } // Delete the slot where the moved value was stored - self._values.pop(); + set._values.pop(); // Delete the tracked position for the deleted slot - delete self._positions[value]; + delete set._positions[value]; return true; } else { @@ -588,15 +588,15 @@ library EnumerableSet { /** * @dev Returns true if the value is in the set. O(1). */ - function contains(StringSet storage self, string memory value) internal view returns (bool) { - return self._positions[value] != 0; + function contains(StringSet storage set, string memory value) internal view returns (bool) { + return set._positions[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ - function length(StringSet storage self) internal view returns (uint256) { - return self._values.length; + function length(StringSet storage set) internal view returns (uint256) { + return set._values.length; } /** @@ -609,8 +609,8 @@ library EnumerableSet { * * - `index` must be strictly less than {length}. */ - function at(StringSet storage self, uint256 index) internal view returns (string memory) { - return self._values[index]; + function at(StringSet storage set, uint256 index) internal view returns (string memory) { + return set._values[index]; } /** @@ -621,8 +621,8 @@ library EnumerableSet { * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ - function values(StringSet storage self) internal view returns (string[] memory) { - return self._values; + function values(StringSet storage set) internal view returns (string[] memory) { + return set._values; } /** @@ -661,12 +661,12 @@ library EnumerableSet { * Returns true if the value was added to the set, that is if it was not * already present. */ - function add(BytesSet storage self, bytes memory value) internal returns (bool) { - if (!contains(self, value)) { - self._values.push(value); + function add(BytesSet storage set, bytes memory value) internal returns (bool) { + if (!contains(set, value)) { + set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value - self._positions[value] = self._values.length; + set._positions[value] = set._values.length; return true; } else { return false; @@ -679,33 +679,33 @@ library EnumerableSet { * Returns true if the value was removed from the set, that is if it was * present. */ - function remove(BytesSet storage self, bytes memory value) internal returns (bool) { + function remove(BytesSet storage set, bytes memory value) internal returns (bool) { // We cache the value's position to prevent multiple reads from the same storage slot - uint256 position = self._positions[value]; + uint256 position = set._positions[value]; if (position != 0) { - // Equivalent to contains(self, value) + // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 valueIndex = position - 1; - uint256 lastIndex = self._values.length - 1; + uint256 lastIndex = set._values.length - 1; if (valueIndex != lastIndex) { - bytes memory lastValue = self._values[lastIndex]; + bytes memory lastValue = set._values[lastIndex]; // Move the lastValue to the index where the value to delete is - self._values[valueIndex] = lastValue; + set._values[valueIndex] = lastValue; // Update the tracked position of the lastValue (that was just moved) - self._positions[lastValue] = position; + set._positions[lastValue] = position; } // Delete the slot where the moved value was stored - self._values.pop(); + set._values.pop(); // Delete the tracked position for the deleted slot - delete self._positions[value]; + delete set._positions[value]; return true; } else { @@ -730,15 +730,15 @@ library EnumerableSet { /** * @dev Returns true if the value is in the set. O(1). */ - function contains(BytesSet storage self, bytes memory value) internal view returns (bool) { - return self._positions[value] != 0; + function contains(BytesSet storage set, bytes memory value) internal view returns (bool) { + return set._positions[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ - function length(BytesSet storage self) internal view returns (uint256) { - return self._values.length; + function length(BytesSet storage set) internal view returns (uint256) { + return set._values.length; } /** @@ -751,8 +751,8 @@ library EnumerableSet { * * - `index` must be strictly less than {length}. */ - function at(BytesSet storage self, uint256 index) internal view returns (bytes memory) { - return self._values[index]; + function at(BytesSet storage set, uint256 index) internal view returns (bytes memory) { + return set._values[index]; } /** @@ -763,8 +763,8 @@ library EnumerableSet { * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ - function values(BytesSet storage self) internal view returns (bytes[] memory) { - return self._values; + function values(BytesSet storage set) internal view returns (bytes[] memory) { + return set._values; } /** diff --git a/scripts/generate/templates/EnumerableMap.js b/scripts/generate/templates/EnumerableMap.js index 5b0d1141d..7285e1156 100644 --- a/scripts/generate/templates/EnumerableMap.js +++ b/scripts/generate/templates/EnumerableMap.js @@ -137,7 +137,7 @@ function at(Bytes32ToBytes32Map storage map, uint256 index) internal view return } /** - * @dev Tries to returns the value associated with \`key\`. O(1). + * @dev Tries to return the value associated with \`key\`. O(1). * Does not revert if \`key\` is not in the map. */ function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool exists, bytes32 value) { @@ -255,7 +255,7 @@ function at(${name} storage map, uint256 index) internal view returns (${key.typ } /** - * @dev Tries to returns the value associated with \`key\`. O(1). + * @dev Tries to return the value associated with \`key\`. O(1). * Does not revert if \`key\` is not in the map. */ function tryGet(${name} storage map, ${key.type} key) internal view returns (bool exists, ${value.type} value) { @@ -275,7 +275,7 @@ function get(${name} storage map, ${key.type} key) internal view returns (${valu } /** - * @dev Return the an array containing all the keys + * @dev Returns an array containing all the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that @@ -294,7 +294,7 @@ function keys(${name} storage map) internal view returns (${key.type}[] memory) } /** - * @dev Return the an array containing a slice of the keys + * @dev Returns an array containing a slice of the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that @@ -394,7 +394,7 @@ function at( } /** - * @dev Tries to returns the value associated with \`key\`. O(1). + * @dev Tries to return the value associated with \`key\`. O(1). * Does not revert if \`key\` is not in the map. */ function tryGet( diff --git a/scripts/generate/templates/EnumerableSet.js b/scripts/generate/templates/EnumerableSet.js index abd9b1b2a..4d709d302 100644 --- a/scripts/generate/templates/EnumerableSet.js +++ b/scripts/generate/templates/EnumerableSet.js @@ -324,12 +324,12 @@ struct ${name} { * Returns true if the value was added to the set, that is if it was not * already present. */ -function add(${name} storage self, ${value.type} memory value) internal returns (bool) { - if (!contains(self, value)) { - self._values.push(value); +function add(${name} storage set, ${value.type} memory value) internal returns (bool) { + if (!contains(set, value)) { + set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value - self._positions[value] = self._values.length; + set._positions[value] = set._values.length; return true; } else { return false; @@ -342,33 +342,33 @@ function add(${name} storage self, ${value.type} memory value) internal returns * Returns true if the value was removed from the set, that is if it was * present. */ -function remove(${name} storage self, ${value.type} memory value) internal returns (bool) { +function remove(${name} storage set, ${value.type} memory value) internal returns (bool) { // We cache the value's position to prevent multiple reads from the same storage slot - uint256 position = self._positions[value]; + uint256 position = set._positions[value]; if (position != 0) { - // Equivalent to contains(self, value) + // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 valueIndex = position - 1; - uint256 lastIndex = self._values.length - 1; + uint256 lastIndex = set._values.length - 1; if (valueIndex != lastIndex) { - ${value.type} memory lastValue = self._values[lastIndex]; + ${value.type} memory lastValue = set._values[lastIndex]; // Move the lastValue to the index where the value to delete is - self._values[valueIndex] = lastValue; + set._values[valueIndex] = lastValue; // Update the tracked position of the lastValue (that was just moved) - self._positions[lastValue] = position; + set._positions[lastValue] = position; } // Delete the slot where the moved value was stored - self._values.pop(); + set._values.pop(); // Delete the tracked position for the deleted slot - delete self._positions[value]; + delete set._positions[value]; return true; } else { @@ -393,15 +393,15 @@ function clear(${name} storage set) internal { /** * @dev Returns true if the value is in the set. O(1). */ -function contains(${name} storage self, ${value.type} memory value) internal view returns (bool) { - return self._positions[value] != 0; +function contains(${name} storage set, ${value.type} memory value) internal view returns (bool) { + return set._positions[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ -function length(${name} storage self) internal view returns (uint256) { - return self._values.length; +function length(${name} storage set) internal view returns (uint256) { + return set._values.length; } /** @@ -414,8 +414,8 @@ function length(${name} storage self) internal view returns (uint256) { * * - \`index\` must be strictly less than {length}. */ -function at(${name} storage self, uint256 index) internal view returns (${value.type} memory) { - return self._values[index]; +function at(${name} storage set, uint256 index) internal view returns (${value.type} memory) { + return set._values[index]; } /** @@ -426,8 +426,8 @@ function at(${name} storage self, uint256 index) internal view returns (${value. * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ -function values(${name} storage self) internal view returns (${value.type}[] memory) { - return self._values; +function values(${name} storage set) internal view returns (${value.type}[] memory) { + return set._values; } /** diff --git a/test/account/AccountMultiSignerWeighted.test.js b/test/account/AccountMultiSignerWeighted.test.js index d3522360d..0d78f3eca 100644 --- a/test/account/AccountMultiSignerWeighted.test.js +++ b/test/account/AccountMultiSignerWeighted.test.js @@ -158,6 +158,10 @@ describe('AccountMultiSignerWeighted', function () { await expect(this.mock.signerWeight(signer3)).to.eventually.equal(3); // unchanged }); + it("no-op doesn't emit an event", async function () { + await expect(this.mock.$_setSignerWeights([signer1], [1])).to.not.emit(this.mock, 'ERC7913SignerWeightChanged'); + }); + it('cannot set weight to non-existent signer', async function () { // Reverts when setting weight for non-existent signer await expect(this.mock.$_setSignerWeights([signer4], [1])) @@ -186,28 +190,28 @@ describe('AccountMultiSignerWeighted', function () { }); it('validates threshold is reachable when updating weights', async function () { - // First, lower the weights so the sum is exactly 6 (just enough for threshold=6) - await expect(this.mock.$_setSignerWeights([signer1, signer2, signer3], [1, 2, 3])) + // First, lower the weights so the sum is exactly 9 (just enough for threshold=9) + await expect(this.mock.$_setSignerWeights([signer1, signer2, signer3], [2, 3, 4])) .to.emit(this.mock, 'ERC7913SignerWeightChanged') - .withArgs(signer1, 1) + .withArgs(signer1, 2) .to.emit(this.mock, 'ERC7913SignerWeightChanged') - .withArgs(signer2, 2) + .withArgs(signer2, 3) .to.emit(this.mock, 'ERC7913SignerWeightChanged') - .withArgs(signer3, 3); + .withArgs(signer3, 4); - // Increase threshold to 6 - await expect(this.mock.$_setThreshold(6)).to.emit(this.mock, 'ERC7913ThresholdSet').withArgs(6); + // Increase threshold to 9 + await expect(this.mock.$_setThreshold(9)).to.emit(this.mock, 'ERC7913ThresholdSet').withArgs(9); // Now try to lower weights so their sum is less than the threshold - await expect(this.mock.$_setSignerWeights([signer1, signer2, signer3], [1, 1, 1])).to.be.revertedWithCustomError( + await expect(this.mock.$_setSignerWeights([signer1, signer2, signer3], [2, 2, 2])).to.be.revertedWithCustomError( this.mock, 'MultiSignerERC7913UnreachableThreshold', ); // Try to increase threshold to be larger than the total weight - await expect(this.mock.$_setThreshold(7)) + await expect(this.mock.$_setThreshold(10)) .to.be.revertedWithCustomError(this.mock, 'MultiSignerERC7913UnreachableThreshold') - .withArgs(6, 7); + .withArgs(9, 10); }); it('reports default weight of 1 for signers without explicit weight', async function () { diff --git a/test/utils/Blockhash.t.sol b/test/utils/Blockhash.t.sol index eda4da626..e585ccba8 100644 --- a/test/utils/Blockhash.t.sol +++ b/test/utils/Blockhash.t.sol @@ -67,6 +67,7 @@ contract BlockhashTest is Test { function testFuzzFutureBlocks(uint256 offset, uint256 currentBlock) public { // Future blocks offset = bound(offset, 1, type(uint256).max); + currentBlock = bound(currentBlock, 0, type(uint256).max - offset); vm.roll(currentBlock); unchecked {